ユーザーが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に簡単に拡張できると想定しています。
df.query
そしてpd.eval
、あなたのユースケースに適しているようです。pd.eval()
関数のファミリー、その機能、および使用例については、pd.eval()を使用したパンダでの動的式評価をご覧ください。