如何高效对DataFrame列对应用自定义函数(替代循环)
高效计算特征两两自定义函数的方阵(替代嵌套循环)
针对你9000列DataFrame两两列应用自定义单值函数的需求,Python嵌套循环因解释器 overhead 效率极低,这里提供几种大幅提速的方案:
1. 利用Scipy的pdist+squareform(优先推荐)
Scipy的pdist底层基于C实现,专门用于成对样本的相似性/距离计算,效率远高于Python循环。只需将自定义函数适配成pdist要求的格式即可:
import numpy as np from scipy.spatial.distance import pdist, squareform # 适配pdist的自定义度量函数,接收两个一维数组返回单值 def custom_metric(x, y): return pcorr(x, y) # pcorr为你的自定义函数 # 将DataFrame转置,让每列成为pdist处理的行向量 arr = df.values.T # 计算所有两两列的函数值(仅计算下三角,避免重复) pairwise_results = pdist(arr, metric=custom_metric) # 转换为对称方阵 corrm = squareform(pairwise_results) # 填充对角线(根据需求设置,比如偏相关系数对角线设为1) np.fill_diagonal(corrm, 1.0)
2. 用Numba加速自定义函数
如果你的pcorr内部包含循环,用Numba将其编译为机器码,可直接让循环效率提升几十倍:
from numba import jit import numpy as np # 用numba装饰自定义函数,nopython=True表示完全编译为机器码 @jit(nopython=True) def pcorr(x, y): # 这里写入你的偏相关系数计算逻辑,示例如下(按需修改) mean_x = np.mean(x) mean_y = np.mean(y) cov_xy = np.mean((x - mean_x)*(y - mean_y)) var_x = np.var(x) var_y = np.var(y) return cov_xy / np.sqrt(var_x * var_y) # 优化后的循环计算 K = len(df.columns) corrm = np.empty((K, K), dtype=float) np.fill_diagonal(corrm, 1.0) for i in range(K): for j in range(i+1, K): x = df.values[:,i] y = df.values[:,j] corrm[i][j] = pcorr(x,y) corrm[j][i] = corrm[i][j] # 对称填充,节省重复计算
3. 并行计算拆分任务
若上述方法不适用,可通过多进程并行处理列对,充分利用CPU多核资源:
import numpy as np from joblib import Parallel, delayed arr = df.values K = arr.shape[1] corrm = np.eye(K) # 初始化对角线为1 # 生成所有需计算的i<j列对 column_pairs = [(i, j) for i in range(K) for j in range(i+1, K)] def compute_pair(i, j): x = arr[:, i] y = arr[:, j] return (i, j, pcorr(x, y)) # 并行计算,n_jobs=-1使用所有CPU核心,verbose显示进度 results = Parallel(n_jobs=-1, verbose=10)( delayed(compute_pair)(i, j) for i, j in column_pairs ) # 填充结果到矩阵 for i, j, val in results: corrm[i][j] = val corrm[j][i] = val # 函数对称时填充对称位置
关键优化点
- 避免重复计算:仅计算i<j的列对,再对称填充(适用于对称函数如相关系数、偏相关系数),直接减少一半计算量。
- 减少数据拷贝:优先使用numpy数组而非DataFrame列索引访问,降低IO开销。
内容的提问来源于stack exchange,提问作者Yasir
相关产品推荐
相关产品推荐

