如何在R中基于单列数据绘制多图并计算ID分组累积平均变化
解决ID分组下多序列的累积平均绘图问题
我来帮你搞定这个需求!核心思路是先给同一ID下的独立序列(也就是你说的不同timespan条目组)打上标记,再计算每个序列内的累积平均,最后分别绘图展示。下面用Python的pandas和matplotlib/seaborn来实现:
步骤1:数据准备与分组标记
首先我们把你的数据转成DataFrame,然后给同一ID下的独立序列分配组ID。观察你的数据,同一组的amount_ID是从1开始递增的,所以我们可以用amount_ID == 1来识别新序列的起点,这样标记组ID会更准确:
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # 构建你的数据 data = { 'ID': [3,3,3,3,3,9,9,9,9,3,3,3,9,9,9], 'amount_ID': [1,2,3,4,5,1,2,3,4,1,2,3,1,2,3], 'timespan': [20,40,60,80,100,25,50,75,100,33.33,66.67,100,33.33,66.67,100], 'change': [2,3,6,4,5,1,-2,0,-1,4,8,7,1,3,4] } df = pd.DataFrame(data) # 给同一ID下的独立序列标记组ID df['group_id'] = df.groupby('ID')['amount_ID'].apply(lambda x: (x == 1).cumsum())
步骤2:计算累积平均
接下来针对每个(ID, group_id)组合,计算当前及之前所有change的平均值——也就是累积和除以当前的条目数:
# 计算每个组内的累积平均 df['cumulative_avg'] = df.groupby(['ID', 'group_id'])['change'].transform( lambda x: x.cumsum() / (x.reset_index(drop=True).index + 1) )
这里用transform是为了保持结果和原DataFrame的行数一致,方便后续绘图。
步骤3:分别绘制ID=3和ID=9的图
现在我们可以把每个ID的不同序列用不同的线条/标记区分开,绘图展示:
绘制ID=3的累积平均图
sns.set_style("whitegrid") plt.figure(figsize=(10, 6)) # 遍历ID=3下的所有独立组 for group_num in df[df['ID'] == 3]['group_id'].unique(): group_data = df[(df['ID'] == 3) & (df['group_id'] == group_num)] plt.plot(group_data['timespan'], group_data['cumulative_avg'], marker='o', linewidth=2, label=f'Sequence {group_num}') plt.title('Cumulative Average of Change for ID = 3', fontsize=14) plt.xlabel('Timespan', fontsize=12) plt.ylabel('Cumulative Average of Change', fontsize=12) plt.legend(title='Sequence') plt.show()
绘制ID=9的累积平均图
plt.figure(figsize=(10, 6)) # 遍历ID=9下的所有独立组 for group_num in df[df['ID'] == 9]['group_id'].unique(): group_data = df[(df['ID'] == 9) & (df['group_id'] == group_num)] plt.plot(group_data['timespan'], group_data['cumulative_avg'], marker='s', linewidth=2, label=f'Sequence {group_num}') plt.title('Cumulative Average of Change for ID = 9', fontsize=14) plt.xlabel('Timespan', fontsize=12) plt.ylabel('Cumulative Average of Change', fontsize=12) plt.legend(title='Sequence') plt.show()
额外说明
如果你的独立序列不是通过amount_ID从1开始来区分的,而是通过timespan的变化(比如突然变小),可以把组ID的标记代码改成这样:
df['group_id'] = df.groupby('ID')['timespan'].apply(lambda x: (x.diff() < 0).cumsum())
这个逻辑是:当当前行的timespan比前一行小时,判定为新序列的起点。
这样处理后,同一ID下的不同序列会被清晰区分,每个序列的累积平均也会正确计算并展示在图上啦!
内容的提问来源于stack exchange,提问作者Luc
相关产品推荐
相关产品推荐

