Pandas多列分组计算标准差异常求助(PM2.5数据场景)
解决PM2.5月均浓度标准差计算异常的问题
看起来你踩了pandas分组统计的一个常见小坑——不小心对所有数值列计算了标准差,而不是只针对conc列,另外最后那个apply的写法也完全不符合你的需求。让我一步步帮你理清问题并解决:
问题根源分析
你给出的异常sd结果里,year列出现44.87这种数值,这明显是年份(比如2014-2023区间)的标准差,而不是PM2.5浓度的标准差。这说明你实际运行的代码可能漏写了指定统计的列,比如把:
sd = d_avg.groupby(['year', 'month'], as_index=False)['conc'].std()
写成了:
sd = d_avg.groupby(['year', 'month'], as_index=False).std()
后者会对d_avg里所有数值型列(year、month、conc)都计算标准差,这完全不是你要的结果。
而你尝试的第三种写法:
sd = d_avg['conc'].apply(lambda x: x.std())
是完全错误的——apply在Series上是对每个元素执行lambda,单个数值的标准差没有意义,这只会得到一堆NaN或者无意义的值。
正确的解决方案
1. 正确计算每月日均浓度的标准差
明确指定只对conc列计算分组标准差,同时重命名列方便后续合并:
# 按年、月分组,计算每组内conc列的标准差 sd = d_avg.groupby(['year', 'month'], as_index=False)['conc'].std() # 重命名标准差列,避免和平均值列重名 sd = sd.rename(columns={'conc': 'conc_std'})
这样得到的sd应该是你想要的格式:
| year | month | conc_std |
|---|---|---|
| 2014 | 1 | 1.795868 |
| 2014 | 2 | 2.355055 |
2. 合并平均值和标准差数据
把标准差数据和你已经生成的月均数据m_avg合并,方便后续绘图:
m_avg_with_std = pd.merge(m_avg, sd, on=['year', 'month'], how='left')
合并后的数据框会包含year、month、conc(月均值)、datetime、conc_std(月内日均浓度的标准差),完美满足绘图需求。
3. 绘制带误差棒的月均浓度图
用matplotlib绘制带误差棒的折线图示例:
import matplotlib.pyplot as plt plt.figure(figsize=(12, 6)) # 绘制带误差棒的折线图,capsize控制误差棒末端的短横线长度 plt.errorbar( x=m_avg_with_std['datetime'], y=m_avg_with_std['conc'], yerr=m_avg_with_std['conc_std'], fmt='-o', # 折线+圆点标记 capsize=5, color='#2c3e50', ecolor='#e74c3c' ) plt.title('Monthly Average PM2.5 Concentration (2014+) with Std Error Bars') plt.xlabel('Date') plt.ylabel('PM2.5 Concentration (μg/m³)') plt.xticks(rotation=45) plt.tight_layout() # 自动调整布局,避免标签被截断 plt.show()
额外注意事项
- 如果某些月份只有1天的数据,对应的标准差会是
NaN,绘图时可以用m_avg_with_std.dropna(subset=['conc_std'])过滤掉这些行,或者根据需求填充合理值(比如0,但要谨慎)。 - 确认你的
d_avg数据是正确的日均浓度——从你的样例来看是没问题的,但可以用d_avg.groupby(['year','month']).size()检查每个月的天数是否合理。
内容的提问来源于stack exchange,提问作者obscuredbyclouds
相关产品推荐
相关产品推荐

