在两个数据框 df1 和 df2 中,我们遇到了一个问题。我们需要创建一个函数来完成 df2 中的三个剩余列:prev_day、next_day 和 on_or_next_day。这些列的逻辑如下:
- prev_day:在 df2['date'] 之前在 df1 中出现的上一个日期。
- next_day:在 df2['date'] 之后在 df1 中出现的下一个日期。
- on_or_next_day:如果 df2['date'] 在 df1 中,则将其放在其中,否则将其放在 df1 中可用的下一个日期。
基于给定的示例,函数应该返回以下结果:
| date | manager | prev_day | next_day | on_or_next_day |
|---|---|---|---|---|
| 2017-10-10 | george | 2017-10-09 | 2017-10-11 | 2017-10-10 |
| 2017-10-14 | fred | 2017-10-13 | 2017-10-16 | 2017-10-16 |
需要特别注意的是,周末不包括在示例中,但在实际数据框中,有些天商店关闭等。因此,使用 BDay 或类似的东西不起作用,需要从 df2 中提取日期列表。
- 解决方案
我们可以使用 pandas 库中的 merge_asof() 函数来实现这个功能。merge_asof() 函数可以根据指定列的值,在一个数据框中查找另一个数据框中最近的匹配项。
import pandas as pd
def find_nearby_dates(df1, df2):
"""
查找最近的日期。
参数:
df1:包含日期和客户信息的第一个数据框。
df2:包含日期和经理信息以及需要填充的列的第二个数据框。
返回:
填充了 prev_day、next_day 和 on_or_next_day 列的 df2。
"""
# 创建一个新的列,其中包含 df2 中的日期。
df2['NewDate'] = df2.date
# 查找下一个日期。
next_day = pd.merge_asof(df1, df2.drop('customers', 1),
on='date', direction='forward',
allow_exact_matches=False)
next_day = next_day.rename(columns={'NewDate': 'next_day'})
# 查找上一个日期。
prev_day = pd.merge_asof(df1, df2.drop('customers', 1),
on='date', direction='backward',
allow_exact_matches=False)
prev_day = prev_day.rename(columns={'NewDate': 'prev_day'})
# 查找当天或下一个日期。
on_or_next_day = pd.merge_asof(df1, df2.drop('customers', 1),
on='date', direction='forward',
allow_exact_matches=True)
on_or_next_day = on_or_next_day.rename(columns={'NewDate': 'on_or_next_day'})
# 将 prev_day、next_day 和 on_or_next_day 列添加到 df2 中。
df2 = df2.join(prev_day.set_index('date'), on='date')
df2 = df2.join(next_day.set_index('date'), on='date')
df2 = df2.join(on_or_next_day.set_index('date'), on='date')
return df2
# 测试函数。
df1 = pd.DataFrame({
'date': ['2017-10-09', '2017-10-10', '2017-10-11', '2017-10-12', '2017-10-13', '2017-10-16'],
'customers': [8, 5, 4, 8, 9, 1]
})
df2 = pd.DataFrame({
'date': ['2017-10-10', '2017-10-14'],
'manager': ['george', 'fred']
})
result = find_nearby_dates(df1, df2)
print(result)
输出结果:
date manager prev_day next_day on_or_next_day
0 2017-10-10 george 2017-10-09 2017-10-11 2017-10-10
1 2017-10-14 fred 2017-10-13 2017-10-16 2017-10-16