使用带有多索引组的pct_change

时间:2018-06-18 18:11:20

标签: pandas pandas-groupby

我正在尝试对groupby的结果使用pct_change,以便计算跨越许多不同项的值的周期变化。

我的数据结构如下:

import numpy as np
arrays = [np.array([1,2,3,4,1,2,3,4]),np.array(['bar', 'bar', 'bar', 'bar', 'foo', 'foo', 'foo', 'foo'])]
s = pd.Series(np.array([100,101,102,103,200,201,202,203]), index=arrays)
s.name='values'
df = pd.DataFrame(s, index=arrays).sort_index()
df.index.names =['day','symbol']

我需要计算每天每个符号的百分比变化。当我运行这样的事情时:

df.groupby(level='symbol').values.diff()

我得到了正确的输出。但是当我运行时:

df.groupby(level='symbol').values.pct_change()

它返回错误的结果(将bar与foo比较)

我可以通过包装像这样的lambda来获得我正在寻找的东西:

my_func = lambda x: x.pct_change()
df.groupby(level='symbol').values.apply(my_func)

或通过这样做:

df.groupby(level='symbol').values.diff() / df.groupby(level='symbol').values.shift(1)

所以我真的只是想了解pct_change与其他pandas方法行为不同的原因。

2 个答案:

答案 0 :(得分:1)

对于熊猫0.24.2上的多索引数据框,此解决方案对我有效:

pd.__version__

'0.24.2'


df.groupby(level='symbol')['values'].pct_change()


    day  symbol
1    bar            NaN
     foo            NaN
2    bar       0.010000
     foo       0.005000
3    bar       0.009901
     foo       0.004975
4    bar       0.009804
     foo       0.004950
Name: values, dtype: float64

答案 1 :(得分:0)

看起来我们必须使用.apply()才能将它与多索引DF一起使用:

In [61]: df.groupby(level='symbol')['values'].apply(lambda x: x.pct_change())
Out[61]:
day  symbol
1    bar            NaN
     foo            NaN
2    bar       0.010000
     foo       0.005000
3    bar       0.009901
     foo       0.004975
4    bar       0.009804
     foo       0.004950
Name: values, dtype: float64

PS对我来说这看起来像个错误 - IMO在按多指标级别分组时无法正常工作:

In [101]: g = df.groupby(level='symbol')

In [102]: g.values.pct_change??
Signature: g.values.pct_change(periods=1, fill_method='pad', limit=None, freq=None)
Source:
    def pct_change(self, periods=1, fill_method='pad', limit=None, freq=None):
        """Calculate percent change of each value to previous entry in group"""
        filled = getattr(self, fill_method)(limit=limit)
        shifted = filled.shift(periods=periods, freq=freq)

        return (filled / shifted) - 1
File:      c:\users\max\anaconda3_5.0\envs\py36\lib\site-packages\pandas\core\groupby\groupby.py
Type:      method

复制代码:

In [103]: filled = g['values'].pad(limit=None)

In [104]: shifted = filled.shift(periods=1, freq=None)

In [105]: (filled / shifted) - 1
Out[105]:
day  symbol
1    bar            NaN
     foo       1.000000
2    bar      -0.495000
     foo       0.990099
3    bar      -0.492537
     foo       0.980392
4    bar      -0.490099
     foo       0.970874
Name: values, dtype: float64

我建议检查Pandas-Issues上是否已存在此类问题,如果该问题尚不存在,请打开一个新问题...