没有重采样的时间序列的 Pandas 子集

Posted

技术标签:

【中文标题】没有重采样的时间序列的 Pandas 子集【英文标题】:Pandas Subset of a Time Series Without Resampling 【发布时间】:2018-06-15 17:25:27 【问题描述】:

我有一个 pandas 数据系列,其中包含一个系列的每日累积回报:

Date    CumReturn
3/31/2017    1
4/3/2017     .99
4/4/2017     .992
 ...        ...
4/28/2017    1.012
5/1/2017     1.011
 ...         ...
5/31/2017    1.022
 ...         ...
6/30/2017    1.033
 ...         ...

我只想要月末值。

Date    CumReturn
4/28/2017    1.012
5/31/2017    1.022
6/30/2017    1.033

因为我只想要月末值,所以重采样不起作用,因为它聚合了中间值。

仅获取原始数据框中显示的月末值的最简单方法是什么?

【问题讨论】:

可以使用 pandas.tseries.offsets.MonthEnd 吗? 我该怎么做?我对时间序列的操作有点犹豫。 这里有很好的记录:pandas.pydata.org/pandas-docs/stable/timeseries.html 类似这样的东西:from pandas.tseries.offsets import MonthEnd df['EndOfMonth'] = pd.to_datetime(df['Date'], format="%m/%d/%Y") + MonthEnd(1) 其中 MonthEnd(1) 指定在下一个月末日期递增一 感谢您参考文档。在发布问题之前我确实看过它,但它似乎没有回答我的问题。如果我正确理解您的评论,我会使用偏移量得出一个或一系列月末值,然后使用它来获取数据框的子集? 执行上述操作将为您获取每个日期的 EndOfMonth,因此您需要进行子集化以仅保留 Date=EndOfMonth 的记录 【参考方案1】:

使用.dt date accessor 的is_month_end 组件:

# Ensure the date column is a Timestamp
df['Date'] = pd.to_datetime(df['Date'])

# Filter to end of the month only
df = df[df['Date'].dt.is_month_end]

将此应用于您提供的数据:

        Date  CumReturn
0 2017-03-31      1.000
5 2017-05-31      1.022
6 2017-06-30      1.033

编辑

要获得营业月结,请使用BMonthEnd(0)进行比较:

from pandas.tseries.offsets import BMonthEnd

# Ensure the date column is a Timestamp
df['Date'] = pd.to_datetime(df['Date'])

# Filter to end of the month only
df = df[df['Date'] == df['Date'] + BMonthEnd(0)]

将此应用于您提供的数据:

        Date  CumReturn
0 2017-03-31      1.000
3 2017-04-28      1.012
5 2017-05-31      1.022
6 2017-06-30      1.033

【讨论】:

谢谢。你能提供一个文件参考吗?我在搜索中没有遇到这种情况。 @Windstorm1981:请参阅我的答案中的链接。如果你想要 business 月底,is_month_end 将不起作用。 是的,这可能有问题。我真正需要的是某种方法来对数据框进行子集化,每月获取最大日期。那是因为这是业务数据,一些月末日期在周末。我可以按月对数据框进行子集化并循环获取最大值,但似乎应该有一种更简单的方法。我刚刚看到第二个答案(下)。虽然不太优雅,但它可能是解决我的特定问题的更好方法。 我添加了一个解决方案来获得业务月结。如果您真正关心的是每个月的 max 日期,无论是月末、营业月末还是两者都不是,请使用@Evan 的解决方案。请在以后更准确地表述您的问题。 这真是太好了。我将删除我的答案; pandas 的行为值得注意,但解决方案不正确。【参考方案2】:
df.sort_values('Date').groupby([df.Date.dt.year,df.Date.dt.month]).last()
Out[197]: 
                Date  CumReturn
Date Date                      
2017 3    2017-03-31      1.000
     4    2017-04-28      1.012
     5    2017-05-31      1.022
     6    2017-06-30      1.033

【讨论】:

这真是太好了。我将删除我的答案; pandas 的行为值得注意,但解决方案不正确。【参考方案3】:

假设数据框已经按“日期”排序,并且该列中的值是 Pandas 时间戳,您可以将它们转换为 YYYY-mm 字符串值进行分组并取最后一个值:

df.groupby(df['Date'].dt.strftime('%Y-%m'))['CumReturn'].last()

# Example output:
# 2017-01    0.127002
# 2017-02    0.046894
# 2017-03    0.005560
# 2017-04    0.150368

【讨论】:

以上是关于没有重采样的时间序列的 Pandas 子集的主要内容,如果未能解决你的问题,请参考以下文章

pandas的resample重采样

如何使用 Pandas 同时应用重采样和分组?

从 Pandas 的重采样中获取索引

Python 之 Pandas 生成时间戳范围Pandas 的时期函数 Period() 和时间序列 - 重采样 resample

Pandas:将重采样与 groupby 相结合并计算时间差

使用 pandas GroupBy 和时间序列重采样的平均聚合