为什么 Pandas 的速度如此之快?如何定义这样的函数?

Joh*_*Dev 6 python python-2.7 python-3.x pandas jupyter-notebook

  • 我尝试比较Pandas传统循环的性能。我意识到,在输入和输出相同的情况下,与传统循环相比,Pandas 执行的计算速度非常快

我的代码:

#df_1h has been imported before

import time

n = 14
pd.options.display.max_columns = 8
display("df_1h's Shape {} rows x {} columns".format(df_1h.shape[0], df_1h.shape[1]))

close = df_1h['close']

start = time.time()
df_1h['sma_14_pandas'] = close.rolling(14).mean()
end = time.time()
display('pandas: {}'.format(end - start))

start = time.time()
df_1h['sma_14_loop'] = np.nan
for i in range(n-1, df_1h.shape[0]):
    df_1h['sma_14_loop'][i] = close[i-n+1:i+1].mean()
end = time.time()
display('loop: {}'.format(end - start))

display(df_1h.tail())
Run Code Online (Sandbox Code Playgroud)

输出:

"df_1h's Shape 16598 rows x 15 columns"
'pandas: 0.0030088424682617188'
'loop: 7.2529966831207275'
        open_time       open        high        low         ... ignore  rsi_14  sma_14_pandas   sma_14_loop
16593   1.562980e+12    11707.39    11739.90    11606.04    ... 0.0 51.813151   11646.625714    11646.625714
16594   1.562983e+12    11664.32    11712.61    11625.00    ... 0.0 49.952679   11646.834286    11646.834286
16595   1.562987e+12    11632.64    11686.47    11510.00    ... 0.0 47.583619   11643.321429    11643.321429
16596   1.562990e+12    11582.06    11624.04    11500.00    ... 0.0 48.725262   11644.912857    11644.912857
16597   1.562994e+12    11604.96    11660.00    11588.16    ... 0.0 50.797087   11656.723571    11656.723571
5 rows × 15 columns
Run Code Online (Sandbox Code Playgroud)
  • Pandas 几乎快2.5k 倍!!!

我的问题:

  • 我的代码错了吗?
  • 如果我的代码是正确的,为什么 Pandas 这么快?
  • 如何为 Pandas定义运行速度如此之快的自定义函数

Ste*_*tef 16

关于你的三个问题:

  1. 您的代码在产生正确结果的意义上是正确的。显式迭代数据帧的行通常是一种规则,但在性能方面并不是一个好主意。大多数情况下,pandas 方法可以更有效地实现相同的结果(如您所证明的那样)。
  2. Pandas 之所以如此之快,是因为它在底层使用了 numpy。Numpy 实现了高效的数组操作。此外,pandas 的最初创造者 Wes McKinney 对效率和速度非常着迷。
  3. 使用 numpy 或其他优化的库。我建议阅读熊猫文档的增强性能部分。如果您不能使用内置的 Pandas 方法,如果检索数据框或系列的 numpy 表示通常有意义(使用value属性或to_numpy()方法),请对 numpy 数组进行所有计算,然后才将结果存储回数据框或系列。

为什么循环算法这么慢?

在您的循环算法中,mean计算超过 16500 次,每次将 14 个元素相加以求平均值。Pandas 的rolling方法使用了更复杂的方法,大大减少了算术运算的次数。

如果您在 numpy 中进行计算,您可以获得与 Pandas 类似(实际上大约好 3 倍)的性能。以下示例说明了这一点:

import pandas as pd
import numpy as np
import time

data = np.random.uniform(10000,15000,16598)
df_1h = pd.DataFrame(data, columns=['Close'])
close = df_1h['Close']
n = 14
print("df_1h's Shape {} rows x {} columns".format(df_1h.shape[0], df_1h.shape[1]))

start = time.time()
df_1h['SMA_14_pandas'] = close.rolling(14).mean()
print('pandas: {}'.format(time.time() - start))

start = time.time()
df_1h['SMA_14_loop'] = np.nan
for i in range(n-1, df_1h.shape[0]):
    df_1h['SMA_14_loop'][i] = close[i-n+1:i+1].mean()
print('loop:   {}'.format(time.time() - start))

def np_sma(a, n=14) :
    ret = np.cumsum(a)
    ret[n:] = ret[n:] - ret[:-n]
    return np.append([np.nan]*(n-1), ret[n-1:] / n)

start = time.time()
df_1h['SMA_14_np'] = np_sma(close.values)
print('np:     {}'.format(time.time() - start))

assert np.allclose(df_1h.SMA_14_loop.values, df_1h.SMA_14_pandas.values, equal_nan=True)
assert np.allclose(df_1h.SMA_14_loop.values, df_1h.SMA_14_np.values, equal_nan=True)
Run Code Online (Sandbox Code Playgroud)

输出:

df_1h's Shape 16598 rows x 1 columns
pandas: 0.0031278133392333984
loop:   7.605962753295898
np:     0.0010571479797363281
Run Code Online (Sandbox Code Playgroud)