我有两个数据框,主要是每月(MS)面板,如下所示:
df = pd.DataFrame({'Location':['A', 'A', 'B', 'B'],
'Date':pd.to_datetime(['1990-1-1', '1990-2-1']*2, yearfirst=True)})
Date Location
0 1990-01-01 A
1 1990-02-01 A
2 1990-01-01 B
3 1990-02-01 B
第二个是包含地点,开始日期和结束日期(第一个月)的事件列表,如下所示:
events = pd.DataFrame({'Location':['A', 'B'],
'Start Date':pd.to_datetime(['1/14/1990', '1/2/1990']),
'End Date':pd.to_datetime(['1/15/1990', '2/13/1990'])})
Location Start Date End Date
0 A 1990-01-14 1990-01-15
1 B 1990-01-02 1990-02-13
我需要的是将第二个数据帧中的起始和结束日期/位置组合转换为第一个中的虚拟变量。换句话说,如果某个特定位置在给定日期有事件,我需要一个值为1的列,否则为0。像这样:
Date Location Event
0 1990-01-01 A 1
1 1990-02-01 A 0
2 1990-01-01 B 1
3 1990-02-01 B 1
正如您所看到的,1990-1-1的日期不属于位置B的第二个数据框中的事件范围,因此它是0.有时事件将跨越多个月,有时则不会。由于主要数据均为MS频率,因此该月内的事件日期无关紧要。这是一个大面板,因此相同的位置将在许多不同的日期举办活动,同一日期将在不同的地点举办活动。
我解决的解决方案是凌乱而且不是很快:
events2 = pd.melt(events, id_vars='Location',
value_vars=['Start Date', 'End Date'],
value_name='Event')
import datetime
def date_fill(g):
#to make sure the 1st of a month is always in the range
y, m = g['Event'].min().year, g['Event'].min().month
date_range = pd.date_range(datetime.datetime(year=y, month=m, day=1),
g['Event'].max(),
freq='MS')
return g.set_index('Event').reindex(date_range,
fill_value=g['Location'].iloc[0])
events3 = events2.groupby('Location', as_index=False).apply(lambda g: date_fill(g))
这给了我这个:
Location variable
0 1990-01-01 A A
1 1990-01-01 B B
1990-02-01 B B
然后我可以清理一下,创建所有1的列,并在位置和日期左合并到第一个数据框中,用0填充NaN。它可以工作,但它显然是凌乱和缓慢的(较小的考虑因素)比杂乱,因为数据不是太大)。我觉得必须有一个更好的方法,但我还没有提出来。
编辑:我的“解决方案”实际上也存在一些问题,因为我更多地探讨这个问题,这是我对这种混乱工作的恐惧。特别是它在一些极端情况下窒息,比如当事件开始和结束时的月份(不能重复索引重复)。
答案 0 :(得分:1)
这个应该产生所需的输出。 (不快)
df["Date"] = df["Date"].dt.to_period('M')
events["Start Date"] = events["Start Date"].dt.to_period('M')
events["End Date"] = events["End Date"].dt.to_period('M')
e_g = events.groupby("Location")
def f(x):
g = e_g.get_group(x.Location)
return ((x.Date >= g["Start Date"])&(x.Date <= g["End Date"])).any()
df["dummy"] = df.apply(f, axis=1).astype(int)
df
Date Location dummy
0 1990-01 A 1
1 1990-02 A 0
2 1990-01 B 1
3 1990-02 B 1