【问题标题】:Merge files based on a date range?根据日期范围合并文件?
【发布时间】:2016-06-22 16:59:19
【问题描述】:

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

因此,使用上面的数据框,此函数将生成一个数据框,该数据框将为每个员工 ID 在 2016 年 2 月 3 日至 2016 年 3 月 8 日之间的每个日期创建一行。这意味着我可以做到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,因为它在有效日期和到期日期之间。在 3/08,员工 abc 的经理是 John,之后没有任何变化。这意味着 6/21 的经理是约翰。

【问题讨论】:

  • 我编辑了函数。名册实际上是另一个数据框。我从一个单独的数据框中的数据库中读取,但这个数据框只有有效日期和到期日期。我加入的原始数据是一个单独的数据框,但它可能包含任何日期的数据。只要日期在生效日期和到期日期之间,我希望能够根据employee_id 和日期加入。
  • 我确实进行了编辑。我正在尝试查找在有效日期和到期日期之间的某个日期的经理是谁,并将其添加到 DF2 中,这是一些示例原始数据。 DF3 是所需的输出。

标签: pandas


【解决方案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]

【讨论】:

  • 我不久前尝试过这样的事情,但我没有使用merged.loc[condition]的部分。我认为这看起来很有希望,让我测试一下。
猜你喜欢
  • 1970-01-01
  • 2016-12-27
  • 2015-09-28
  • 1970-01-01
  • 2018-01-09
  • 2021-08-06
  • 2018-11-14
  • 1970-01-01
  • 2021-04-01
相关资源
最近更新 更多