Pandas遍历DataFrame行效率低下问题排查及行间差平方和快速计算方法咨询
问题分析与优化方案
你的Pandas实现速度慢的核心原因是嵌套循环中逐行使用iloc提取数据——这完全违背了Pandas和numpy的设计初衷,它们的优势在于向量化批量操作,而不是逐行循环处理。每次iloc[i][2:-2].values都会触发一次数据切片、转换的开销,在11万+次迭代(480*479/2=114960)下,这些开销会被放大,导致速度骤降。
一、修正思路:用向量化操作替代逐行循环
我们可以直接提取需要计算的列,然后利用numpy的广播机制或者现成的工具函数,一次性计算所有行对的差的平方和,完全避免循环。
二、具体实现方案
方案1:使用sklearn的pairwise_distances(最简洁)
差的平方和本质就是平方欧氏距离,sklearn提供了专门的函数来计算所有行对的距离,速度极快:
import pandas as pd from sklearn.metrics.pairwise import pairwise_distances # 读取数据 df = pd.read_csv(filename, delim_whitespace=True) # 提取需要计算的列:第2列到倒数第3列(对应原代码的[2:-2]) target_data = df.iloc[:, 2:-2].values # 计算所有行对的平方欧氏距离,结果是n×n的对称矩阵 sq_dist_matrix = pairwise_distances(target_data, metric='sqeuclidean')
得到的sq_dist_matrix中,sq_dist_matrix[i][j]就对应原代码中np.sum((row_i - row_j)**2)的结果。如果你只需要i<j的行对结果,可以提取矩阵的上三角部分:
# 获取上三角索引(i < j) i_indices, j_indices = np.triu_indices_from(sq_dist_matrix, k=1) # 提取所有i<j的平方和结果 sq_dist_results = sq_dist_matrix[i_indices, j_indices]
方案2:纯numpy手动实现(无需额外依赖)
如果不想引入sklearn,可以用numpy的广播机制直接计算:
import pandas as pd import numpy as np df = pd.read_csv(filename, delim_whitespace=True) target_data = df.iloc[:, 2:-2].values # 利用广播计算所有行对的差:shape为(n, n, d),n是行数,d是特征数 diff = target_data[:, np.newaxis, :] - target_data[np.newaxis, :, :] # 计算平方后求和,得到n×n的平方和矩阵 sq_dist_matrix = np.sum(diff ** 2, axis=2) # 同样提取i<j的结果 i_indices, j_indices = np.triu_indices_from(sq_dist_matrix, k=1) sq_dist_results = sq_dist_matrix[i_indices, j_indices]
三、为什么这个方法更快?
- 向量化操作是在numpy的底层C代码中执行的,避免了Python循环的解释器开销;
- 一次性处理所有数据,减少了多次切片、转换的额外开销;
- 无论是sklearn还是numpy的实现,都做了大量的性能优化,比如内存复用、并行计算(部分场景)。
用这种方法处理480行数据,耗时应该会降到毫秒级,和csv库的实现速度相当甚至更快。
验证结果正确性
你可以随机选几组i,j,对比两种方法的结果:
# 原代码的计算方式 row_i = df.iloc[i][2:-2].values row_j = df.iloc[j][2:-2].values original_result = np.sum((row_i - row_j)**2) # 新方法的结果 new_result = sq_dist_matrix[i][j] print(np.isclose(original_result, new_result)) # 应该输出True
内容的提问来源于stack exchange,提问作者Flavio Moraes
相关产品推荐
相关产品推荐

