我有一个数据框:
import pandas as pd
df = pd.DataFrame([['A', 'G1', '2019-01-01', 11],
['A', 'G1', '2019-01-02', 12],
['A', 'G1', '2019-01-04', 14],
['B', 'G2', '2019-01-01', 11],
['B', 'G2', '2019-01-03', 13],
['B', 'G2', '2019-01-06', 16]],
columns=['cust', 'group', 'date', 'val'])
df
df = df.groupby(['cust', 'group', 'date']).sum()
df
数据框已分组,现在我想计算pct_change
,但前提是有以前的日期。
如果我这样做:
df['pct'] = df.groupby(['cust', 'group']).val.pct_change()
df
我会得到pct_change
,但与丢失的日期无关。
例如,在组('A', 'G1')
中,日期pct
的{{1}}应该是2019-01-04
,因为没有(先前)日期np.nan
。
也许解决方案是按天重新采样,即每行新的2019-01-03
为np.nan
,而不是val
。
我尝试使用pct_change
,但出现错误:
TypeError:仅对DatetimeIndex,TimedeltaIndex或PeriodIndex有效,但具有“ MultiIndex”的实例
对于组df.resample('1D', level=2)
,所有('B', 'G2')
都应为pct_change
,因为所有行都没有上一个日期。
预期结果是:
如何计算np.nan
的缺失日期?
解决方案:
pct_change
答案 0 :(得分:2)
使用groupby
进行检查,然后您首先需要resample
并使用布尔型掩码获取pct更改,因为pct_change将忽略NaN
d={}
for x, y in df.groupby(['cust', 'group']):
s=y.set_index('date').resample('D').val.mean()
d[x]=pd.concat([s,s.pct_change().mask(s.shift().isnull()|s.isnull())],1)
newdf=pd.concat(d)
newdf.columns=['val','pct']
newdf
Out[651]:
val pct
date
A G1 2019-01-01 11.0 NaN
2019-01-02 12.0 0.090909
2019-01-03 NaN NaN
2019-01-04 14.0 NaN
B G2 2019-01-01 11.0 NaN
2019-01-02 NaN NaN
2019-01-03 13.0 NaN
2019-01-04 NaN NaN
2019-01-05 NaN NaN
2019-01-06 16.0 NaN
您可以在末尾添加reset_index(inplace = True)以使所有索引都回到列
答案 1 :(得分:1)
也许您可以尝试比较连续行之间的差异(不等于1天),然后更改pct_change。
df= df.groupby(['cust', 'group', 'date'])\
.agg({'val':'sum','date':[min,max]}).reset_index()
df.columns = ['%s%s' % (a, '_%s' % b if b else '') for a, b in df.columns]
df['date_diff']=df['date'].diff()
df['pct_change_val']=df.val_sum.pct_change()
df['pct_change_final'] = df.apply(lambda row: np.NaN if pd.isnull(row.date_diff) \
else np.NaN if row.date_diff != np.timedelta64(1, 'D') else row.pct_change_val ,axis=1)
#output:
cust group date date_min date_max val_sum date_diff pct_change_val pct_change_final
0 A G1 2019-01-01 2019-01-01 2019-01-01 11
1 A G1 2019-01-02 2019-01-02 2019-01-02 12 1 days 00:00:00.000000000 0.09090909090909083 0.09090909090909083
2 A G1 2019-01-04 2019-01-04 2019-01-04 14 2 days 00:00:00.000000000 0.16666666666666674
3 B G2 2019-01-01 2019-01-01 2019-01-01 11 -3 days +00:00:00.000000000 -0.2142857142857143
4 B G2 2019-01-03 2019-01-03 2019-01-03 13 2 days 00:00:00.000000000 0.18181818181818188
5 B G2 2019-01-06 2019-01-06 2019-01-06 16 3 days 00:00:00.000000000 0.23076923076923084