【问题标题】:How would you tackle computing a correlation of two columns within a 1-million column CSV?您将如何处理计算 100 万列 CSV 中两列的相关性?
【发布时间】:2021-09-20 05:30:24
【问题描述】:

场景:

  • 我有一个第一列“年龄”的 CSV,还有一百万 其他列。我想找到最多的列 与年龄相关。
  • 行数很少,比如说不到 1000 行。
  • 这是用 Python 编写的更大解决方案的一部分,但不一定是 Python。
  • 和大多数事情一样,我想平衡代码可读性和性能
  • 在下面的示例中,为简单起见,我只查看一列。真正的解决方案可能会使用所有列的多处理。

我有下面的代码可以运行,但可以理解的是,将 CSV 存储为非常(非常!)宽的 Pandas 数据框会很慢。

如果是你,你会怎么做?

命令行:python mycode.py myfile.csv columnname-to-measure

import pandas as pd
from scipy import stats   
import os,sys

if __name__=="__main__":
    
    _DATAFILE = sys.argv[1]

    ##Sample tiny datafile
    
    #Age,m1,m2,m3
    #35,0.00234,0.1,1
    #30,0.0034,0.2,2
    #40,0.0013,0.3,4

    _MEASURE=sys.argv[2]

    print("Parsing file %s" %(_DATAFILE))
    
    df = pd.read_csv(_DATAFILE)
    print(f"Corellating {_MEASURE} with Age")
    all =df[['Age',_MEASURE]].copy()
    allna=all[all[_MEASURE].notna()]
    pearson_coef, p_value = stats.pearsonr( allna['Age'].values,allna[_MEASURE].values)
    print(pearson_coef,p_value)
   

【问题讨论】:

    标签: python pandas csv bigdata pearson-correlation


    【解决方案1】:
    1. 最好一次读取所有列并计算所有相关性,这样可以避免多次读取文件。或者,使用 parquet 等列式存储来存储文件,这样您就只能读取所需的列。查看 pandas.read_parquet 和 df.to_parquet。

    2. 使用 pandas 内置的关联方法往往更快(底层 numpy 实现)。 https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.corr.html

    3. 我不认为多处理会加快速度,因为您的瓶颈是 csv IO 时间,而不是相关计算时间。要么一次性读取文件,要么使用镶木地板或其他方式。

    【讨论】:

    • 非常感谢这位 Leo,我没有尝试过镶木地板,但我会的。
    【解决方案2】:

    对于您的用例来说,使用 pandas.DataFrame.corr 是否太慢?它会计算一堆不必要的相关性,但我会从那里开始。如果速度太慢,可以试试numpy.corrcoef。我将这两个与您的示例数据进行了比较:

    data = [[35,0.00234,0.1,1],
            [30,0.0034,0.2,2],
            [40,0.0013,0.3,4]]
    
    df = pd.DataFrame(data, columns=['Age', 'm1', 'm2', 'm3'])
    np_data = df.to_numpy()
    

    在 Jupyter Lab 环境中使用 %timeit 魔术函数计时:

    %timeit df.corr()
    

    产生216 µs ± 24.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)。尝试numpy 路由:

    %timeit np.corrcoef(np_data, rowvar=False)
    

    产生88 µs ± 1.4 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)。所以np.corrcoef会快一点。

    为了与scipy.stats.pearsonr 进行比较,我将列迭代策略封装在一个函数中以对其进行计时:

    def orig(df):
        for col in df.columns:
            pearson_coef, p_value = stats.pearsonr(df['Age'], df[col])
    

    如果我们计时:

    %timeit orig(df)
    

    我们得到450 µs ± 46.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each),因此pandas.DataFrame.corrnumpy.corrcoef 都更快,尽管必须计算不必要的相关性。

    【讨论】:

    • 嗯。使用具有这么多相关性的 pandas.DataFrame.corr 需要 5.2 TiB 的内存。 MemoryError: Unable to allocate 5.22 TiB for an array with shape (847081, 847081) and data type float64
    • 啊,该死。我想知道混合方法是否可行,其中采用一些(可配置,取决于内存)列数的块,并在每个块上使用 pandas.DataFrame.corrnumpy.corrcoef 计算与年龄的相关性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-04
    • 2017-02-12
    • 2011-11-18
    • 1970-01-01
    • 2011-10-14
    • 2014-11-07
    • 2021-07-04
    相关资源
    最近更新 更多