【问题标题】:Calculate monthly percentage change of daily basis data in Python在Python中计算每日基础数据的每月百分比变化
【发布时间】:2021-12-22 22:35:12
【问题描述】:

假设我有如下的每日数据:

import pandas as pd
import numpy as np

np.random.seed(2021)
dates = pd.date_range('20130226', periods=90)
df = pd.DataFrame(np.random.randint(0, 100, size=(90, 3)), index=dates, columns=list('ABC'))
df

输出:

             A   B   C
2013-02-26  85  57   0
2013-02-27  94  86  44
2013-02-28  62  91  29
2013-03-01  21  93  24
2013-03-02  12  70  70
        ..  ..  ..
2013-05-22  57  13  81
2013-05-23  43  68  85
2013-05-24  55  50  53
2013-05-25  75  78  66
2013-05-26  70  93   3

对于列AB,我需要每天计算它们的每月pct变化,例如@987654325的每月pct变化值 @ for 2013-05-26 的计算方法是:A 在 2013-05-26 的值除以 2013-04-26 的值减去 1。

我的想法是这样的:通过将它们向前移动一个月来创建新列'A1', 'B1',然后df['A_MoM']将由df['A']/df['A_shifted'] - 1计算,与列B的逻辑相同。

由于并非所有月份的天数都相同,所以我将使用上个月的最后一天的值,即计算 2013-03-30 的 pct 变化将通过以下方式计算:2013-03-30's value/2013-02-28's value - 1

我尝试了下面的代码,但它生成了一个包含所有NaNs 的数据框:

df[['A1', 'B1']] = df[['A', 'B']].shift(freq=pd.DateOffset(months=1)).resample('D').last().fillna(method=ffill)
df[['A_MoM', 'B_MoM']] = df[['A', 'B']].div(df[['A1', 'B1']], axis=0) - 1

输出:

             A  A1   B  B1
2013-02-26 NaN NaN NaN NaN
2013-02-27 NaN NaN NaN NaN
2013-02-28 NaN NaN NaN NaN
2013-03-01 NaN NaN NaN NaN
2013-03-02 NaN NaN NaN NaN
        ..  ..  ..  ..
2013-05-22 NaN NaN NaN NaN
2013-05-23 NaN NaN NaN NaN
2013-05-24 NaN NaN NaN NaN
2013-05-25 NaN NaN NaN NaN
2013-05-26 NaN NaN NaN NaN

如何正确实现这一点?提前致以诚挚的感谢。

编辑:

df = pd.DataFrame(np.random.randint(0, 100, size=(90, 3)), index=dates, columns=['A_values', 'B_values', 'C'])
df.columns

df1 = df.filter(regex='_values$').shift(freq=pd.DateOffset(months=1)).resample('D').last().ffill().add_suffix('_shifted')
df2 = df.filter(regex='_values$').div(df1.to_numpy(), axis=0) - 1
df.join(df2.add_suffix('_MoM'))

输出:

ValueError: Unable to coerce to DataFrame, shape must be (90, 2): given (93, 2)

【问题讨论】:

    标签: python-3.x pandas dataframe numpy date


    【解决方案1】:

    原因是列名不同,解决方法是将df[['A1', 'B1']]转换为numpy数组:

    df[['A1', 'B1']] = df[['A', 'B']].shift(freq=pd.DateOffset(months=1)).resample('D').last().ffill()
    df[['A_MoM', 'B_MoM']] = df[['A', 'B']].div(df[['A1', 'B1']].to_numpy(), axis=0) - 1
    print (df)
                 A   B   C    A1    B1      A_MoM     B_MoM
    2013-02-26  85  57   0   NaN   NaN        NaN       NaN
    2013-02-27  94  86  44   NaN   NaN        NaN       NaN
    2013-02-28  62  91  29   NaN   NaN        NaN       NaN
    2013-03-01  21  93  24   NaN   NaN        NaN       NaN
    2013-03-02  12  70  70   NaN   NaN        NaN       NaN
            ..  ..  ..   ...   ...        ...       ...
    2013-05-22  57  13  81  14.0  50.0   3.071429 -0.740000
    2013-05-23  43  68  85   2.0  45.0  20.500000  0.511111
    2013-05-24  55  50  53  89.0  52.0  -0.382022 -0.038462
    2013-05-25  75  78  66  86.0  54.0  -0.127907  0.444444
    2013-05-26  70  93   3   4.0  45.0  16.500000  1.066667
    
    [90 rows x 7 columns]
    

    或者如果可能的话将输出分配给df1,所以列名不会改变,所以可以用相同的列名划分,这里A, B正确:

    df1 = df[['A', 'B']].shift(freq=pd.DateOffset(months=1)).resample('D').last().ffill()
    df[['A_MoM', 'B_MoM']] = df[['A', 'B']].div(df1, axis=0) - 1
    print (df)
                 A   B   C      A_MoM     B_MoM
    2013-02-26  85  57   0        NaN       NaN
    2013-02-27  94  86  44        NaN       NaN
    2013-02-28  62  91  29        NaN       NaN
    2013-03-01  21  93  24        NaN       NaN
    2013-03-02  12  70  70        NaN       NaN
            ..  ..  ..        ...       ...
    2013-05-22  57  13  81   3.071429 -0.740000
    2013-05-23  43  68  85  20.500000  0.511111
    2013-05-24  55  50  53  -0.382022 -0.038462
    2013-05-25  75  78  66  -0.127907  0.444444
    2013-05-26  70  93   3  16.500000  1.066667
    
    [90 rows x 5 columns]
    

    编辑:resample 也更改了 datetimeIndex 之后,因此在两个 DataFrames 中为相同的索引添加了 reindex

    np.random.seed(2021)
    
    dates = pd.date_range('20130226', periods=90)
    df = pd.DataFrame(np.random.randint(0, 100, size=(90, 3)), index=dates, columns=['A_values', 'B_values', 'C'])
    
    df1 = df.filter(regex='_values$').shift(freq=pd.DateOffset(months=1)).resample('D').last().ffill()
    print (df1.columns)
    Index(['A_values', 'B_values'], dtype='object')
    
    df2 = df.filter(regex='_values$').div(df1, axis=0).sub(1).reindex(df.index)
    
    print (df.filter(regex='_values$').columns)
    Index(['A_values', 'B_values'], dtype='object')
    
    df = df.join(df2.add_suffix('_MoM'))
    print (df)
                A_values  B_values   C  A_values_MoM  B_values_MoM
    2013-02-26        85        57   0          NaN          NaN
    2013-02-27        94        86  44          NaN          NaN
    2013-02-28        62        91  29          NaN          NaN
    2013-03-01        21        93  24          NaN          NaN
    2013-03-02        12        70  70          NaN          NaN
                 ...       ...  ..          ...          ...
    2013-05-22        57        13  81     3.071429    -0.740000
    2013-05-23        43        68  85    20.500000     0.511111
    2013-05-24        55        50  53    -0.382022    -0.038462
    2013-05-25        75        78  66    -0.127907     0.444444
    2013-05-26        70        93   3    16.500000     1.066667
    
    [90 rows x 5 columns]
    

    【讨论】:

    • 谢谢,还有一个问题,因为我的真实数据框有很多列,假设列名是['A_values', 'B_values', 'C'],所以我需要使用df.filter(regex='_values$') 过滤前两列,然后使用df.join()add_prefix('MoM'),我该如何修改你的代码?请不要删除您发布的代码,而是添加更多以适应这种情况。
    • @ahbon - 我认为.to_numpy() 应该可以正常工作。
    • 它引发了我在帖子中更新的错误,请检查,非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-14
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 2020-08-25
    • 1970-01-01
    相关资源
    最近更新 更多