Pandas如何实现DataFrame按日索引、Topic转列并匹配对应数值
问题场景
现有包含Date、Val、Topic三列的DataFrame对象df,需要构建新DataFramedf1满足以下要求:
- 以自然日作为行索引
- 每个
Topic的唯一取值作为单独列 - 列中存储对应Topic在当日的数值
用户初始尝试代码如下:
import numpy as np import pandas as pd import random rng = pd.date_range('2015-02-24', periods=50, freq='H') TOPIC=np.random.choice(5, len(rng), replace=True) df = pd.DataFrame({ 'Date': rng, 'Val' : np.random.randn(len(rng)),'Topic':TOPIC}) columns=df.Topic.unique() df1=pd.DataFrame(columns=columns) df1['Date']=df['Date'] df1.set_index('Date',inplace=True) df1=df1.resample('D').ffill() df1
实现方案
直接使用pandas透视表功能即可完成长表转宽表+按日维度聚合的逻辑,无需手动创建空表后逐列匹配。
- 首先将原始小时级的
Date字段归一到自然日粒度,推荐使用dt.normalize()保留datetime类型,方便后续时间序列操作 - 调用
pivot_table完成结构转换,注意如果同一天同一Topic存在多条记录,需要指定对应的聚合规则(求和、取均值、取首尾值均可,按业务需求选择)
可直接运行的参考代码:
import numpy as np import pandas as pd # 构造示例数据 rng = pd.date_range('2015-02-24', periods=50, freq='H') TOPIC = np.random.choice(5, len(rng), replace=True) df = pd.DataFrame({'Date': rng, 'Val': np.random.randn(len(rng)), 'Topic': TOPIC}) # 核心转换逻辑 # 提取自然日维度 df['day'] = df['Date'].dt.normalize() # 透视生成目标结构 df1 = df.pivot_table( index='day', columns='Topic', values='Val', aggfunc='mean' # 聚合规则可按需替换为sum、last、first等 ).resample('D').ffill() # 补全无数据的自然日,不需要可删除该行 df1
说明
- 若业务上同一天同一Topic只会存在一条有效值,可将
aggfunc设置为first,或直接使用df.pivot(index='day', columns='Topic', values='Val')实现,不会触发聚合计算 - 初始代码的问题是仅创建了带列名和索引的空表,没有完成日期、Topic和Val三者的映射匹配,因此所有Topic列最终都会是空值
- 末尾的
resample('D').ffill()作用是补全时间序列中没有任何数据的自然日,用前一个最近有效值填充,不需要连续时间索引可以删除该段逻辑
内容的提问来源于stack exchange,提问作者Khalid
相关产品推荐
相关产品推荐

