【问题标题】:How to get DataFrame.pct_change to calculate monthly change on daily price data?如何获取 DataFrame.pct_change 来计算每日价格数据的每月变化?
【发布时间】:2012-12-11 18:20:33
【问题描述】:

我知道可以使用 periods 参数进行抵消,但是如何返回化分布在一个月内(例如交易日)的每日价格数据?

示例数据为:

In [1]: df.AAPL
2009-01-02 16:00:00    90.36
2009-01-05 16:00:00    94.18
2009-01-06 16:00:00    92.62
2009-01-07 16:00:00    90.62
2009-01-08 16:00:00    92.30
2009-01-09 16:00:00    90.19
2009-01-12 16:00:00    88.28
2009-01-13 16:00:00    87.34
2009-01-14 16:00:00    84.97
2009-01-15 16:00:00    83.02
2009-01-16 16:00:00    81.98
2009-01-20 16:00:00    77.87
2009-01-21 16:00:00    82.48
2009-01-22 16:00:00    87.98
2009-01-23 16:00:00    87.98
...
2009-12-10 16:00:00    195.59
2009-12-11 16:00:00    193.84
2009-12-14 16:00:00    196.14
2009-12-15 16:00:00    193.34
2009-12-16 16:00:00    194.20
2009-12-17 16:00:00    191.04
2009-12-18 16:00:00    194.59
2009-12-21 16:00:00    197.38
2009-12-22 16:00:00    199.50
2009-12-23 16:00:00    201.24
2009-12-24 16:00:00    208.15
2009-12-28 16:00:00    210.71
2009-12-29 16:00:00    208.21
2009-12-30 16:00:00    210.74
2009-12-31 16:00:00    209.83
Name: AAPL, Length: 252

如您所见,简单地偏移 30 不会产生正确的结果,因为时间戳数据中存在间隙,并非每个月都是 30 天,等等。我知道使用 pandas 必须有一种简单的方法来做到这一点。

【问题讨论】:

  • 不同是因为频率不同:BM是工作月份,M是月份(见docs)。

标签: python pandas


【解决方案1】:

您可以将数据重新采样到营业月。如果您不想要平均价格(这是resample 中的默认值),您可以使用关键字参数how 使用自定义重新采样方法:

In [31]: from pandas.io import data as web

# read some example data, note that this is not exactly your data!
In [32]: s = web.get_data_yahoo('AAPL', start='2009-01-02',
...                             end='2009-12-31')['Adj Close']

# resample to business month and return the last value in the period
In [34]: monthly = s.resample('BM', how=lambda x: x[-1])

In [35]: monthly
Out[35]: 
Date
2009-01-30     89.34
2009-02-27     88.52
2009-03-31    104.19
...
2009-10-30    186.84
2009-11-30    198.15
2009-12-31    208.88
Freq: BM

In [36]: monthly.pct_change()
Out[36]: 
Date
2009-01-30         NaN
2009-02-27   -0.009178
2009-03-31    0.177022
...
2009-10-30    0.016982
2009-11-30    0.060533
2009-12-31    0.054151
Freq: BM

【讨论】:

  • 注意你也可以使用asfreq('M', fill_method='ffill')。但是,需要注意日内数据
  • @WesMcKinney 不知道首选哪种方法:通常我会使用resample。使用asfreq有什么优势吗? (当使用asfreq 时,关键字似乎是method(在0.10 中不是fill_method
  • 请参阅问题中的更新
  • 我对您的问题添加了评论。 resample 应该可以工作,不确定asfreq 的优势。
  • resample 有一个新语法:__main__:1: FutureWarning: how in .resample() is deprecated the new syntax is .resample(...)..apply(<func>)。所以这个电话会变成In [34]: monthly = s.resample('BM').apply(lambda x: x[-1])
【解决方案2】:

我在使用 pct_change 函数时也偶然发现了这个错误,并且想在这个问题上提供我的两分钱。

pct_change 函数的 freq 参数似乎只接受固定周期的时间偏移,例如“2D”和“3D”。但是,“M”是一个不确定的时间段,可以在 28 天到 31 天之间。这就是错误的来源。

Pct_change 的操作类似于 rolling() 函数,使用“M”时间偏移和 rolling() 会得到相同的错误。

这是一个在 pct_change 参数中使用 freq 参数的工作示例:

将 pandas_datareader.data 导入为网络

return.pct_change(periods = 1, freq = '2D')

Date
2008-03-26         NaN
2008-03-27         NaN
2008-03-28   -0.010342
2008-03-31         NaN
2008-04-01         NaN
            ...   

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-13
    • 2017-09-26
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    • 2013-07-17
    相关资源
    最近更新 更多