【问题标题】:Sample and group by, and pivot time series data采样和分组,以及透视时间序列数据
【发布时间】:2021-06-23 09:04:38
【问题描述】:

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

我有一个时间序列数据集,并希望将其分解为按块分组的非重叠透视。它按客户、年份和价值进行组织。出于这个玩具示例的目的,我试图将其分解为对未来 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   |

非常感谢。

【问题讨论】:

  • 如果您有 6 个或更多日期为 1 位客户,您希望为该客户提供 2 行或更多行还是只有 1 行?
  • 只是 2。为了清楚起见,我更新了示例。

标签: pandas time-series


【解决方案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

【讨论】:

  • 我认为您需要客户在索引的前面。否则看起来不错并且有效!
  • 我相信您的支点实际上应该是支点表。我需要改变它才能让它工作。进行编辑,我很高兴回答。
  • pivot_table 聚合您的数据(默认为np.mean)。如果使用pivot 不起作用,则您的数据集中一定有重复项。
【解决方案2】:

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

首先我们添加一个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)

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

【讨论】:

    猜你喜欢
    • 2020-12-28
    • 1970-01-01
    • 2018-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多