我的目标是能够在特定日期查找有关员工的具体信息。我有一个可以工作的功能,但是当我与超过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日经理是约翰。
答案 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_date
和expiration_date
之间的行。
要选择您想要的行,请形成布尔掩码condition
并使用merged.loc[condition]
选择condition
为True的行:
condition = ((merged['effective_date'] <= merged['date'])
& (merged['date'] < merged['expiration_date']))
result = merged.loc[condition]