数字处理2d阵列的最快方法:数据帧vs系列vs阵列vs numba

时间:2014-09-18 14:32:07

标签: python numpy pandas numba

编辑添加:我认为numba基准测试不公平,下面的说明

我正在尝试针对以下用例对数据处理数据的不同方法进行基准测试:

  1. 相当大的数据集(100,000多条记录)
  2. 100多行相当简单的代码(z = x + y)
  3. 不需要排序或索引
  4. 换句话说,不需要系列和数据帧的完整通用性,虽然它们包含在这里b / c它们仍然是封装数据的便捷方式,并且通常需要预处理或后处理才需要通用性大熊猫在numpy数组上。

    问题:基于此用例,以下基准是否合适,如果没有,我该如何改进?

    # importing pandas, numpy, Series, DataFrame in standard way
    from numba import jit
    nobs = 10000
    nlines = 100
    
    def proc_df():
       df = DataFrame({ 'x': np.random.randn(nobs),
                        'y': np.random.randn(nobs) })
       for i in range(nlines):
          df['z'] = df.x + df.y
       return df.z
    
    def proc_ser():
       x = Series(np.random.randn(nobs))
       y = Series(np.random.randn(nobs))
       for i in range(nlines):
          z = x + y
       return z
    
    def proc_arr():
       x = np.random.randn(nobs)
       y = np.random.randn(nobs)
       for i in range(nlines):
          z = x + y
       return z
    
    @jit
    def proc_numba():
       xx = np.random.randn(nobs)
       yy = np.random.randn(nobs)
       zz = np.zeros(nobs)
       for j in range(nobs):
          x, y = xx[j], yy[j]
          for i in range(nlines):
             z = x + y
          zz[j] = z
       return zz
    

    结果(Win 7,3岁的Xeon工作站(四核)。标准和最近的anaconda分布或非常接近。)

    In [1251]: %timeit proc_df()
    10 loops, best of 3: 46.6 ms per loop
    
    In [1252]: %timeit proc_ser()
    100 loops, best of 3: 15.8 ms per loop
    
    In [1253]: %timeit proc_arr()
    100 loops, best of 3: 2.02 ms per loop
    
    In [1254]: %timeit proc_numba()
    1000 loops, best of 3: 1.04 ms per loop   # may not be valid result (see note below)
    

    编辑添加(对jeff的响应)将df / series / array传递给函数而不是在函数内部创建它们的替代结果(即将包含'randn'的代码行从内部函数移动到外部功能):

    10 loops, best of 3: 45.1 ms per loop
    100 loops, best of 3: 15.1 ms per loop
    1000 loops, best of 3: 1.07 ms per loop
    100000 loops, best of 3: 17.9 µs per loop   # may not be valid result (see note below)
    

    关于numba结果的注意事项:我认为numba编译器必须在for循环上进行优化并将for循环减少到单个迭代。我不知道,但这是我能说出来的唯一解释,因为它不能比numpy快50倍,对吧?跟进问题:Why is numba faster than numpy here?

2 个答案:

答案 0 :(得分:4)

嗯,你真的没有在这里做同样的事情(或者更确切地说,你正在考虑不同的方面)。

E.g。

In [6]:    x = Series(np.random.randn(nobs))

In [7]:    y = Series(np.random.randn(nobs))

In [8]:  %timeit x + y
10000 loops, best of 3: 131 µs per loop

In [9]:  %timeit Series(np.random.randn(nobs)) + Series(np.random.randn(nobs))
1000 loops, best of 3: 1.33 ms per loop

[8]实际操作,而[9]包括系列创建(和随机数生成)的开销加上实际操作

另一个例子是proc_ser vs proc_dfproc_df包括在DataFrame中分配特定列的开销(实际上对于初始创建和后续重新分配是不同的)。

所以创建结构(你也可以计时,但这是一个单独的问题)。执行完全相同的操作并计时。

此外,您说您不需要对齐。 Pandas默认情况下会给你这个(并没有很简单的方法来关闭它,虽然它只是一个简单的检查,如果它们已经对齐)。在numba中你需要手动'对齐它们。

答案 1 :(得分:1)

跟进@Jeff的回答。代码可以进一步优化。

nobs = 10000
x = pd.Series(np.random.randn(nobs))
y = pd.Series(np.random.randn(nobs))

%timeit proc_ser()
%timeit x + y
%timeit x.values + y.values

100 loops, best of 3: 11.8 ms per loop
10000 loops, best of 3: 107 µs per loop
100000 loops, best of 3: 12.3 µs per loop