2016-06-22 4 views
2

Моя цель - иметь возможность искать конкретную информацию о сотруднике на определенную дату. У меня есть функция, которая работает, но она довольно интенсивная память, когда я имею дело с более чем 100 000 сотрудников.Объединить файлы на основе диапазона дат?

DF1 (реестр):

employee_id | manager | effective_date | expiration_date 
abc   Fred  2016-02-03  2016-03-07 
abc   John  2016-03-08  2999-12-31 

Таким образом, используя dataframe выше, эта функция будет производить dataframe, который создавал бы строку для каждой даты между 2016-02-03 до 2016-03-08 для КАЖДОГО employee_id. Это означает, что я могу сделать pd.merge(raw, roster, on=['employee_id', 'effective_date'])

def add_roster(df, date_col): 
    min_date = df[date_col].min() #min date of the raw data I am joining 
    roster = df2 
    current_roster = roster.groupby(['employee_id'])['effective_date'].idxmax() #max date in the roster 
    rows = roster.ix[current_roster] 
    rows['effective_date'] = pd.to_datetime(dt.date.today()) #makes sure there is a date up until current date 
    current = pd.concat([roster, rows], ignore_index=True) 
    current = current.sort_values(['avaya_id', 'effective_date'], ascending=True) 
    roster = current.groupby(['employee_id']).apply(
     lambda x: x.set_index('effective_date').resample('D').first().ffill()) #this is filling the roster up so there is an entry for every date 
    roster = roster.reset_index(level=0, drop=True).reset_index() 
    roster = roster[roster['effective_date'] >= min_date] 
    return roster 

Это работает, но теперь я имею дело с большим количеством сотрудников, так что кажется немного неэффективным. Есть лучший способ сделать это?

В данных также имеется срок годности.

Могу ли я сделать pd.merge, что говорит что-то вроде:

Регистрация на employee_id where date >= effective_date and date < expiration_date?

Я хочу наиболее эффективный способ объединения данных в определенную дату.

DF2 (сырые)

employee_id | date  | data_count_1 | data_count_2 
abc   2016-02-18  10    56 
abc   2016-02-28  19    102 
abc   2016-06-21  5    4 

DF3 (Желаемый выход):

employee_id | date  | data_count_1 | data_count_2 | manager 
abc   2016-02-18  10    56   Fred 
abc   2016-02-28  19    102  Fred 
abc   2016-06-21  5    4   John 

Менеджер должен быть Фред на 2/18 и 2/28, потому что он находится между EFFECTIVE_DATE и EXPIRATION_DATE. 3/08, менеджер для сотрудника abc - Джон, и после этого изменений нет. Это означает, что на 6/21 менеджер - Джон.

+0

Я редактировал функцию. На самом деле этот реестр является еще одним фреймворком данных. Я читаю из базы данных в отдельном фрейме данных, но этот файл данных имеет только эффективные и срочные даты. С исходными данными, с которыми я соединяюсь, является отдельный блок данных, но он может иметь данные для любой даты. Я хочу, чтобы иметь возможность присоединиться на основе employee_id и даты, пока дата находится между эффективной и истекающей датой. – trench

+0

Конечно, я сделал редактирование. Я пытаюсь посмотреть, кто менеджер на определенную дату, которая находится между датами действия и срока действия и добавляет их в DF2, который является примером сырых данных. DF3 - желаемый выход. – trench

ответ

1

Пусть df1 является

effective_date employee_id expiration_date manager 
0  2016-02-03   abc  2016-03-07 Fred 
1  2016-03-08   abc  2199-12-31 John 
2  2016-01-01   xyz  2016-02-14 Rocco 
3  2016-02-15   xyz  2016-03-14 Floyd 

и df2 является

data_count data_count2  date employee_id 
0   10   56 2016-02-18   abc 
1   19   102 2016-02-28   abc 
2   5   4 2016-06-21   abc 
3   9   99 2016-02-20   xyz 

затем

import pandas as pd 

df1 = pd.DataFrame({'employee_id':['abc', 'abc', 'xyz', 'xyz'], 
        'manager':['Fred','John', 'Rocco', 'Floyd'], 
       'effective_date':['2016-02-03', '2016-03-08', 
            '2016-01-01', '2016-02-15'], 
       'expiration_date':['2016-03-07', '2199-12-31', 
            '2016-02-14', '2016-03-14'], }) 
for col in ['effective_date', 'expiration_date']: 
    df1[col] = pd.to_datetime(df1[col]) 

df2 = pd.DataFrame({'employee_id':['abc', 'abc', 'abc', 'xyz'], 
        'date':['2016-02-18', '2016-02-28', '2016-06-21', '2016-02-20'], 
        'data_count':[10,19,5,9], 
        'data_count2':[56,102,4,99],}) 
df2['date'] = pd.to_datetime(df2['date']) 

merged = pd.merge(df2, df1, on='employee_id', how='left') 
condition = ((merged['effective_date'] <= merged['date']) 
      & (merged['date'] < merged['expiration_date'])) 
result = merged.loc[condition] 
print(result) 

дает

data_count data_count2  date employee_id effective_date expiration_date manager 
0   10   56 2016-02-18   abc  2016-02-03  2016-03-07 Fred 
2   19   102 2016-02-28   abc  2016-02-03  2016-03-07 Fred 
5   5   4 2016-06-21   abc  2016-03-08  2199-12-31 John 
7   9   99 2016-02-20   xyz  2016-02-15  2016-03-14 Floyd 

Предположительно количество менеджеров на одного работника будет низким, так что

merged = pd.merge(df2, df1, on='employee_id', how='left') 

будет иметь размер порядка по len(df2) раз некоторых малых кратным (примерно, среднего числа менеджеров на одного работника) , Так что если len(df2) находится на заказе 100K, то len(merged), вероятно, будет меньше пары миллионов, а должно соответствовать комфортным в памяти на стандартном компьютере.

mergedmerged может иметь много строк, которые вам действительно не нужны - строки, где date не находится между effective_date и expiration_date. Для выбора строки вы хотите, образуют булеву маску condition и использовать merged.loc[condition] для выбора строки, в которых condition является True:

condition = ((merged['effective_date'] <= merged['date']) 
      & (merged['date'] < merged['expiration_date'])) 
result = merged.loc[condition] 
+0

Я пробовал что-то вроде этого некоторое время назад, но у меня не было части с объединенным.loc [condition]. Я думаю, что это выглядит довольно многообещающе, позвольте мне проверить его. – trench