1

在看到这个关于在 Pandas 中复制 SQL select-statement-like 行为的问题后,我添加了这个答案,显示了两种可以缩短该问题已接受答案中给出的冗长语法的方法。

在玩过它们之后,我的两种较短的语法方法明显变慢了,我希望有人能解释为什么

您可以假设下面使用的任何函数都来自 Pandas、IPython,或者来自上面链接的问答

import pandas
import numpy as np
N = 100000
df = pandas.DataFrame(np.round(np.random.rand(N,5)*10))

def pandas_select(dataframe, select_dict):
    inds = dataframe.apply(lambda x: reduce(lambda v1,v2: v1 and v2,
                           [elem[0](x[key], elem[1])
                           for key,elem in select_dict.iteritems()]), axis=1)
    return dataframe[inds]



%timeit _ = df[(df[1]==3) & (df[2]==2) & (df[4]==5)]
%timeit _ = df[df.apply(lambda x: (x[1]==3) & (x[2]==2) & (x[4]==5), axis=1)]

import operator
select_dict = {1:(operator.eq,3), 2:(operator.eq,2), 4:(operator.eq,5)}
%timeit _ = pandas_select(df, select_dict)

我得到的输出是:

In [6]: %timeit _ = df[(df[1]==3) & (df[2]==2) & (df[4]==5)]
100 loops, best of 3: 4.91 ms per loop

In [7]: %timeit _ = df[df.apply(lambda x: (x[1]==3) & (x[2]==2) & (x[4]==5), axis=1)]
1 loops, best of 3: 1.23 s per loop

In [10]: %timeit _ = pandas_select(df, select_dict)
1 loops, best of 3: 1.6 s per loop

我可以购买 , 函数的用户reduceoperator以及我的函数的函数开销pandas_select可能会减慢它。但这似乎太过分了。在我的函数内部,我使用相同的语法,df[key] logical_op value,但它要慢得多。

我也很困惑为什么这个apply版本axis=1要慢得多。从字面上看,它应该只是语法的缩写,不是吗?

4

1 回答 1

5

当您编写时df[df.apply(lambda x: (x[1]==3) & (x[2]==2) & (x[4]==5), axis=1)],您正在为数据框中的 100000 行中的每一行调用您的 lambda。这会产生大量开销,因为必须为每一行执行 Python 方法调用。

当您编写df[(df[1]==3) & (df[2]==2) & (df[4]==5)]时,没有开销;相反,该操作在单个操作中应用于每一列,并且循环在具有矢量化潜力的本机代码中执行(例如 SSE)。

这不是 Pandas 独有的。一般来说,如果您将数组和矩阵作为整体处理,而不是在单个项目上调用 Python 函数或内部循环,那么任何 numpy 操作都会快得多。

于 2012-11-19T16:01:45.937 回答