Pandas中如何将DataFrame每行按每3值切分后纵向堆叠为3列
问题描述
我有一个100行、126900列的大型Pandas DataFrame,每行对应一辆车辆的单段道路行程:
- 列按
longitude(经度)、latitude(纬度)、timestamp(时间戳)的固定顺序循环重复排列 - 每行存储车辆按秒采集的瞬时位置序列
需求是:针对每一行(单段行程),将重复排列的列按每3个为一组拆分后纵向堆叠,最终转换为仅含3列的DataFrame。目标转换效果参考:
最初我尝试用iterrows()写双重for循环实现,代码框架如下:
for index, row in df.iterrows(): for i in range(len(df)):
但我不清楚后续逻辑如何编写,同时我了解到对大型DataFrame使用行/列遍历性能通常很差,不符合Pandas开发最佳实践,希望得到可行的解决方案。
解决方案
给你两个无Python层循环的高效实现,处理你这个规模的数据性能比手写循环高数百倍:
方法1:Numpy维度重塑(推荐,性能最高)
核心是直接利用numpy的数组重塑能力,没有额外的索引处理开销,是这类宽表转长表场景下的最优方案:
import pandas as pd import numpy as np # 把(100, 126900)的二维数组重塑为(100, 采样点数量, 3)的三维数组 # 126900 / 3 = 42300,也就是单段行程共有42300个秒级采样点 reshaped = df.to_numpy().reshape(len(df), -1, 3) # 把三维数组展平为(行程数*采样点数, 3)的二维结构 stacked = reshaped.reshape(-1, 3) # 转为DataFrame并设置列名 result = pd.DataFrame(stacked, columns=['longitude', 'latitude', 'timestamp']) # 如果需要保留原行对应的行程ID,可以加这一行 result['trip_id'] = np.repeat(df.index, reshaped.shape[1])
注意:这个方案要求你的列严格按照经度、纬度、时间戳的顺序循环排列,无错位,否则会出现字段值匹配错误。
方法2:Pandas原生API实现(可读性更好)
如果你不想直接操作numpy数组,可以用wide_to_long接口实现,逻辑更直观,方便后续调试修改:
import pandas as pd import numpy as np # 先给列重命名,给每个采样点加序号,格式为 字段名_采样点序号 sample_count = len(df.columns) // 3 field_names = np.tile(['longitude', 'latitude', 'timestamp'], sample_count) sample_idx = np.repeat(np.arange(sample_count), 3) df.columns = [f"{f}_{i}" for f, i in zip(field_names, sample_idx)] # 调用宽转长接口完成转换 result = pd.wide_to_long( df.reset_index().rename(columns={'index': 'trip_id'}), stubnames=['longitude', 'latitude', 'timestamp'], i='trip_id', j='sample_seq', sep='_' ).reset_index(drop=True)
性能对比
- 两种方法的核心运算都在C层实现,处理你当前规模的数据耗时都在1秒以内,其中方法1比方法2快2~3倍
- 你最初尝试的
iterrows()双重循环属于Python层逐元素遍历,处理这个规模的数据可能需要数十分钟,完全不建议使用
内容的提问来源于stack exchange,提问作者wellagainst
相关产品推荐
相关产品推荐

