You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提升SciPy皮尔逊相关系数大量成对计算的速度?

我明白你的问题——处理这么大的数据集时,双重循环逐对计算确实会慢到让人抓狂。咱们来一步步优化这个流程,把运行时间从几十分钟压缩到几分钟甚至更短。

核心问题分析

你的原始代码慢主要卡两个点:

  • 双重循环+逐行append:DataFrame.append每次都会创建新的DataFrame,随着结果集变大,开销会指数级增长;而且逐个调用pearsonr完全没利用numpy向量化运算的优势。
  • 重复列筛选:每次循环都重新筛选_PC和_lncRNAs列,虽然影响不大,但可以提前预处理减少冗余操作。

优化方案1:向量化计算(首选最快方案)

我们可以把两组列分别提取为矩阵,用向量化方式批量计算相关系数和p值,彻底丢掉循环。

import pandas as pd
import numpy as np
from scipy import stats

def correlation_analysis_fast(lncRNA_PC_T):
    # 提前筛选两组列,避免循环中重复计算
    pc_cols = [col for col in lncRNA_PC_T.columns if "_PC" in col]
    lnc_cols = [col for col in lncRNA_PC_T.columns if "_lncRNAs" in col]
    
    # 转成numpy数组,加快后续计算
    X = lncRNA_PC_T[pc_cols].values  # shape: (1222, 列数_PC)
    Y = lncRNA_PC_T[lnc_cols].values  # shape: (1222, 列数_lncRNAs)
    
    n_rows = X.shape[0]
    # 预计算均值和标准差,用于相关系数和p值推导
    X_mean = X.mean(axis=0)
    X_std = X.std(axis=0, ddof=1)
    Y_mean = Y.mean(axis=0)
    Y_std = Y.std(axis=0, ddof=1)
    
    # 批量计算协方差矩阵,再转换为相关系数矩阵
    cov_matrix = np.dot(X.T, Y - Y_mean) / (n_rows - 1)
    corr_matrix = cov_matrix / np.outer(X_std, Y_std)  # shape: (列数_PC, 列数_lncRNAs)
    
    # 基于t分布计算p值(Pearson相关的p值公式)
    t_stat = corr_matrix * np.sqrt((n_rows - 2) / (1 - corr_matrix**2))
    p_matrix = 2 * (1 - stats.t.cdf(np.abs(t_stat), df=n_rows-2))
    
    # 把矩阵结果转换成目标格式的DataFrame
    index = [f"{pc}_{lnc}" for pc in pc_cols for lnc in lnc_cols]
    result = pd.DataFrame({
        "PCC": corr_matrix.flatten(),
        "p-value": p_matrix.flatten()
    }, index=index)
    return result

为什么这个快?

  • 所有计算都是numpy底层的C实现向量化操作,比Python循环快几个数量级。
  • 只做一次列筛选和矩阵运算,没有重复冗余操作。
  • 最后一次性构建DataFrame,彻底避免了逐行append的巨大开销。

优化方案2:并行计算(向量化仍有压力时可选)

如果你的机器有多核心CPU,可以用并行库把列对计算拆分到多个进程中。这里推荐joblib,用法简单:

from joblib import Parallel, delayed
import pandas as pd
from scipy.stats import pearsonr

def correlation_analysis_parallel(lncRNA_PC_T, n_jobs=-1):
    pc_cols = [col for col in lncRNA_PC_T.columns if "_PC" in col]
    lnc_cols = [col for col in lncRNA_PC_T.columns if "_lncRNAs" in col]
    
    # 定义单个列对的计算函数
    def compute_single_pair(pc_col, lnc_col):
        corr, p_val = pearsonr(lncRNA_PC_T[pc_col], lncRNA_PC_T[lnc_col])
        return pd.Series(
            [corr, p_val], 
            index=["PCC", "p-value"], 
            name=f"{pc_col}_{lnc_col}"
        )
    
    # 并行计算所有列对,n_jobs=-1会用满所有CPU核心
    results = Parallel(n_jobs=n_jobs)(
        delayed(compute_single_pair)(pc, lnc) 
        for pc in pc_cols 
        for lnc in lnc_cols
    )
    
    # 合并所有结果
    return pd.concat(results, axis=1).T

注意点

  • 并行计算的开销主要在进程间数据传输,所以适合列对数量极多的场景,但速度还是不如向量化方案。
  • 如果你的数据集已经占满内存,并行可能会导致内存溢出,需要谨慎使用。

额外小优化建议

  1. 提前转numpy数组:不管用哪种方案,先把DataFrame列转成numpy数组,比直接访问DataFrame列更快。
  2. 内存压缩:如果精度足够,可以用dtype=np.float32存储数据,减少内存占用,间接加快计算。
  3. 避免全局变量:把DataFrame作为函数参数传入,减少不必要的内存拷贝。

内容的提问来源于stack exchange,提问作者ARJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 12:12:48