采样和分组,以及透视时间序列数据

时间:2021-06-22 18:04:47

标签: pandas time-series

我正在努力处理对时间序列数据的复杂(恕我直言)操作。

我有一个时间序列数据集,想将其分解为按块分组的非重叠枢轴。它按客户、年份和价值组织。出于这个玩具示例的目的,我试图将其分解为对未来 3 个月的简单预测。

df = pd.DataFrame({'Customer': {0: 'a', 1: 'a', 2: 'a', 3: 'a', 4: 'a',  5: 'a', 6: 'a', 7: 'b', 8: 'b', 9: 'b'},
                   'Year': {0: 2020, 1: 2020, 2: 2020, 3: 2020, 4: 2020,  5: 2021, 6: 2021, 7: 2020,  8: 2020, 9: 2020},
                   'Month': {0: 8, 1: 9, 2: 10, 3: 11, 4: 12,  5: 1, 6: 2, 7: 1, 8: 2, 9: 3},
                   'Value': {0: 5.2, 1: 2.2, 2: 1.7, 3: 9.0, 4: 5.5,  5: 2.5, 6: 1.9, 7: 4.5, 8: 2.9, 9: 3.1}})

我的目标是创建一个数据框,其中每一行都包含以 3 个月为透视增量的非重叠数据。所以每一行都有 3 个“值”数据点从那个时间点开始。我还希望此数据包含最新数据,因此如果数据量为奇数,则删除该数据(参见示例 a)。

| Customer | Year | Month | Month1 | Month2 | Month3 |
|     b    | 2020 |   1   |   4.5  |   2.9  |  3.1   |
|     a    | 2020 |   9   |   2.2  |   1.7  |  9.0   |
|     a    | 2020 |  12   |   5.5  |   2.5  |  1.9   |

非常感谢。

2 个答案:

答案 0 :(得分:1)

可能有更好的方法来做到这一点,但这会给你你想要的输出:

首先,我们添加一个 Customer_counter 列以向同一块的行成员添加 ID,然后删除额外的行。

df["Customer_chunk"] = (df[::-1].groupby("Customer").cumcount()) // 3
df = df.groupby(["Customer", "Customer_chunk"]).filter(lambda group: len(group) == 3)

然后我们按 Customer 和 Customer_chunk 分组以生成所需输出的每一列。

df_grouped = df.groupby(["Customer", "Customer_chunk"])
colYear = df_grouped["Year"].first()
colMonth = df_grouped["Month"].first()
colMonth1 = df_grouped["Value"].first()
colMonth2 = df_grouped["Value"].nth(2)
colMonth3 = df_grouped["Value"].last()

最后我们通过合并每一列来创建输出。

df_output = pd.concat([colYear, colMonth, colMonth1, colMonth2, colMonth3], axis=1).reset_index().drop("Customer_chunk", axis=1)

有些步骤感觉有点笨重,这段代码可能还有改进的空间,但它不应该对性能产生太大影响。

答案 1 :(得分:1)

一种方法是在您的 df 上先 sort_values 以便最近的月份排在最前面,分配组号并删除那些不在 3 组中的组号:

df = df.sort_values(["Year", "Month", "Customer"], ascending=False)
df["group"] = (df.groupby("Customer").cumcount()%3).eq(0).cumsum()
df = df[(df.groupby(["Customer", "group"])["Year"].transform("size").eq(3))]
df["num"] = (df.groupby("Customer").cumcount()%3+1).replace({1:3, 3:1})

print (df)

  Customer  Year  Month  Value  group  num
6        a  2021      2    1.9      2    3
5        a  2021      1    2.5      2    2
4        a  2020     12    5.5      2    1
3        a  2020     11    9.0      3    3
2        a  2020     10    1.7      3    2
1        a  2020      9    2.2      3    1
9        b  2020      3    3.1      5    3
8        b  2020      2    2.9      5    2
7        b  2020      1    4.5      5    1

现在您可以透视数据:

print (df.assign(Month=df["Month"].where(df["num"].eq(1)).bfill(),
                 Year=df["Year"].where(df["num"].eq(1)).bfill(),
                 num="Month"+df["num"].astype(str))
         .pivot(["Customer","Month","Year"], "num", "Value")
         .reset_index())

num Customer  Month    Year  Month1  Month2  Month3
0          a    9.0  2020.0     2.2     1.7     9.0
1          a   12.0  2020.0     5.5     2.5     1.9
2          b    1.0  2020.0     4.5     2.9     3.1