我有两个看起来像这样的数据框
start_date end_date
1 2018-01-01 2018-01-31
2 2018-01-15 2018-02-28
3 2018-01-31 2018-03-15
4 2018-01-07 2018-04-30
value
2018-01-01 1
2018-01-02 4
2018-01-03 2
2018-01-04 10
2018-01-05 0
... ...
2018-12-28 1
2018-12-29 7
2018-12-30 9
2018-12-31 5
我正在尝试向第一个DataFrame添加一个新列,其中包含第二个DataFrame的求和值,并按start_date
和end_date
进行过滤。像
start_date end_date total_value
1 2018-01-01 2018-01-31 47 # Where 47 is the sum of values between 2018-01-01 and 2018-01-31, inclusive
2 2018-01-15 2018-02-28 82
3 2018-01-31 2018-03-15 116
4 2018-01-07 2018-04-30 253
我想我可以用apply
来做到这一点(基本上只是用start_date
和end_date
过滤并求和第二个DataFrame并返回总和),但是我想知道是否有一个而是使用简洁的熊猫式解决方案。
答案 0 :(得分:4)
我正在使用OP数据,需要对其进行轻微按摩
df2 = df2.asfreq('D').fillna(0, downcast='infer')
然后我们要进行cumsum
的操作,但要增加班次。
s = df2.value.cumsum()
starts = df1.start_date.map(s.shift().fillna(0, downcast='infer'))
ends = df1.end_date.map(s)
df1.assign(total_value=ends - starts)
start_date end_date total_value
1 2018-01-01 2018-01-31 17
2 2018-01-15 2018-02-28 0
3 2018-01-31 2018-03-15 0
4 2018-01-07 2018-04-30 0
很酷,但是不准确。这是开始日期之后的数字总和。为了包括开始日期,我必须使用班次。见上文。
您可以使用cumsum
并有所作为。
df1.assign(
total_value=df1.applymap(df2.cumsum().value.get).eval('end_date - start_date'))
start_date end_date total_value
1 2018-01-01 2018-01-31 145
2 2018-01-15 2018-02-28 229
3 2018-01-31 2018-03-15 212
4 2018-01-07 2018-04-30 535
np.random.seed([3, 1415])
min_date = df1.values.min()
max_date = df1.values.max()
tidx = pd.date_range(min_date, max_date)
df2 = pd.DataFrame(dict(value=np.random.randint(10, size=len(tidx))), tidx)
答案 1 :(得分:3)
设置
location.pathname
使用循环和df2.reset_index(inplace=True)
创建条件(zip
与output
的索引相匹配很重要)
df1
使用conditions = [df2['index'].between(i, j) for i, j in zip(df1.start_date, df1.end_date)]
output = df1.index
,然后使用np.select
:
groupby
最后合并:
tmp = df2.assign(flag=np.select(conditions, output, np.nan))
tmp = tmp.dropna().groupby('flag').value.sum()
输出:
df1.merge(tmp.to_frame(), left_index=True, right_index=True)
答案 2 :(得分:2)
请注意,这将是O(m * n)方法,为合并创建新的密钥
df1['Newkey']=1
df2['Newkey']=1
df2.reset_index(inplace=True)
mergefilterdf=df1.merge(df2).\
loc[lambda x : (x['start_date']<=x['index'])&(x['end_date']>=x['index'])]
mergefilterdf.groupby(['start_date','end_date']).value.sum()
Out[331]:
start_date end_date
2018-01-01 2018-01-31 17
Name: value, dtype: int64