在系列结束时将 data/shrink window 扩展为 pct_change

Extend data/shrink window for pct_change at end of series

我正在尝试计算系列结束时具有收缩 window 效应的百分比变化(对于大于 1 的周期)。

以下示例未产生所需的结果:

    import pandas as pd
    import numpy as np

    labels = ['A', 'A', 'A', 'A', 'A', 'B', 'A', 'C', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'B']
    prices = [62, 55, 55, 74, 31, 77, 20, 21, 25, 30, 21, 35, 66, 12, 1, 2, 4]
    df = pd.DataFrame(data = {'label':labels,'price': price}, columns = ['label', 'price'])
    df['price_chg'] = df.groupby('label')['price'].transform(lambda x: x.pct_change(3, fill_method=None).shift(-3))
    df = df.iloc[np.lexsort((df.index, df['label'].values))]

df

        label   price   price_chg
    0   A       62      0.193548
    1   A       55      -0.436364
    2   A       55      -0.636364
    3   A       74      NaN
    4   A       31      NaN
    6   A       20      NaN
    5   B       77      -0.727273
    8   B       25      0.400000
    9   B       30      -0.866667
    10  B       21      NaN
    11  B       35      NaN
    16  B       4       NaN
    7   C       21      -0.952381
    12  C       66      -0.969697
    13  C       12      NaN
    14  C       1       NaN
    15  C       2       NaN

想要的结果:


        label   price   price_chg
    0   A       62      0.193548
    1   A       55      -0.436364
    2   A       55      -0.636364
    3*  A       74      -0.729730
    4*  A       31      -0.354839
    6   A       20      NaN
    5   B       77      -0.727273
    8   B       25      0.400000
    9   B       30      -0.866667
    10* B       21      -0.809523
    11* B       35      -0.885714
    16  B       4       NaN
    7   C       21      -0.952381
    12  C       66      -0.969697
    13* C       12      -0.833333
    14* C       1       1.000000
    15  C       2       NaN

在期望的结果中,百分比变化计算继续超过组 'A' 的索引 2。因此,索引 3 和索引 4 的值计算为:

    df.loc[3,['price_chg']] = float(df.loc[6,['price']] / df.loc[3,['price']] - 1)
    -0.729730
    df.loc[4,['price_chg']] = float(df.loc[6,['price']] / df.loc[4,['price']] - 1)
    -0.354839

对于索引 10 和 11 处的值(标签 'B')类似:

    df.loc[10,['price_chg']] = float(df.loc[16,['price']] / df.loc[10,['price']] - 1)
    -0.809523
    df.loc[11,['price_chg']] = float(df.loc[16,['price']] / df.loc[11,['price']] - 1)
    -0.885714

等等标签 'C'.

我在想自定义滑动 window 函数,或者重复系列的最后一个值所需次数的方法(虚拟扩展),但我不熟悉如何完成这个。由于我使用的是大 pct_change() 周期和大量数据,我认为自定义滑动 window 方法可能更快,因此比扩展系列更可取。

谢谢!

我认为主要问题是计算百分比然后进行移位会使极端值被 NaN.

填充

您的问题的一个解决方案是使用 pandas.DataFrame.shift:

计算百分比
df['price_chg'] = df.groupby('label')['price'].transform(
                  lambda x: (x.shift(-3).ffill(limit=2)-x)/x)

x.shift(-3).ffill(limit=2):在这个表达式中,我们向后移动行并用标签的最后一个可用值填充出现的 nan 值。我们的最大填充将是两行,因为当我们向前填充时,最后一行将对应于句点=0(pct_change =0),这是不需要的。

那么 df 将是:

> df

   label  price  price_chg
0      A     62   0.193548
1      A     55  -0.436364
2      A     55  -0.636364
3      A     74  -0.729730
4      A     31  -0.354839
6      A     20        NaN
5      B     77  -0.727273
8      B     25   0.400000
9      B     30  -0.866667
10     B     21  -0.809524
11     B     35  -0.885714
16     B      4        NaN
7      C     21  -0.952381
12     C     66  -0.969697
13     C     12  -0.833333
14     C      1   1.000000
15     C      2        NaN