pandas corr 和 corrwith 非常慢

TMa*_*rks 5 python dataframe pandas

我有一个 <30K 行和 7 列的 Pandas 数据框,我正在尝试获得 4 列与第五列的相关性。问题是,我想用大量数据集来做这件事,但这需要大约 40 秒才能运行。这是我的代码:

df_a = dfr[['id', 'state', 'perform', 'A']].groupby(['id', 'state']).corr().ix[1::2][['A']].reset_index(2).drop('level_2', axis=1)
df_b = dfr[['id', 'state', 'perform', 'B']].groupby(['id', 'state']).corr().ix[1::2][['B']].reset_index(2).drop('level_2', axis=1)
df_c = dfr[['id', 'state', 'perform', 'C']].groupby(['id', 'state']).corr().ix[1::2][['C']].reset_index(2).drop('level_2', axis=1)
df_d = dfr[['id', 'state', 'perform', 'D']].groupby(['id', 'state']).corr().ix[1::2][['D']].reset_index(2).drop('level_2', axis=1)

df = df_a.merge(df_b, left_index=True, right_index=True)
df = df.merge(df_c, left_index=True, right_index=True)
df = df.merge(df_d, left_index=True, right_index=True)
Run Code Online (Sandbox Code Playgroud)

示例数据如下所示:

ID   State   perform   A   B   C   D
234   AK     75.8456   1   0   0   0
284   MN     78.6752   0   0   1   0
Run Code Online (Sandbox Code Playgroud)

有没有人有任何关于如何加快速度或更好地实施此方法的提示?

谢谢!

Ma *_*ing 7

pandas corr很慢的原因是它考虑了 NAN:它基本上是一个 cython for 循环。

如果您的数据没有 NAN,则 numpy.corrcoef 会快得多


JBB*_*JBB 6

我想在这里赞同妈妈的回答......

numpy 相对于 pandas 来说速度快得令人难以置信。我正在做一些测试,看看到底快了多少......速度大幅提升

import timeit
import numpy as np
import pandas as pd


holdings_array = np.arange(40, 100, 20)
dates_array = [200, 800]

calc = pd.DataFrame(
    index=pd.MultiIndex.from_product(
        [['Correlation', 'Returns'], ['pandas', 'numpy', 'pandas.values'], dates_array],
        names=['Method', 'Library', 'Shape']),
    columns=holdings_array
).unstack(level=-1)

print("Checking pandas vs numpy... (ms)")

# PANDAS
for num_holdings in holdings_array:
    for num_dates in dates_array:
        df = pd.DataFrame(np.random.random(size=[num_dates, num_holdings]))
        ls = np.random.random(size=num_holdings)
        calc.loc[('Correlation', 'pandas'), (num_holdings, num_dates)] \
            = str(np.round(timeit.timeit('df.corr()', number=100, globals=globals()) * 10, 3))
        calc.loc[('Returns', 'pandas'), (num_holdings, num_dates)] \
            = str(np.round(timeit.timeit('(df*ls).sum(axis=1)', number=100, globals=globals()) * 10, 3))


# # NUMPY
# for x, num_holdings in enumerate(holdings_array):
#     for y, num_dates in enumerate(dates_array):
#         df = np.array(np.random.random(size=[num_dates, num_holdings]))
#         ls = np.random.random(size=num_holdings)
#         calc.loc[('Correlation', 'numpy'), (num_holdings, num_dates)] \
#             = str(np.round(timeit.timeit('np.corrcoef(df)', number=100, globals=globals()) * 10, 3))
#         calc.loc[('Returns', 'numpy'), (num_holdings, num_dates)] \
#             = str(np.round(timeit.timeit('(df*ls).sum(axis=1)', number=100, globals=globals()) * 10, 3))

# PANDAS.VALUES WITH NP FUNCTIONS
for num_holdings in holdings_array:
    for num_dates in dates_array:
        df = pd.DataFrame(np.random.random(size=[num_dates, num_holdings]))
        ls = np.random.random(size=num_holdings)
        calc.loc[('Correlation', 'pandas.values'), (num_holdings, num_dates)] \
            = str(np.round(timeit.timeit('np.corrcoef(df.values, rowvar=False)', number=100, globals=globals()) * 10, 3))
        calc.loc[('Returns', 'pandas.values'), (num_holdings, num_dates)] \
            = str(np.round(timeit.timeit('(df.values*ls).sum(axis=1)', number=100, globals=globals()) * 10, 3))

print(f"Results: \n{calc.to_string()}")
Run Code Online (Sandbox Code Playgroud)

只要有可能,如果在 pandas df 上进行向量计算,请将其更改为 df.values 并运行 np 操作

例如,我可以将 df.corr() 更改为 np.corrcoef(df.values, rowvar=False) (注意:rowvar=False 很重要,因此形状正确),对于大型操作,您将看到 10 倍、100 倍的速度。不是微不足道的。

在此输入图像描述


TMa*_*rks 1

虽然可能不是最好的解决方案,但这对我来说很有效,并且与之前的 52 秒相比,总共运行时间减少到了 4.8 秒。

我最终在 pandas 中进行分组,然后使用 numpy 运行相关性。

groups = df.groupby(['course_id', 'activity_id'])
np_arr = []

for (cor_id,act_id), group in groups:

    np_arr.append([cor_id, act_id,
                   np.corrcoef(group.A.as_matrix(), group.perform.as_matrix())[0,1],
                   np.corrcoef(group.B.as_matrix(), group.perform.as_matrix())[0,1],
                   np.corrcoef(group.C.as_matrix(), group.perform.as_matrix())[0,1],
                   np.corrcoef(group.D.as_matrix(), group.perform.as_matrix())[0,1]])

df = pd.DataFrame(data=np.array(np_arr), columns=['course_id', 'activity_id', 'A', 'B', 'C', 'D'])
Run Code Online (Sandbox Code Playgroud)

这有效地减少了我的运行时间,我将使用 cython 输入变量以进一步提高速度。