如何为带用户ID的时间序列数据计算可扩展的移动周平均值?
问题
我有带用户ID列(uid)和连续数值列(col)的时间序列数据,想为每个用户计算数值的移动周平均值并生成新列。以下是生成样本数据集的代码:
import pandas as pd import numpy as np df = pd.DataFrame(index=pd.date_range(freq=f'{60}T',start='2020-01-01',periods=(1)*24*14)) df['col'] = np.random.random_integers(0, 250, size= df.shape[0]) df['uid'] = 1 df2 = pd.DataFrame(index=pd.date_range(freq=f'{60}T',start='2020-01-01',periods=(1)*24*14)) df2['col'] = np.random.random_integers(0, 150, size= df2.shape[0]) df2['uid'] = 2 df3=pd.concat([df, df2]).reset_index() df3
样本中每个用户有2周数据,要求每个用户生成两个平均值:
- 第一周所有行填充第一周的均值
- 第二周所有行填充前两周均值的平均值(即(第一周均值+第二周均值)/2)
真实数据集规模较大,需要可扩展的实现方案。
期望输出示例:
index uid col week_average 2020-01-01 00:00:00 1 104 week1_uid1_mean 2020-01-01 01:00:00 1 150 week1_uid1_mean 2020-01-01 02:00:00 1 243 week1_uid1_mean .... 2020-01-08 00:00:00 1 174 (week1_uid1_mean+week2_uid1_mean)/2 2020-01-08 01:00:00 1 24 (week1_uid1_mean+week2_uid1_mean)/2 ...
解决方案
步骤1:处理时间列并标记用户内周数
先确保时间列格式正确,再按用户分组,以每个用户的最早数据时间为基准,标记每行属于该用户的第几周:
# 确保时间列是datetime类型 df3['index'] = pd.to_datetime(df3['index']) # 按uid分组,计算每行对应的周序号(从1开始) df3['week_num'] = df3.groupby('uid')['index'].transform( lambda x: (x - x.min()).dt.days // 7 + 1 )
步骤2:计算用户每周的均值
按用户和周数分组,计算每周的col均值,再将结果合并回原数据集:
# 计算每个用户每周的col均值 weekly_means = df3.groupby(['uid', 'week_num'])['col'].mean().reset_index(name='weekly_mean') # 合并回原数据,让每行匹配所在周的均值 df3 = df3.merge(weekly_means, on=['uid', 'week_num'], how='left')
步骤3:计算移动周平均(累计均值)
按用户分组,对每周均值计算累计平均值,即前N周均值的平均,再将该值填充到对应周的所有行:
# 按uid分组,计算累计移动周平均 df3['week_average'] = df3.groupby('uid')['weekly_mean'].transform( lambda x: x.expanding().mean() )
完整可运行代码
整合所有步骤,同时替换已弃用的random_integers为randint:
import pandas as pd import numpy as np # 生成样本数据 df = pd.DataFrame(index=pd.date_range(freq=f'{60}T',start='2020-01-01',periods=(1)*24*14)) df['col'] = np.random.randint(0, 250, size= df.shape[0]) df['uid'] = 1 df2 = pd.DataFrame(index=pd.date_range(freq=f'{60}T',start='2020-01-01',periods=(1)*24*14)) df2['col'] = np.random.randint(0, 150, size= df2.shape[0]) df2['uid'] = 2 df3=pd.concat([df, df2]).reset_index() # 步骤1:处理时间并标记周数 df3['index'] = pd.to_datetime(df3['index']) df3['week_num'] = df3.groupby('uid')['index'].transform( lambda x: (x - x.min()).dt.days // 7 + 1 ) # 步骤2:计算每周均值 weekly_means = df3.groupby(['uid', 'week_num'])['col'].mean().reset_index(name='weekly_mean') df3 = df3.merge(weekly_means, on=['uid', 'week_num'], how='left') # 步骤3:计算移动周平均 df3['week_average'] = df3.groupby('uid')['weekly_mean'].transform( lambda x: x.expanding().mean() ) # 查看结果(可选) print(df3[['index', 'uid', 'col', 'week_average']].head())
方案说明
- 全程使用Pandas内置的分组和向量化运算,避免循环,性能高效,可轻松扩展到百万级以上数据
expanding().mean()直接实现“前N周均值的平均”需求,逻辑简洁清晰- 所有操作都基于用户分组,确保每个用户的周计算独立不干扰
内容的提问来源于stack exchange,提问作者prof32
相关产品推荐
相关产品推荐

