Python基于日值CSV计算多年月均值并按月份缩写绘图
Python处理加拿大环境部逐日气候观测数据实现方案
核心实现思路
- 基于pandas做数据读取、清洗、聚合计算,对大规模逐日数据处理效率高,Spyder环境自带变量查看功能,入门阶段调试方便,后续批量处理15个站点只需封装函数循环调用即可,无需重复写代码。
- 统计逻辑严格匹配需求拆分:
- 先做数据清洗:剔除降水、气温关键字段为空的记录,过滤降水为负、气温超出合理区间的异常值,避免统计偏差
- 第一层聚合(年+月维度):按年份、月份分组,对总降水量做当月逐日求和、对平均气温做当月逐日求均值,得到逐年逐月的基础统计表,作为后续多年统计、指定时段导出的数据源
- 第二层聚合(月维度):基于逐年逐月表,按月份分组对月总降水量、月平均气温求跨年份均值,直接得到1-12月的多年月平均统计结果
- 绘图采用matplotlib双Y轴方案,柱状图展示降水量、折线图展示气温,横轴替换为通用月份缩写,结果直观
- 指定时段导出直接在逐年逐月基础表上做年份筛选,用pandas内置导出方法生成CSV即可。
首次运行前先在Spyder的IPython控制台执行命令安装依赖:
pip install pandas matplotlib numpy
完整参考代码
1. 基础导入与配置
import pandas as pd import matplotlib.pyplot as plt import numpy as np import os # 配置绘图参数,兼容中文显示、负号正常显示 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False
2. 数据读取与清洗
# 替换为本地存储的站点CSV文件路径 raw_df = pd.read_csv( '你的站点数据文件.csv', # 如果原始数据里用M/T等标记缺测,放开下面这行注释自动识别为空值 # na_values=['M', 'T', ''] ) # 筛选计算需要的字段,剔除空值记录 use_cols = ['YYYY', 'MM', 'DD', 'Total Precip', 'Mean Temp'] raw_df = raw_df.dropna(subset=use_cols) # 过滤异常值:降水量不能为负,气温合理区间设为-60℃到60℃,可根据站点实际情况调整 raw_df = raw_df[ (raw_df['Total Precip'] >= 0) & (raw_df['Mean Temp'].between(-60, 60)) ]
3. 生成逐年逐月基础统计数据
# 第一层聚合:按年、月分组,计算单月总降水量、单月平均气温 monthly_stats = raw_df.groupby(['YYYY', 'MM'], as_index=False).agg( month_total_precip = ('Total Precip', 'sum'), month_mean_temp = ('Mean Temp', 'mean') )
4. 计算多年月平均值(对应需求1)
# 第二层聚合:按月份分组,计算所有年份同月的平均值 clim_stats = monthly_stats.groupby('MM', as_index=False).agg( avg_monthly_precip = ('month_total_precip', 'mean'), avg_monthly_temp = ('month_mean_temp', 'mean') ) # 匹配月份缩写,用于后续绘图和导出 month_abbr_list = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] clim_stats['month_abbr'] = month_abbr_list
5. 绘制多年月均统计双轴图(对应需求2)
fig, ax_precip = plt.subplots(figsize=(10, 6)) # 左轴绘制降水量柱状图 ax_precip.bar( clim_stats['month_abbr'], clim_stats['avg_monthly_precip'], color='#2E86AB', alpha=0.7, label='多年月平均降水量' ) ax_precip.set_xlabel('月份') ax_precip.set_ylabel('平均降水量(mm)', color='#2E86AB') ax_precip.tick_params(axis='y', labelcolor='#2E86AB') # 右轴绘制气温折线图 ax_temp = ax_precip.twinx() ax_temp.plot( clim_stats['month_abbr'], clim_stats['avg_monthly_temp'], color='#F24C00', marker='o', linewidth=2, label='多年月平均气温' ) ax_temp.set_ylabel('平均气温(℃)', color='#F24C00') ax_temp.tick_params(axis='y', labelcolor='#F24C00') # 合并双轴图例 handles1, labels1 = ax_precip.get_legend_handles_labels() handles2, labels2 = ax_temp.get_legend_handles_labels() ax_precip.legend(handles1 + handles2, labels1 + labels2, loc='upper left') plt.title('气候站多年月平均降水量与气温统计') plt.tight_layout() plt.show()
6. 导出指定时段逐月统计结果(对应需求3)
# 自定义需要导出的年份范围 target_start = 1980 target_end = 2010 # 筛选指定时段数据 export_df = monthly_stats[ (monthly_stats['YYYY'] >= target_start) & (monthly_stats['YYYY'] <= target_end) ].copy() # 增加月份缩写列方便查看 export_df['month_abbr'] = export_df['MM'].apply(lambda x: month_abbr_list[x-1]) # 调整列顺序 export_df = export_df[['YYYY', 'MM', 'month_abbr', 'month_total_precip', 'month_mean_temp']] # 导出为CSV,用utf-8-sig编码避免Excel打开乱码 export_df.to_csv( f'站点{target_start}-{target_end}年逐月统计结果.csv', index=False, encoding='utf-8-sig' )
批量处理15个站点的扩展方案
把单站点处理逻辑封装为函数,传入所有站点的文件路径循环调用即可,无需重复修改代码:
def process_single_station(csv_path, output_folder, export_start=1980, export_end=2010): """ 单气候站数据批量处理函数 :param csv_path: 原始CSV文件路径 :param output_folder: 结果存储文件夹路径 :param export_start: 导出数据起始年份 :param export_end: 导出数据结束年份 """ # 自动创建输出文件夹 if not os.path.exists(output_folder): os.makedirs(output_folder) # 读取清洗数据 df = pd.read_csv(csv_path, na_values=['M', 'T', '']) df = df.dropna(subset=['YYYY', 'MM', 'DD', 'Total Precip', 'Mean Temp']) df = df[(df['Total Precip'] >= 0) & (df['Mean Temp'].between(-60, 60))] # 逐月聚合 monthly = df.groupby(['YYYY', 'MM'], as_index=False).agg( month_total_precip=('Total Precip', 'sum'), month_mean_temp=('Mean Temp', 'mean') ) # 导出指定时段结果 station_name = os.path.basename(csv_path).split('.')[0] export_part = monthly[(monthly['YYYY'] >= export_start) & (monthly['YYYY'] <= export_end)] export_part.to_csv( f'{output_folder}/{station_name}_{export_start}-{export_end}逐月统计.csv', index=False, encoding='utf-8-sig' ) return monthly # 批量调用示例:把15个站点的CSV路径存入列表,循环执行即可 # station_file_list = ['站点1路径.csv', '站点2路径.csv', ..., '站点15路径.csv'] # for file in station_file_list: # process_single_station(file, './气候站统计结果/')
入门调试提示
- Spyder右上角的变量浏览器可以直接点开所有DataFrame表格查看中间结果,不需要反复写print语句,方便核对计算是否正确
- 如果读取CSV时报编码错误,给
pd.read_csv()添加encoding='gbk'或者encoding='latin1'参数重试即可 - 如果需要统计总降雨量、总降雪量、最高/最低气温的多年均值,直接在agg()函数里加对应字段的聚合规则就行,逻辑和现有统计完全一致
内容的提问来源于stack exchange,提问作者kcastrom94
相关产品推荐
相关产品推荐

