根据日期范围合并文件?

时间:2016-06-22 16:59:19

标签: pandas

我的目标是能够在特定日期查找有关员工的具体信息。我有一个可以工作的功能,但是当我与超过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

因此,使用上面的数据框,此函数将生成一个数据框,该数据框将为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日的Fred,因为它位于effective_date和expiration_date之间。在08年3月,员工abc的经理是John,之后没有变化。这意味着6月21日经理是约翰。

1 个答案:

答案 0 :(得分: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)可能不到几百万 应该适合在标准计算机上使用。

merged可能包含许多您实际不想要的行 - date不在effective_dateexpiration_date之间的行。 要选择您想要的行,请形成布尔掩码condition并使用merged.loc[condition]选择condition为True的行:

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