207

ユーザーがいくつかのフィルターを Pandas DataFrame または Series オブジェクトに適用したいというシナリオがあります。基本的に、実行時にユーザーが指定した一連のフィルタリング (比較操作) を効率的に連鎖させたいと考えています。

フィルタは追加的である必要があります (つまり、適用されるそれぞれが結果を絞り込む必要があります)。

私は現在使用してreindex()いますが、これは毎回新しいオブジェクトを作成し、基礎となるデータをコピーします(ドキュメントを正しく理解している場合)。そのため、大きな Series または DataFrame をフィルタリングする場合、これは非常に非効率的です。

apply()map()、または同様のものを使用する方が良いかもしれないと考えています。私はパンダにかなり慣れていないので、まだすべてを理解しようとしています。

TL;DR

次の形式の辞書を取得し、各操作を特定の Series オブジェクトに適用して、「フィルター処理された」Series オブジェクトを返したいと考えています。

relops = {'>=': [1], '<=': [1]}

長い例

私が現在持っているものの例から始めて、単一の Series オブジェクトをフィルタリングするだけです。以下は私が現在使用している機能です:

   def apply_relops(series, relops):
        """
        Pass dictionary of relational operators to perform on given series object
        """
        for op, vals in relops.iteritems():
            op_func = ops[op]
            for val in vals:
                filtered = op_func(series, val)
                series = series.reindex(series[filtered])
        return series

ユーザーは、実行したい操作を含む辞書を提供します。

>>> df = pandas.DataFrame({'col1': [0, 1, 2], 'col2': [10, 11, 12]})
>>> print df
>>> print df
   col1  col2
0     0    10
1     1    11
2     2    12

>>> from operator import le, ge
>>> ops ={'>=': ge, '<=': le}
>>> apply_relops(df['col1'], {'>=': [1]})
col1
1       1
2       2
Name: col1
>>> apply_relops(df['col1'], relops = {'>=': [1], '<=': [1]})
col1
1       1
Name: col1

繰り返しますが、上記のアプローチの「問題」は、中間のステップで不要なデータのコピーがたくさんあると思うことです。

また、渡されたディクショナリに演算子の列を含め、入力ディクショナリに基づいて DataFrame 全体をフィルタリングできるように、これを拡張したいと思います。ただし、シリーズで機能するものはすべて、DataFrame に簡単に拡張できると想定しています。

4

7 に答える 7

320

Pandas (および numpy) では、ブール値のインデックス作成が可能になり、はるかに効率的になります。

In [11]: df.loc[df['col1'] >= 1, 'col1']
Out[11]: 
1    1
2    2
Name: col1

In [12]: df[df['col1'] >= 1]
Out[12]: 
   col1  col2
1     1    11
2     2    12

In [13]: df[(df['col1'] >= 1) & (df['col1'] <=1 )]
Out[13]: 
   col1  col2
1     1    11

このためのヘルパー関数を書きたい場合は、次の行に沿って何かを検討してください。

In [14]: def b(x, col, op, n): 
             return op(x[col],n)

In [15]: def f(x, *b):
             return x[(np.logical_and(*b))]

In [16]: b1 = b(df, 'col1', ge, 1)

In [17]: b2 = b(df, 'col1', le, 1)

In [18]: f(df, b1, b2)
Out[18]: 
   col1  col2
1     1    11

更新: pandas 0.13 には、列名が有効な識別子であると仮定して、これらの種類のユース ケース用のクエリ メソッドがあります(背後でnumexprを使用するため、大きなフレームの場合はより効率的です)。

In [21]: df.query('col1 <= 1 & 1 <= col1')
Out[21]:
   col1  col2
1     1    11
于 2012-11-28T23:38:41.263 に答える
5

なぜこれをしないのですか?

def filt_spec(df, col, val, op):
    import operator
    ops = {'eq': operator.eq, 'neq': operator.ne, 'gt': operator.gt, 'ge': operator.ge, 'lt': operator.lt, 'le': operator.le}
    return df[ops[op](df[col], val)]
pandas.DataFrame.filt_spec = filt_spec

デモ:

df = pd.DataFrame({'a': [1,2,3,4,5], 'b':[5,4,3,2,1]})
df.filt_spec('a', 2, 'ge')

結果:

   a  b
 1  2  4
 2  3  3
 3  4  2
 4  5  1

列「a」が a >=2 でフィルタリングされていることがわかります。

これは、演算子チェーンよりもわずかに高速です (パフォーマンスではなく、入力時間)。もちろん、インポートをファイルの先頭に置くこともできます。

于 2016-05-18T10:06:20.270 に答える