熊猫桶时间戳到 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 创建一些日期的频率表,但是它返回错误