在pct_change()和缺少值之前重新采样

时间:2019-01-18 14:21:34

标签: python pandas resampling

我有一个数据框:

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

enter image description here

df = df.groupby(['cust', 'group', 'date']).sum()
df

enter image description here

数据框已分组,现在我想计算pct_change,但前提是有以前的日期。 如果我这样做:

df['pct'] = df.groupby(['cust', 'group']).val.pct_change()
df

enter image description here

我会得到pct_change,但与丢失的日期无关。 例如,在组('A', 'G1')中,日期pct的{​​{1}}应该是2019-01-04,因为没有(先前)日期np.nan

也许解决方案是按天重新采样,即每行新的2019-01-03np.nan,而不是val

我尝试使用pct_change,但出现错误:

  

TypeError:仅对DatetimeIndex,TimedeltaIndex或PeriodIndex有效,但具有“ MultiIndex”的实例

对于组df.resample('1D', level=2),所有('B', 'G2')都应为pct_change,因为所有行都没有上一个日期。

预期结果是:

enter image description here

如何计算np.nan的缺失日期?

解决方案:

pct_change

enter image description here

2 个答案:

答案 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