Python “这是一种方法吗?”;矢量化用于中等数据集,速度相对较慢

Python “这是一种方法吗?”;矢量化用于中等数据集,速度相对较慢,python,pandas,dataframe,Python,Pandas,Dataframe,我有这个数据框: df = pd.DataFrame({'a' : np.random.randn(9), 'b' : ['foo', 'bar', 'blah'] * 3, 'c' : np.random.randn(9)}) 此功能: def my_test2(row, x): if x == 'foo': blah = 10 if x == 'bar': blah = 20 if

我有这个数据框:

df = pd.DataFrame({'a' : np.random.randn(9),
             'b' : ['foo', 'bar', 'blah'] * 3,
             'c' : np.random.randn(9)})
此功能:

def my_test2(row, x):
    if x == 'foo':
        blah = 10
    if x == 'bar':
        blah = 20
    if x == 'blah':
        blah = 30
    return (row['a'] % row['c']) + blah
然后,我将创建3个新列,如下所示:

df['Value_foo'] = df.apply(my_test2, axis=1, x='foo')
df['Value_bar'] = df.apply(my_test2, axis=1, x='bar')
df['Value_blah'] = df.apply(my_test2, axis=1, x='blah')

它运行正常,但当我将我的_test2变得更复杂,并将df扩展到数千行时,它的运行速度很慢——我听到的上述描述是“矢量化”的吗?我可以轻松地加快速度吗?

正如Andrew、Ami Tavory和Sohier Dane在评论中提到的,您的解决方案中有两个“缓慢”的方面:

  • .apply()
    通常速度较慢,因为它在发动机罩下循环
  • .apply(…,axis=1)
    速度非常慢(即使与
    .apply(…,axis=0)
    相比也是如此)
  • 以下是一种矢量化方法:

    In [74]: d = {
       ....:   'foo': 10,
       ....:   'bar': 20,
       ....:   'blah': 30
       ....: }
    
    In [75]: d
    Out[75]: {'bar': 20, 'blah': 30, 'foo': 10}
    
    In [76]: for k,v in d.items():
       ....:         df['Value_{}'.format(k)] = df.a % df.c + v
       ....:
    
    In [77]: df
    Out[77]:
              a     b         c  Value_bar  Value_blah  Value_foo
    0 -0.747164   foo  0.438713  20.130262   30.130262  10.130262
    1 -0.185182   bar  0.047253  20.003828   30.003828  10.003828
    2  1.622818  blah -0.730215  19.432174   29.432174   9.432174
    3  0.117658   foo  1.530249  20.117658   30.117658  10.117658
    4  2.536363   bar -0.100726  19.917499   29.917499   9.917499
    5  1.128002  blah  0.350663  20.076014   30.076014  10.076014
    6  0.059516   foo  0.638910  20.059516   30.059516  10.059516
    7 -1.184688   bar  0.073781  20.069590   30.069590  10.069590
    8  1.440576  blah -2.231575  19.209001   29.209001   9.209001
    
    针对90K行DF的计时:

    In [80]: big = pd.concat([df] * 10**4, ignore_index=True)
    
    In [81]: big.shape
    Out[81]: (90000, 3)
    
    In [82]: %%timeit
       ....: big['Value_foo'] = big.apply(my_test2, axis=1, x='foo')
       ....: big['Value_bar'] = big.apply(my_test2, axis=1, x='bar')
       ....: big['Value_blah'] = big.apply(my_test2, axis=1, x='blah')
       ....:
    1 loop, best of 3: 10.5 s per loop
    
    In [83]: big = pd.concat([df] * 10**4, ignore_index=True)
    
    In [84]: big.shape
    Out[84]: (90000, 3)
    
    In [85]: %%timeit
       ....: for k,v in d.items():
       ....:     big['Value_{}'.format(k)] = big.a % big.c + v
       ....:
    100 loops, best of 3: 7.24 ms per loop
    

    结论:矢量化方法的速度快1450倍…

    我认为
    df.apply
    只是迭代地应用函数。最好根据
    if
    语句对数据帧进行3次过滤,然后编写函数,使其能够接受
    df
    作为参数,并以非迭代方式更改该参数。要添加到Andrew的注释中,第一行相当于
    df.a%df.c+10
    ,但它的运行时间为1.6秒,而不是2.31毫秒。任何时候使用axis=1时,它都不是完全矢量化的。Axis=1将函数应用于单个行,并且几乎总是比一次应用于整个列的完全矢量化操作慢得多。非常好-感谢您花时间-我将在代码中使用时间,在与完整函数一起使用时也将使用时间