1

PandasでSQLのselect-statementのような動作を複製することについてのこの質問を見た後、私はこの回答を追加して、その質問に対する受け入れられた回答で与えられた冗長な構文を短縮できる2つの方法を示しました。

それらをいじってみた後、私の2つの短い構文の方法は大幅に遅くなり、誰かがその理由を説明できることを望んでいます。

以下で使用される関数は、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

reduce、関数のユーザーoperator、および関数からの関数オーバーヘッドだけで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行ごとにラムダを呼び出しています。行ごとにPythonメソッド呼び出しを実行する必要があるため、これにはかなりのオーバーヘッドがあります。

あなたが書くときdf[(df[1]==3) & (df[2]==2) & (df[4]==5)]、オーバーヘッドはありません。代わりに、操作は1回の操作で各列に適用され、ループはベクトル化の可能性があるネイティブコード(SSEなど)で実行されます。

これはパンダだけのものではありません。一般に、個々のアイテムでPython関数や内部ループを呼び出す代わりに、配列と行列を集約して処理すると、numpy操作ははるかに高速になります。

于 2012-11-19T16:01:45.937 に答える