如何高效将行式pandas DataFrame重构为采样后的列式结构?
优化方案:高效重构与重采样Pandas DataFrame
你的原始代码通过嵌套循环和逐次合并实现需求,但针对百万级别的数据量,这种方式效率低下。我们可以利用Pandas的向量化操作(如透视表pivot_table和批量重采样)来大幅提升性能,同时让代码更简洁Pythonic。
核心优化思路
- 透视表转换:将长格式的DataFrame转为宽格式(每个信号作为一列),避免逐列合并的开销。
- 批量重采样:对宽格式DataFrame一次性执行重采样和前向填充,替代循环内的逐列处理。
- 唯一列名处理(可选):如果不同CAN ID下存在同名信号,通过组合CAN ID和信号名生成唯一列名,避免数据覆盖。
优化后的代码
def restructure_data(df_phys, res): import pandas as pd if df_phys.empty: return pd.DataFrame() # 确保时间戳索引是有序的(重采样的前提) df_phys = df_phys.sort_index() # 生成唯一列名(若不同CAN ID下有同名信号,避免列名冲突) df_phys['Signal_Full'] = df_phys['CAN ID'].astype(str) + '_' + df_phys['Signal'] # 转换为宽格式:时间戳为索引,每个Signal_Full为一列,值为Physical Value # aggfunc='last'用于处理同一时间戳下同一信号的多条记录 df_wide = df_phys.pivot_table( index='TimeStamp', columns='Signal_Full', values='Physical Value', aggfunc='last' ) # 按指定频率重采样并前向填充缺失值 df_resampled = df_wide.resample(res).ffill() # 可选:移除所有列均为NaN的行(与原代码dropna()逻辑一致) df_resampled = df_resampled.dropna(how='all') # 若确认所有信号名在CAN ID间唯一,可跳过Signal_Full步骤,直接用Signal作为列名: # df_wide = df_phys.pivot_table(index='TimeStamp', columns='Signal', values='Physical Value', aggfunc='last') return df_resampled
为什么更快?
- 向量化操作:
pivot_table和resample都是Pandas底层优化的C实现,比Python循环快几个数量级。 - 避免重复合并:原代码每次循环都执行
merge_ordered,会产生大量中间DataFrame,而透视表只需一次转换。 - 统一处理逻辑:重采样和填充在宽格式上批量完成,无需逐列单独处理。
关键细节说明
- 排序索引:重采样要求时间戳索引有序,因此先执行
sort_index确保正确性。 - 唯一列名:
Signal_Full解决了不同CAN ID下同名信号的冲突问题,若你的数据中信号名全局唯一,可直接用Signal作为列名。 - aggfunc选择:
last表示同一时间戳下同一信号保留最后一条记录,你可根据需求替换为first或mean等。
内容的提问来源于stack exchange,提问作者mfcss
相关产品推荐
相关产品推荐

