在数据帧时间序列的每月序列中查找给定月份的历史季节性平均值

Posted

技术标签:

【中文标题】在数据帧时间序列的每月序列中查找给定月份的历史季节性平均值【英文标题】:Finding historical seasonal average for given month in a monthly series in a dataframe time-series 【发布时间】:2020-07-24 18:03:12 【问题描述】:

我有一个数据框(下面的 sn-p),其索引格式为 YYYYMM 和几列值,包括一个名为“月”的值,其中我从索引列中提取了 MM 数据。

      index             st             us       stu     px month
0    202001      2616757.0      3287969.0  0.795858  2.036    01
1    201912      3188693.0      3137911.0  1.016183  2.283    12
2    201911      3610052.0      2752828.0  1.311398  2.625    11
3    201910      3762043.0      2327289.0  1.616492  2.339    10
4    201909      3414939.0      2216155.0  1.540930  2.508    09

我想做的是创建一个名为“stavg”的新列,它采用给定月份的“st”列的 5 年平均值。例如,由于第一行指的是 202001 年,因此该行的 stavg 应该是 2019 年、2018 年、2017 年、2016 年和 2015 年 1 月值的平均值。每隔一年回溯一次应该拉回移动平均线同样,例如 201205 的行的 stavg 应该显示 2011、2010、2009、2008 和 2007 年 5 月值的平均值。

      index             st             us       stu     px month   stavg   
0    202001      2616757.0      3287969.0  0.795858  2.036    01     xxx    
1    201912      3188693.0      3137911.0  1.016183  2.283    12     xxx
2    201911      3610052.0      2752828.0  1.311398  2.625    11     xxx
3    201910      3762043.0      2327289.0  1.616492  2.339    10     xxx
4    201909      3414939.0      2216155.0  1.540930  2.508    09     xxx

我知道如何根据对同一行上其他列的操作生成新的数据列(例如将 'st' 除以 'us' 得到 'stu' 并从索引中提取数字得到 'month')但是根据以前的值创建一列数据的想法真的让我很难过。

任何有关如何解决此问题的线索将不胜感激!我知道对于前五年的数据,我将无法用任何东西填充“stavg”列,这很好——我可以在那里使用 NaN。

【问题讨论】:

这能回答你的问题吗? Moving average or running mean ***.com/questions/40060842/moving-average-pandas 这些基本的移动平均线帖子并没有真正解决问题的核心,即需要平均的值分布在系列中,而不仅仅是最近的值。我试图仅对过去五年中每个月的值进行平均,而不是像简单的移动平均线那样只取过去五个月的平均值。 说了这么多,如果有人将常规移动平均代码的解释概括为适用于像我这样的季节性案例,我想很多人会发现这很有用! 【参考方案1】:

尝试定义一个函数并使用apply方法

df['year'] = (df['index'].astype(int)/100).astype(int)

def get_stavg(df, year, month):
    # get year from index

    df_year_month = df.query('@year - 5 <= year < @year and month == @month')
    return df_year_month.st.mean()


df['stavg'] = df.apply(lambda x: get_stavg(df, x['year'], x['month']), axis=1)

【讨论】:

嗯,这对我不起作用,部分原因是“不支持的操作数类型 //:'str' 和 'int'”我猜这意味着我的索引是字符串或 int(相反到浮动??)。任何线索如何解决这个问题? index。不是指数据框的索引,您有一个名为index 的列。我遵循年月格式,我认为这一列是一个整数。那么很难处理与字符串的比较,你可以做df['index'] = df['index'].astype(int)。在所有这些之前,让我知道这是否有效。 感谢您的额外帮助,jcaliz。我现在得到“TypeError:不支持的操作数类型//:'VariableNode'和'int'”。因此,即使在代码中预先添加 df['index'] = df['index'].astype(int) 之后,它似乎仍然对 'index' 不满意。 // 是否需要其他类型的变量?非常感谢您的帮助! //。只是获取除法的整数部分的方便方法,我已经用更简单的版本更新了解决方案,但是你能把df.dtypes 的输出放在数据框中吗?我很想知道你在数据框中有什么数据类型。 非常感谢,jcaliz,我认为这行得通!这是我从 df.dtypes 看到的: index object NG.N5020US2.M float64 NG.N9140US2.M float64 stu float64 px float64 month object 无论如何,新方法似乎有效,所以我非常感谢你的帮助和耐心.【参考方案2】:

如果您正在寻找 pandas 唯一的解决方案,您可以这样做

虚拟数据

在这里,我们创建了一个虚拟数据集,其中包含 10 年的数据,只有两个月(1 月和 2 月)。

import pandas as pd


df1 = pd.DataFrame("date":pd.date_range("2010-01-01", periods=10, freq="AS-JAN"))
df2 = pd.DataFrame("date":pd.date_range("2010-01-01", periods=10, freq="AS-FEB"))
df1["n"] = df1.index*2
df2["n"] = df2.index*3
df = pd.concat([df1, df2]).sort_values("date").reset_index(drop=True)

df.head(10)
        date   n
0 2010-01-01   0
1 2010-02-01   0
2 2011-01-01   2
3 2011-02-01   3
4 2012-01-01   4
5 2012-02-01   6
6 2013-01-01   6
7 2013-02-01   9
8 2014-01-01   8
9 2014-02-01  12

Groupby + 滚动平均

df["n_mean"] = df.groupby(df["date"].dt.month)["n"]\
                 .rolling(5).mean()\
                 .reset_index(0,drop=True)
         date   n  n_mean
0  2010-01-01   0     NaN
1  2010-02-01   0     NaN
2  2011-01-01   2     NaN
3  2011-02-01   3     NaN
4  2012-01-01   4     NaN
5  2012-02-01   6     NaN
6  2013-01-01   6     NaN
7  2013-02-01   9     NaN
8  2014-01-01   8     4.0
9  2014-02-01  12     6.0
10 2015-01-01  10     6.0
11 2015-02-01  15     9.0
12 2016-01-01  12     8.0
13 2016-02-01  18    12.0
14 2017-01-01  14    10.0
15 2017-02-01  21    15.0
16 2018-01-01  16    12.0
17 2018-02-01  24    18.0
18 2019-01-01  18    14.0
19 2019-02-01  27    21.0

根据定义,前 4 年的结果是 NaN

更新

针对您的特殊情况

import pandas as pd

index = [f"y01" for y in range(2010, 2020)] +\
        [f"y02" for y in range(2010, 2020)]

df = pd.DataFrame("index":index)
df["st"] = df.index + 1
# dates/ index should be sorted
df = df.sort_values("index").reset_index(drop=True)

# extract month
df["month"] = df["index"].str[-2:]


df["st_mean"] = df.groupby("month")["st"]\
                  .rolling(5).mean()\
                  .reset_index(0,drop=True)


【讨论】:

谢谢,rpanai。这看起来很有希望,但我不能让它工作,因为我的原始索引列实际上不是日期时间序列。它只是一个 YYYYMM 字符串。我尝试使用 df.index.to_datetime() 对其进行转换,但我遇到了错误“'RangeIndex' object has no attribute 'to_datetime'”,我被卡住了。您知道将列转换和索引为日期时间的任何其他方法吗?

以上是关于在数据帧时间序列的每月序列中查找给定月份的历史季节性平均值的主要内容,如果未能解决你的问题,请参考以下文章

R语言ggplot2可视化:可视化时间序列季节图使用季节图可以比较不同年份相同月份的数据差异或者相同(年/月/周等)的时间序列在同一天的数据差异(Seasonal Plot)

如何在 django 1.11 中查找给定月份每周的记录数?

具有季节性的Excel时间序列预测

获得池中每个人每月的前 3 名

在 pandas 中查找每月某个时间范围内发生的定期付款

过滤特定月份的日期列