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

Python 数字处理2d阵列的最快方法:数据帧vs系列vs阵列vs numba,python,numpy,pandas,numba,Python,Numpy,Pandas,Numba,编辑添加:我不认为numba基准是公平的,注意如下 我正试图为以下用例测试不同的数值处理数据的方法: 相当大的数据集(100000多条记录) 100多行相当简单的代码(z=x+y) 不需要排序或索引 换句话说,系列和数据帧的完整通用性是不需要的,尽管它们包含在这里b/c它们仍然是封装数据的方便方法,并且通常存在预处理或后处理,这确实需要pandas over numpy阵列的通用性 问题:基于此用例,以下基准是否合适?如果不合适,我如何改进它们 # importing pandas, numpy

编辑添加:我不认为numba基准是公平的,注意如下

我正试图为以下用例测试不同的数值处理数据的方法:

  • 相当大的数据集(100000多条记录)
  • 100多行相当简单的代码(z=x+y)
  • 不需要排序或索引
  • 换句话说,系列和数据帧的完整通用性是不需要的,尽管它们包含在这里b/c它们仍然是封装数据的方便方法,并且通常存在预处理或后处理,这确实需要pandas over 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分布或非常接近。)

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


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

    好吧,你在这里并不是在为同样的事情计时(或者更确切地说,你是在为不同的方面计时)

    例如

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

    另一个例子是
    proc\u ser
    vs
    proc\u df
    proc_df
    包括数据帧中特定列的分配开销(对于初始创建和后续重新分配,这实际上是不同的)

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


    进一步说,你不需要对齐。Pandas默认为您提供此功能(并且没有真正简单的方法关闭它,尽管它只是简单地检查它们是否已对齐)。在numba中,您需要“手动”对齐它们。

    继续@Jeff answer。代码可以进一步优化

    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
    

    好的,我不认为它改变了什么(数据创建是有意的,只是这里测量的一小部分),但上面添加了替代结果。Re numba manual alignment(手动对齐):虽然我不认为它与numpy在本例中有任何不同(因为我只是在numba中迭代numpy数组),但这个用例非常简单,我不认为这是一个问题。Jeff,如果你错过了,这是以下内容的后续内容:
    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)
    
    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
    
    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