【问题标题】:Fillna based on month over month percent change and previous value in PandasFillna 基于 Pandas 中的月度变化百分比和之前的值
【发布时间】:2021-12-23 14:17:00
【问题描述】:

给定一个时间序列数据如下,我需要根据之前的值和MoM_pctvalue列中填写NaNs:

          date    value  MoM_pct
0    2012-1-31  17222.1   0.0019
1    2012-2-29      NaN   0.0101  --> calculated by (1+0.0101) * 17222.1
2    2012-3-31  15650.2   0.0121
3    2012-4-30  15603.1   0.0093
4    2012-5-31      NaN   0.0111  --> calculated by (1+0.0111) * 15603.1
5    2012-6-30      NaN   0.0112  --> calculated by (1+0.0111) * 15603.1 * (1+0.0112)
6    2012-7-31  16314.9   0.0103
7    2012-8-31  16658.9   0.0111
8    2012-9-30      NaN   0.0132  --> calculated by (1+0.0132) * 16658.9
9   2012-10-31      NaN   0.0118  --> calculated by (1+0.0132) * 16658.9 * (1+0.0118)
10  2012-11-30  18476.7   0.0121
11  2012-12-31  20334.2   0.0123
12   2013-1-31      NaN   0.0014  --> calculated by (1+0.0014) * 20334.2
13   2013-2-28      NaN   0.0087  --> calculated by (1+0.0014) * 20334.2 * (1+0.0087)

预期的结果是这样的:

          date        value  MoM_pct
0    2012-1-31  17222.10000   0.0019
1    2012-2-29  17396.04321   0.0101
2    2012-3-31  15650.20000   0.0121
3    2012-4-30  15603.10000   0.0093
4    2012-5-31  15776.29441   0.0111
5    2012-6-30  15952.98891   0.0112
6    2012-7-31  16314.90000   0.0103
7    2012-8-31  16658.90000   0.0111
8    2012-9-30  16878.79748   0.0132
9   2012-10-31  17077.96729   0.0118
10  2012-11-30  18476.70000   0.0121
11  2012-12-31  20334.20000   0.0123
12   2013-1-31  20362.66788   0.0014
13   2013-2-28  20539.82309   0.0087
14   2013-3-31  17641.20000   0.0150

示例数据:

import pandas as pd
from numpy import nan

df = pd.DataFrame({
    'date': {0: '2012-1-31', 1: '2012-2-29', 2: '2012-3-31', 3: '2012-4-30',
             4: '2012-5-31', 5: '2012-6-30', 6: '2012-7-31', 7: '2012-8-31',
             8: '2012-9-30', 9: '2012-10-31', 10: '2012-11-30',
             11: '2012-12-31', 12: '2013-1-31', 13: '2013-2-28',
             14: '2013-3-31'},
    'value': {0: 17222.1, 1: nan, 2: 15650.2, 3: 15603.1, 4: nan, 5: nan,
              6: 16314.9, 7: 16658.9, 8: nan, 9: nan, 10: 18476.7, 11: 20334.2,
              12: nan, 13: nan, 14: 17641.2},
    'MoM_pct': {0: 0.0019, 1: 0.0101, 2: 0.0121, 3: 0.0093, 4: 0.0111,
                5: 0.0112, 6: 0.0103, 7: 0.0111, 8: 0.0132, 9: 0.0118,
                10: 0.0121, 11: 0.0123, 12: 0.0014, 13: 0.0087, 14: 0.015}
})

我下面的代码适用于示例数据,但如果样本有两个以上的连续值为NaNs,则不适合,也不简洁:

df['value1'] = df['value'].shift(1)*df['MoM_pct'].add(1)
df['value2'] = df['value1'].shift(1)*df['MoM_pct'].add(1)
df['value'].fillna(df['value1'], inplace=True)
df['value'].fillna(df['value2'], inplace=True)

如何修复上面的代码?

【问题讨论】:

    标签: python python-3.x pandas dataframe


    【解决方案1】:

    我们可以从MoM_pct 列中创建乘数,groupby cumprod 然后fillna 乘法标识为1 的有效值,并与ffilled value 列相乘:

    m = df['value'].isna()
    df['value'] = (
            df['value'].ffill() *
            (1 + df['MoM_pct']).groupby((~m).cumsum()[m]).cumprod().fillna(1)
    )
    

    或等效地使用multiplyfill_value 而不是fillna

    m = df['value'].isna()
    df['value'] = (
        df['value'].ffill().multiply(
            df['MoM_pct'].add(1).groupby((~m).cumsum()[m]).cumprod(),
            fill_value=1
        )
    )
    

    df:

              date         value  MoM_pct
    0    2012-1-31  17222.100000   0.0019
    1    2012-2-29  17396.043210   0.0101
    2    2012-3-31  15650.200000   0.0121
    3    2012-4-30  15603.100000   0.0093
    4    2012-5-31  15776.294410   0.0111
    5    2012-6-30  15952.988907   0.0112
    6    2012-7-31  16314.900000   0.0103
    7    2012-8-31  16658.900000   0.0111
    8    2012-9-30  16878.797480   0.0132
    9   2012-10-31  17077.967290   0.0118
    10  2012-11-30  18476.700000   0.0121
    11  2012-12-31  20334.200000   0.0123
    12   2013-1-31  20362.667880   0.0014
    13   2013-2-28  20539.823091   0.0087
    14   2013-3-31  17641.200000   0.0150
    

    以下是作为 DataFrame 的步骤细分:

    m = df['value'].isna()
    print(pd.DataFrame({
        'm': m,
        'groups': (~m).cumsum(),
        'filtered groups': (~m).cumsum()[m],
        'result of cumprod': (1 + df['MoM_pct']).groupby(
            (~m).cumsum()[m]
        ).cumprod(),
        'fill missing with 1': (1 + df['MoM_pct']).groupby(
            (~m).cumsum()[m]
        ).cumprod().fillna(1)
    }))
    
            m  groups  filtered groups  result of cumprod  fill missing with 1
    0   False       1              NaN                NaN             1.000000
    1    True       1              1.0           1.010100             1.010100
    2   False       2              NaN                NaN             1.000000
    3   False       3              NaN                NaN             1.000000
    4    True       3              3.0           1.011100             1.011100
    5    True       3              3.0           1.022424             1.022424
    6   False       4              NaN                NaN             1.000000
    7   False       5              NaN                NaN             1.000000
    8    True       5              5.0           1.013200             1.013200
    9    True       5              5.0           1.025156             1.025156
    10  False       6              NaN                NaN             1.000000
    11  False       7              NaN                NaN             1.000000
    12   True       7              7.0           1.001400             1.001400
    13   True       7              7.0           1.010112             1.010112
    14  False       8              NaN                NaN             1.000000
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-19
      • 2019-10-02
      • 2021-06-01
      • 2020-12-09
      • 2021-11-30
      • 2021-06-02
      • 2021-09-05
      相关资源
      最近更新 更多