我有2个数据框:
df1
id |tier |event_date
233|1 |2014-01-20
234|1 |2015-02-12
235|2 |2015-02-12
df2
id |join_date |stop_date
233|2013-03-12|2015-04-01
233|2016-03-12|2017-04-01
235|2013-03-12|2016-04-01
我想在df2
,has_tier_1
,has_tier_2
对于df2
中的每一行,我想查看是否有一个基于id
中的df1
的匹配行。 df1
中可能有多个匹配的行。:
如果存在匹配的行,那么我想检查event_date
中的df1
在join_date
中的stop_date
和df2
之间。如果是这样,则基于tier
,相应列中的值为1。
目标是df2
看起来像这样:
id |join_date |stop_date |has_tier_1| has_tier_2
233|2013-03-12|2015-04-01| 1 | 0
233|2016-03-12|2017-04-01| 0 | 0
235|2013-03-12|2016-04-01| 0 | 1
我创建了此功能:
def create_columns(x):
x[has_tier_1] == 0
x[has_tier_2] == 0
if x['id'] in df1['id']:
if x['join_date'] <= df1['event_date'] <= x['stop_date']:
if df1['tier'] == '1':
return has_tier_1 == 1
elif df1['tier'] == '2':
return has_tier_2 == 1
else:
return x[has_tier_1], x[has_tier_2]
else:
return x[has_tier_1], x[has_tier_2]
我申请了:
df1.apply(create_columns)
但是,我也没有得到正确的结果。请帮助我如何实现这一目标。
答案 0 :(得分:0)
pandas的merge asof方法在这里派上用场,因为它允许我们根据距离合并列。方向设置为正向,确保左侧的值小于或等于右侧的值。请查看该链接以获取更多指导。
测试以下代码,看看它是否涵盖您的用例:
res = (pd.merge_asof(df1,df,
by='id',
left_on='join_date',
right_on='event_date',
direction='forward')
.fillna(0)
.drop('event_date',axis=1)
.assign(has_tier_1 = lambda x: np.where(x.tier == 1, 1, 0),
has_tier_2 = lambda x: np.where(x.tier == 2, 1, 0)
)
.sort_values('id')
)
res
id join_date stop_date tier has_tier_1 has_tier_2
0 233 2013-03-12 2015-04-01 1.0 1 0
2 233 2016-03-12 2017-04-01 0.0 0 0
1 235 2013-03-12 2016-04-01 2.0 0 1