如何优化Python For Loop以提升20万行表格处理速度?
嘿,我明白处理20万行表格的循环跑22小时有多闹心——咱们来聊聊怎么给这段代码提速,毕竟没人愿意耗这么久在等程序跑完对吧?
首先得说,Python原生的for循环逐行处理大数据量本来就效率很低,尤其是如果你的代码里还在循环里用iloc[i]这类逐行修改DataFrame的操作,那开销更是大到离谱。下面给你几个实用的优化方向,按优先级排序:
优先用Pandas向量化操作替代逐行循环
这是最立竿见影的提速手段,Pandas底层是用C实现的,向量化操作能把循环的开销降到几乎为零。比如如果你的填充规则是基于现有两列的计算,直接对整列做运算就行,完全不用写循环。
举个例子,原来的循环代码可能是这样:for i in range(len(rolling)): rolling['yellow_col1'][i] = rolling['green_col1'][i] * 2 + rolling['green_col2'][i]改成向量化操作后:
rolling['yellow_col1'] = rolling['green_col1'] * 2 + rolling['green_col2']这种修改能把运行时间从小时级直接压缩到分钟甚至秒级。
如果必须用循环,别用
iterrows(),改用itertuples()
要是你的填充逻辑没法完全向量化(比如有复杂的条件判断),那也别用iterrows()遍历行——它每次返回一个Series对象,开销极大。换成itertuples()会快很多,它返回的是轻量的元组。另外,别在循环里逐行修改DataFrame,先把结果存在列表里,最后一次性赋值:result_list = [] for row in rolling.itertuples(): # 用row.green_col1、row.green_col2直接获取值 if row.green_col1 > 100: calc_val = row.green_col1 + row.green_col2 else: calc_val = row.green_col1 * row.green_col2 result_list.append(calc_val) rolling['yellow_col1'] = result_list用NumPy数组处理复杂计算
要是逻辑再复杂点,Pandas的向量化搞不定,可以把列转成NumPy数组来运算——NumPy的向量化同样比Python循环快得多:green1_np = rolling['green_col1'].to_numpy() green2_np = rolling['green_col2'].to_numpy() # 用NumPy的条件判断替代Python循环里的if-else yellow_col1 = np.where(green1_np > 100, green1_np + green2_np, green1_np * green2_np) rolling['yellow_col1'] = yellow_col1极端复杂逻辑?试试Numba编译循环
如果你的填充逻辑真的没办法向量化(比如依赖前一行的计算结果),那可以用Numba给循环加个装饰器,把Python代码编译成机器码,速度能接近C语言:from numba import jit import numpy as np @jit(nopython=True) def fill_complex_values(green1, green2): result = np.empty(len(green1)) # 比如依赖前一行的结果 result[0] = green1[0] + green2[0] for i in range(1, len(green1)): result[i] = result[i-1] * 0.5 + green1[i] * green2[i] return result rolling['yellow_col1'] = fill_complex_values(rolling['green_col1'].to_numpy(), rolling['green_col2'].to_numpy())最后检查内存使用
如果表格太大导致内存不足,系统会频繁用磁盘交换数据,这也会拖慢速度。可以把数据类型改成更紧凑的,比如把int64改成int32(如果数值范围允许),float64改成float32:rolling['green_col1'] = rolling['green_col1'].astype('int32') rolling['green_col2'] = rolling['green_col2'].astype('float32')
建议你先从向量化操作开始试,绝大多数情况下,这个方法就能解决你的速度问题。要是逻辑复杂,再往下试后面的方案。
内容的提问来源于stack exchange,提问作者Tarek Khedr




