使用 pandas GroupBy 和时间序列重采样的平均聚合
Posted
技术标签:
【中文标题】使用 pandas GroupBy 和时间序列重采样的平均聚合【英文标题】:Mean Aggregations using pandas GroupBy and Time Series resampling 【发布时间】:2021-04-07 17:42:31 【问题描述】:我在使用 Pandas groupby 功能和时间序列时遇到问题。我已阅读文档,但无法弄清楚如何将聚合函数应用于多个列并正确计算“聚合”的体积(平均值)的平均值。
这是我导入 CSV 文件的代码:
#CSV Import
import pandas as pd
path = r'Z:\Python\30_Min_Data.txt'
from datetime import datetime
customdateparse = lambda x: datetime.strptime(x, '%Y/%m/%d %H:%M:%S.%f')
df = pd.read_csv(
path,
parse_dates='DateTime': [0, 1],
date_parser=customdateparse)
# Set the Date as the Index --> needed for Resampling
df.set_index('DateTime', inplace=True)
df.sort_index()
这是我导入后的 DataFrame:
df
Out[3]:
Volume Session
DateTime
2020-12-16 08:00:00 1000 PRTH
2020-12-16 08:30:00 5000 PRTH
2020-12-16 09:00:00 1000 RTH
2020-12-16 09:30:00 3000 RTH
2020-12-17 08:00:00 2000 PRTH
2020-12-17 08:30:00 2000 PRTH
2020-12-17 09:00:00 2000 RTH
2020-12-17 09:30:00 2000 RTH
2020-12-18 08:00:00 1000 PRTH
2020-12-18 08:30:00 1000 PRTH
2020-12-18 09:00:00 1000 RTH
2020-12-18 09:30:00 1000 RTH
2019-11-18 08:00:00 1000 PRTH
2019-11-18 08:30:00 1000 PRTH
2019-11-18 09:00:00 1000 RTH
2019-11-18 09:30:00 1000 RTH
这是我尝试过的: 由于时间序列重采样,它计算每天的平均值。 我希望它首先对值求和,最后计算平均值。 但它确实意味着每天的所有数据。
#2.Volume: Average per Year & Session & Day
funcs_year = lambda idx: idx.year
(df
.groupby([funcs_year,'Session', pd.Grouper(freq='D')])
['Volume']
.mean()
)
Out[6]:
Session DateTime
2019 PRTH 2019-11-18 1000
RTH 2019-11-18 1000
2020 PRTH 2020-12-16 3000
2020-12-17 2000
2020-12-18 1000
RTH 2020-12-16 2000
2020-12-17 2000
2020-12-18 1000
Name: Volume, dtype: int64
这就是我希望正确计算和显示结果的方式(我是手动计算的): 每天的平均(平均)交易量(分别显示年份和会话):
Year Session Mean Volume
2020 RTH 3.333,33
PRTH 4.000,00
2019 RTH 2.000,00
PRTH 2.000,00
有人知道我错过了什么/做错了吗?
【问题讨论】:
让我知道以下是否适合您df.groupby([df.index.strftime('%Y'),'Session']).agg('Volume':['sum','mean'])
感谢您的努力。总和是正确的,但不幸的是平均值不是。对于平均值,它取总和,然后将其与时间序列中找到的行相除。 2019 年和 Session = PRTH 的示例:Sum 为 2000,然后它计算平均值 2000 / 2 = 1000。它没有考虑我们进行了重新采样,它应该计算平均每天计数而不是行计数。因为两条记录的日期相同,所以如果我们按天重新采样(就像我一样),它只是一天而不是两行。 2019 年和 Session = PRTH 的正确平均值为:2000 / 1 = 2000
如果我错了,请纠正我,我从您的问题中了解到,您想根据年份和每天的平均交易量计算交易量总和,对吗?
@k33da_lets_debug:正确。看我上面的例子,结果应该如何。谢谢
好的,请参阅答案部分。我提供了使用 groupby 链接的替代解决方案。
【参考方案1】:
以下也应该有效,根据您的问题,“总和”显示基于“年份”的“交易量总和”,“平均”显示基于“每日平均”的“交易量平均”,均按“会话”分组和“日期时间”。 (只是使用了一些带有连接的 groupy 链接)
import pandas as pd
data =
'DateTime':['2020-12-16 08:00:00','2020-12-16 08:30:00','2020-12-16 09:00:00','2020-12-16 09:30:00','2020-12-17 08:00:00','2020-12-17 08:30:00','2020-12-17 09:00:00','2020-12-17 09:30:00','2020-12-18 08:00:00','2020-12-18 08:30:00','2020-12-18 09:00:00','2020-12-18 09:30:00','2019-11-18 08:00:00','2019-11-18 08:30:00','2019-11-18 09:00:00','2019-11-18 09:30:00'],
'Volume':[1000,500,1000,3000,2000,2000,2000,2000,1000,1000,1000,1000,1000,1000,1000,1000],
'Session':['PRTH','PRTH','RTH','RTH','PRTH','PRTH','RTH','RTH','PRTH','PRTH','RTH','RTH','PRTH','PRTH','RTH','RTH']
df = pd.DataFrame(data)
df['DateTime'] = pd.to_datetime(df['DateTime'])
df.index = pd.to_datetime(df['DateTime'])
#See below code
x = df.groupby([df.index.strftime('%Y'),'Session',df.index.strftime('%Y-%m-%d')]).agg('Volume':['sum','mean']).groupby(['DateTime','Session'],level=2).agg(['sum','mean'])
x['Volume'].drop('mean',axis=1,level=0)
【讨论】:
感谢替代方法,它也有效,但我发现第一个更容易理解【参考方案2】:这对你有用吗:
df['Year']=df['DateTime'].dt.year
(df
.groupby(['Year','Session'])
.apply(lambda x: x['Volume'].sum()/len(x['DateTime'].dt.date.unique()))
)
请注意,“日期时间”现在应该是一列。
我认为这计算了每年和 Session 的平均每日交易量。可以试一试吗?
【讨论】:
Thnx,但它给了我 KeyError: 'DateTime'code
File "C:\Users\UL\miniconda3\lib\site-packages\pandas\core\indexes\base.py",第 2900 行,在 get_loc 中从 err 引发 KeyError(key)
不错的解决方案。我也在做这个。
@udi76623:您已将“日期时间”作为索引。删除脚本开头的 set_index() 。我认为这将解决您的问题。
@flow_me_over: Thnx,但没有设置索引并运行您的解决方案,我得到:File "pandas\_libs\lib.pyx", line 2403, in pandas._libs.lib.map_infer File "<ipython-input-7-4d53a12ff682>", line 1, in <lambda> funcs_year = lambda idx: idx.year AttributeError: 'int' object has no attribute 'year'
@udi76623:嗯,是的,那么你可以试试 df['DateTime'].dt.year,而不是 groupby 中的 funcs_year。或者,创建一个列 df['Year']=df['DateTime'].dt.year,然后在 ['Year', 'Session'] 上进行分组。我已将示例更改为添加附加列;见上文。以上是关于使用 pandas GroupBy 和时间序列重采样的平均聚合的主要内容,如果未能解决你的问题,请参考以下文章
在 Pandas 中使用 Keras StandardScaler 和 Groupby 函数
使用 matplotlib 和 pandas 制作 groupby 图