循环中pd.concat与list.append构建Pandas DataFrame:求更优方案
基于Pandas高效构建全局DataFrame的优化方案
问题描述
我采用两种方法基于Pandas构建全局DataFrame,每行数据来自另一DataFrame的筛选结果:通过循环生成计算列,筛选其中最小值对应的行。了解到循环中使用pd.concat会占用较多内存,但测试发现两种方法耗时差异不大,请问是否存在更优实现方案?
原实现代码
import time import pandas as pd technologies = { 'X' :[20000,25000,22000,30000,50000,10000,30000], 'Y':[1000,2300,1200,2000,1000,3000,5000] } df = pd.DataFrame(technologies) start_time = time.time() df1_result=pd.DataFrame() for i in range(df.shape[0]): df1=df.copy() df1['i']=i df1['Y']=df1['Y'].shift(-i) df1['Dist']=df1['X']-df1['Y'] idmin=df1['Dist'].idxmin() result=pd.DataFrame([df1.iloc[idmin,:]]) df1_result=pd.concat(([df1_result, result]), ignore_index=True) print("--- %s seconds ---" % (time.time() - start_time)) start_time = time.time() ListResult2=[] for i in range(df.shape[0]): df2=df.copy() df2['i']=i df2['Y']=df2['Y'].shift(-i) df2['Dist']=df2['X']-df2['Y'] idmin=df2['Dist'].idxmin() ListResult2.append(df2.iloc[idmin,:].values.tolist()) df_result2 = pd.DataFrame (ListResult2)
原代码核心问题
原实现的最大开销在于每次循环都完整复制了原DataFrame,这在数据量较大时会导致内存占用飙升;同时循环内重复执行shift和计算逻辑,没有利用Pandas/Numpy的向量化优势。
优化方案:向量化批量计算
通过预先生成所有需要的移位结果,用Numpy矩阵运算批量计算Dist,一次性找到所有循环对应的最小索引,最后组装结果。这种方式彻底避免了循环内的DataFrame复制,大幅提升效率。
优化后代码
import time import pandas as pd import numpy as np technologies = { 'X' :[20000,25000,22000,30000,50000,10000,30000], 'Y':[1000,2300,1200,2000,1000,3000,5000] } df = pd.DataFrame(technologies) start_time = time.time() n = df.shape[0] Y_vals = df['Y'].values X_vals = df['X'].values # 预先生成所有i对应的Y移位结果矩阵:每一列对应一个i的shift(-i)输出 Y_shifted = np.full((n, n), np.nan) for i in range(n): # 前n-i个位置填充Y[i:],剩余位置保持NaN Y_shifted[:n-i, i] = Y_vals[i:] # 批量计算所有i对应的Dist值:X的每个元素与对应i的Y移位值做差 Dist_matrix = X_vals[:, np.newaxis] - Y_shifted # 找到每个i对应的最小Dist的行索引(自动忽略NaN) min_row_indices = np.nanargmin(Dist_matrix, axis=0) # 组装最终结果 optimized_result = [] for i, row_idx in enumerate(min_row_indices): row_data = df.iloc[row_idx].copy() row_data['i'] = i row_data['Dist'] = Dist_matrix[row_idx, i] optimized_result.append(row_data) df_optimized = pd.DataFrame(optimized_result).reset_index(drop=True) print("--- 优化方案耗时:%s seconds ---" % (time.time() - start_time))
优化效果说明
- 内存效率:不再循环复制原DataFrame,仅生成必要的矩阵数据,内存占用大幅降低
- 计算速度:利用Numpy向量化运算替代循环内的逐行计算,数据量越大,效率提升越明显(比如数据量达到万级时,耗时可能仅为原方法的1/10甚至更低)
- 逻辑清晰:将移位、计算、索引查找拆分为独立步骤,便于维护和扩展
内容的提问来源于stack exchange,提问作者Bantul
相关产品推荐
相关产品推荐

