熊猫桶时间戳到 TimeGrouper 频率组

Posted

技术标签:

【中文标题】熊猫桶时间戳到 TimeGrouper 频率组【英文标题】:pandas bucket timestamp into TimeGrouper frequency group 【发布时间】:2020-12-29 10:45:23 【问题描述】:

我在 pandas 中有一个带有 DateTime 索引的数据框。 当使用 time grouper:pd.Grouper(freq='360Min') 对其进行分组时,如何将此结果加入原始时间戳? IE。 equijoin timestamp=bucket 不起作用? 有便利功能吗? 应该使用asof 连接吗? 还是我必须手动提取小时数,然后尝试匹配?

示例:

来源

import pandas as pd
df = pd.DataFrame(
   
       "Publish date": [
            pd.Timestamp("2000-01-02"),
            pd.Timestamp("2000-01-02"),
            pd.Timestamp("2000-01-09"),
            pd.Timestamp("2000-01-16")
        ],
        "ID": [0, 1, 2, 3],
        "Price": [10, 20, 30, 40]
    
)

这给出了:

  Publish date  ID  Price
0   2000-01-02   0     10
1   2000-01-02   1     20
2   2000-01-09   2     30
3   2000-01-16   3     40

我想以任意频率(不仅是月、日、小时)执行聚合,比如说 1

month.

agg_result = df.groupby(pd.Grouper(key="Publish date", freq="1M")).agg([pd.Series.mean, pd.Series.median]).reset_index()
agg_result.columns = ['_'.join(col).strip() for col in agg_result.columns.values]
agg_result.columns = ['Publish date month', 'ID_mean', 'ID_median', 'Price_mean', 'Price_median']
print(agg_result)
Publish date month  ID_mean  ID_median  Price_mean  Price_median
0         2000-01-31      1.5        1.5          25            25

如何确保等值连接再次起作用? IE。使用相同的任意频率将原始时间戳转换为拟合桶?

即示例代码中描述的,如何获取:

agg_result['Publish date month'] = agg_result['Publish date'].apply(magic transform to same frequency bucket)
df.merge(agg_result, on['Publish date month'])

工作,即定义到正确存储桶的转换?

【问题讨论】:

【参考方案1】:

编辑:

识别每个组对应的原始值的最简单方法应该是:

gb = df.groupby(pd.Grouper(key="Publish date", freq="1M"))
dict(list(gb['Publish date']))

然后您可以使用它将任何信息连接回原始表。


你可以只加入两个中间列吗?

df['Publish date'].dt.month

df.groupby(pd.Grouper(key="Publish date", freq="1M")).agg([pd.Series.mean, pd.Series.median]).index.month

喜欢这个

results =  df.groupby(pd.Grouper(key="Publish date", freq="1M")).agg([pd.Series.mean, pd.Series.median])

results.columns = ['-'.join(col[::-1]).strip() for col in results.columns]

df['month'] = df['Publish date'].dt.month

results['month'] = results.index.month
results.merge(df)

【讨论】:

但这仅适用于月份。不是在提供 4 小时作为频率时。 啊,明白了——这很有道理。我想您仍然可以查看组 df.groupby(pd.Grouper(key="Publish date", freq="1M")).groups 然后查找包含的日期/时间。 df.groupby(pd.Grouper(key="Publish date", freq="1M")).get_group(pd.Timestamp('2000-01-31 00:00:00', freq='M')) 到建立一个连接键。我会按照这个来看看是否有人有更好的方法来做到这一点。 @GeorgHeiler 请查看我的编辑以获得更直接的方法。 也不错。两者都适用于小数据 - 并且都失败了真实数据;)但原则上,它们解决了问题。由于这个使用的 JOIN 较少,我想这个可能是首选,我会将其标记为已接受。 @GeorgHeiler 谢谢。你面临的错误是什么?是在 groupby agg 函数期间还是在 join 期间?如果是连接,您可以尝试创建一个自定义 groupby 函数以返回具有聚合信息(例如中位数、平均值)的组以及组本身。如果您提供一个单行代码来从 numpy 创建一个随机数据集构建,但仍然会给您带来错误,我很乐意看看。【参考方案2】:

我会使用Groupby.transform 方法:

import pandas as pd
df = pd.DataFrame(
   
       "Publish date": [
            pd.Timestamp("2000-01-02"),
            pd.Timestamp("2000-01-02"),
            pd.Timestamp("2000-01-09"),
            pd.Timestamp("2000-01-16")
        ],
        "ID": [0, 1, 2, 3],
        "Price": [10, 20, 30, 40]
    
)

g = df.groupby(pd.Grouper(key="Publish date", freq="1M"))

(
  df.join(g.transform('mean'), rsuffix='_mean')
    .join(g.transform('median'), rsuffix='_median')
)

然后返回:

  Publish date  ID  Price  ID_mean  Price_mean  ID_median  Price_median
0   2000-01-02   0     10      1.5          25        1.5            25
1   2000-01-02   1     20      1.5          25        1.5            25
2   2000-01-09   2     30      1.5          25        1.5            25
3   2000-01-16   3     40      1.5          25        1.5            25

您也可以使用pandas.concat 代替DataFrame.join

methods = ['mean', 'median', 'std', 'min', 'max']

pd.concat([
    df, *[g.transform(m).add_suffix(f'_m') for m in methods]
], axis='columns')

这给了你:

  Publish date  ID  Price  ID_mean  Price_mean  ID_median  Price_median    ID_std  Price_std  ID_min  Price_min  ID_max  Price_max
0   2000-01-02   0     10      1.5          25        1.5            25  1.290994  12.909944       0         10       3         40
1   2000-01-02   1     20      1.5          25        1.5            25  1.290994  12.909944       0         10       3         40
2   2000-01-09   2     30      1.5          25        1.5            25  1.290994  12.909944       0         10       3         40
3   2000-01-16   3     40      1.5          25        1.5            25  1.290994  12.909944       0         10       3         40

【讨论】:

很好,但如果我想保留列表(可以灵活地作为函数参数传递),是否可以动态构建df.join.transform(xxxx) @GeorgHeiler 是的,您可以将concat 与列表理解一起使用。查看编辑。 整洁。但我想df.groupby(pd.Grouper(key="Publish date", freq="1M")).get_group(pd.Timestamp('2000-01-31 00:00:00', freq='M')) 下面的评论更好,因为你的反复需要一个 JOIN(这可能很慢=而且这个只使用一个应用 UDF,然后是一个 JOIN。这是正确的吗? @GeorgHeiler 我不知道。您应该分析可能的答案。

以上是关于熊猫桶时间戳到 TimeGrouper 频率组的主要内容,如果未能解决你的问题,请参考以下文章

多索引上的 Pandas TimeGrouper

pandas TimeGrouper 自定义频率时间范围

我正在尝试使用 pandas TimeGrouper 创建一些日期的频率表,但是它返回错误

在 C# 中计算数组频率分布的最快方法是啥?

如何使用 TimeGrouper 遍历包含不同范围的多个文件

工作日的熊猫石斑鱼?