如何基于列名重组DataFrame,合并多列降雨数据为日期关联单列
Pandas多列逐日降雨数据转日期关联单列格式方案
问题场景
现有一个Pandas DataFrame,包含A、Date(仅记录年月)、C、D字段,以及rain01至rain31共31列字段,分别对应每月1-31日的降雨数据。需要将这些分散的降雨列合并为单列,并关联对应的完整日期,最终得到包含rain、A、C、D、day、month、year的结构化数据。
示例数据
生成示例DataFrame的代码如下:
import pandas as pd import numpy as np col = ['A', 'Date', 'C', 'D'] rain_cols = [f'rain{i:02d}' for i in range(1, 32)] dates = pd.date_range(start='1991-01-01', periods=5, freq='MS') df = pd.DataFrame({ 'A': np.random.rand(5), 'Date': dates, 'C': np.random.rand(5), 'D': np.random.rand(5) }) for i in range(1, 32): df[f'rain{i:02d}'] = np.random.rand(5) print(df.head())
示例输出:
A Date C D rain01 rain02 rain03 ... rain31 0 0.724846 1991-01-01 0.639414 0.367906 0.917830 0.697984 0.201039 ... 0.241123 1 0.594479 1991-02-01 0.411521 0.960513 0.364190 0.376364 0.911960 ... 0.773762 2 0.597719 1991-03-01 0.853656 0.909157 0.689504 0.619992 0.499380 ... 0.301950 3 0.054729 1991-04-01 0.268398 0.072613 0.202812 0.407357 0.576621 ... 0.959684 4 0.132683 1991-05-01 0.481039 0.216094 0.179478 0.834409 0.459967 ... 0.135629
预期结果
转换后的数据需要按日期排序,每一行对应单日降雨数据,示例如下(1月部分数据):
rain A C D day month year 0 0.718490 0.994329 0.501845 0.311373 1 1 1991 1 0.573670 0.797525 0.279621 0.138967 2 1 1991 2 0.174612 0.065365 0.085481 0.184512 3 1 1991
优化后的解决方案
针对原尝试代码中存在的日期合并问题,以下是优化后的完整实现:
import pandas as pd import numpy as np # 生成示例数据(同问题中的代码) col = ['A', 'Date', 'C', 'D'] rain_cols = [f'rain{i:02d}' for i in range(1, 32)] dates = pd.date_range(start='1991-01-01', periods=5, freq='MS') df = pd.DataFrame({ 'A': np.random.rand(5), 'Date': dates, 'C': np.random.rand(5), 'D': np.random.rand(5) }) for i in range(1, 32): df[f'rain{i:02d}'] = np.random.rand(5) # 1. 执行melt操作,保留所有非降雨列作为ID变量 df_melted = df.melt( id_vars=['A', 'Date', 'C', 'D'], value_vars=rain_cols, var_name='Day_str', value_name='rain' ) # 2. 提取日数:直接取rainXX字段的最后两位转整数 df_melted['Day'] = df_melted['Day_str'].str[-2:].astype(int) # 3. 生成完整日期:拼接年月字符串与日数字符串,自动过滤无效日期 df_melted['FullDate'] = pd.to_datetime( df_melted['Date'].dt.strftime('%Y-%m-') + df_melted['Day'].astype(str), errors='coerce' ) # 4. 清理数据并整理列结构 df_final = df_melted.dropna(subset=['FullDate']).copy() # 拆分年、月、日字段 df_final['year'] = df_final['FullDate'].dt.year df_final['month'] = df_final['FullDate'].dt.month df_final['day'] = df_final['FullDate'].dt.day # 调整列顺序并排序 df_final = df_final[['rain', 'A', 'C', 'D', 'day', 'month', 'year']] df_final = df_final.sort_values(by=['year', 'month', 'day']).reset_index(drop=True) print(df_final.head())
优化说明
- 保留完整关联字段:melt时将
A、C、D都纳入id_vars,避免后续需要重新关联这些字段 - 高效提取日数:用
str[-2:]替代正则提取,代码更简洁且性能更优 - 自动处理无效日期:通过
pd.to_datetime的errors='coerce'参数,自动将不存在的日期(如2月30日、4月31日)转为NaN,再通过dropna过滤 - 结构化输出:拆分出
year、month、day字段,并调整为预期的列顺序,最终数据按日期排序
内容的提问来源于stack exchange,提问作者tripster
相关产品推荐
相关产品推荐

