如何使用 cython(或 numpy)加速 pandas
How to speed up pandas with cython (or numpy)
我正在尝试使用 Cython 来加速相对简单的 Pandas DataFrame 计算:遍历 DataFrame 中的每一行,将该行添加到自身以及 DataFrame 中的所有剩余行,求和这些跨越每一行,并产生这些总和的列表。随着 DataFrame 中的行用完,这些系列的长度将减少。这些系列存储为以索引行号为键的字典。
def foo(df):
vals = {i: (df.iloc[i, :] + df.iloc[i:, :]).sum(axis=1).values.tolist()
for i in range(df.shape[0])}
return vals
除了在此函数的顶部添加 %%cython
之外,是否有人建议我如何使用 cdefs
将 DataFrame 值转换为双精度值,然后将此代码 cythonize ?
以下是一些虚拟数据:
>>> df
A B C D E
0 -0.326403 1.173797 1.667856 -1.087655 0.427145
1 -0.797344 0.004362 1.499460 0.427453 -0.184672
2 -1.764609 1.949906 -0.968558 0.407954 0.533869
3 0.944205 0.158495 -1.049090 -0.897253 1.236081
4 -2.086274 0.112697 0.934638 -1.337545 0.248608
5 -0.356551 -1.275442 0.701503 1.073797 -0.008074
6 -1.300254 1.474991 0.206862 -0.859361 0.115754
7 -1.078605 0.157739 0.810672 0.468333 -0.851664
8 0.900971 0.021618 0.173563 -0.562580 -2.087487
9 2.155471 -0.605067 0.091478 0.242371 0.290887
和预期输出:
>>> foo(df)
{0: [3.7094795101205236,
2.8039983729106,
2.013301815968468,
2.24717712931852,
-0.27313665495940964,
1.9899718844711711,
1.4927321304935717,
1.3612155622947018,
0.3008239883773878,
4.029880107986906],
. . .
6: [-0.72401524913338,
-0.8555318173322499,
-1.9159233912495635,
1.813132728359954],
7: [-0.9870483855311194, -2.047439959448434, 1.6816161601610844],
8: [-3.107831533365748, 0.6212245862437702],
9: [4.350280705853288]}
如果你只是想更快地完成它而不是专门使用 cython,我只是用普通的 numpy 来做(大约快 50 倍)。
def numpy_foo(arr):
vals = {i: (arr[i, :] + arr[i:, :]).sum(axis=1).tolist()
for i in range(arr.shape[0])}
return vals
%timeit foo(df)
100 loops, best of 3: 7.2 ms per loop
%timeit numpy_foo(df.values)
10000 loops, best of 3: 144 µs per loop
foo(df) == numpy_foo(df.values)
Out[586]: True
总的来说,pandas相对于numpy给了你很多便利,但是也有开销成本。因此,在 pandas 没有真正添加任何内容的情况下,您通常可以通过在 numpy 中进行操作来加快速度。再举一个例子,看这个 question 我问哪个显示了大致相当的速度差异(大约 23 倍)。
我正在尝试使用 Cython 来加速相对简单的 Pandas DataFrame 计算:遍历 DataFrame 中的每一行,将该行添加到自身以及 DataFrame 中的所有剩余行,求和这些跨越每一行,并产生这些总和的列表。随着 DataFrame 中的行用完,这些系列的长度将减少。这些系列存储为以索引行号为键的字典。
def foo(df):
vals = {i: (df.iloc[i, :] + df.iloc[i:, :]).sum(axis=1).values.tolist()
for i in range(df.shape[0])}
return vals
除了在此函数的顶部添加 %%cython
之外,是否有人建议我如何使用 cdefs
将 DataFrame 值转换为双精度值,然后将此代码 cythonize ?
以下是一些虚拟数据:
>>> df
A B C D E
0 -0.326403 1.173797 1.667856 -1.087655 0.427145
1 -0.797344 0.004362 1.499460 0.427453 -0.184672
2 -1.764609 1.949906 -0.968558 0.407954 0.533869
3 0.944205 0.158495 -1.049090 -0.897253 1.236081
4 -2.086274 0.112697 0.934638 -1.337545 0.248608
5 -0.356551 -1.275442 0.701503 1.073797 -0.008074
6 -1.300254 1.474991 0.206862 -0.859361 0.115754
7 -1.078605 0.157739 0.810672 0.468333 -0.851664
8 0.900971 0.021618 0.173563 -0.562580 -2.087487
9 2.155471 -0.605067 0.091478 0.242371 0.290887
和预期输出:
>>> foo(df)
{0: [3.7094795101205236,
2.8039983729106,
2.013301815968468,
2.24717712931852,
-0.27313665495940964,
1.9899718844711711,
1.4927321304935717,
1.3612155622947018,
0.3008239883773878,
4.029880107986906],
. . .
6: [-0.72401524913338,
-0.8555318173322499,
-1.9159233912495635,
1.813132728359954],
7: [-0.9870483855311194, -2.047439959448434, 1.6816161601610844],
8: [-3.107831533365748, 0.6212245862437702],
9: [4.350280705853288]}
如果你只是想更快地完成它而不是专门使用 cython,我只是用普通的 numpy 来做(大约快 50 倍)。
def numpy_foo(arr):
vals = {i: (arr[i, :] + arr[i:, :]).sum(axis=1).tolist()
for i in range(arr.shape[0])}
return vals
%timeit foo(df)
100 loops, best of 3: 7.2 ms per loop
%timeit numpy_foo(df.values)
10000 loops, best of 3: 144 µs per loop
foo(df) == numpy_foo(df.values)
Out[586]: True
总的来说,pandas相对于numpy给了你很多便利,但是也有开销成本。因此,在 pandas 没有真正添加任何内容的情况下,您通常可以通过在 numpy 中进行操作来加快速度。再举一个例子,看这个 question 我问哪个显示了大致相当的速度差异(大约 23 倍)。