2017-11-06 12 views
0

Pandasを使用した基本的なフィルタリングとクエリには満足しています。たとえば、dfというデータフレームがある場合は、df[df['field1'] < 2]またはdf[df['field2'] < 3]を実行できます。複数の基準を連鎖させることもできます(例:フィルタ任意の条件を使用したPandasデータフレーム

df[(df['field1'] < 3) & (df['field2'] < 2)])。

使用する必要がある基準の数が事前にわからない場合はどうすればよいですか?これらの操作を任意の数だけ「連鎖」する方法はありますか?私は[('field1', 3), ('field2', 2), ('field3', 4)]のようなフィルタのリストを渡して、これら3つの条件を連鎖させることになります。

ありがとうございます!

+0

例役に立ったかもしれない – kbball

+0

'mask = df [ 'field1'] <3;マスク=マスク&(df ['フィールド2'] <2); mask = mask&df ['field3'] <4'など。次に 'df [mask]'を使います。 – Evert

答えて

2

パンダシリーズのオブジェクトは、あなたが呼び出すことのできるメソッドとして、より小さい、より大きい、などの操作を持っています。従ってdf['field1'] < 3df['field1'].lt(3)になります。これはあまり重要ではありませんが、コードを読みやすくします。

あなたが求めているものを実装するには、functoolsのreduce関数と演算子パッケージのand_&相当)を使用できます。

from functools import reduce 
from operator import and_ 

reduce(and_, (df.field1.lt(3), df.field2.lt(2), df.field3.lt(4))) 
+0

私はこれが一番ストレート - フォワードインテントと、少なくともマジック。ありがとう! – speedyturkey

+1

これはまた、非常に良いアプローチです!しかし、ダイナミズムは欠けています。また、シリーズよりもむしろndarraysを評価することを念頭に置いています。そして、あなたはまだ初期データフレームをフィルタリングするために結果を利用する必要があります。私は実際のソリューションとしてこれを使用したいと思います。 'c '= [(' field1 '、3)、(' field2 '、2)ここで、c = [(' field1 '、3)、(' field2 '、2)' df [reduce(and_、df [t [0] 、( 'field3'、4)] ' – piRSquared

0

私はreduce((lambda x, y: x & (df[y[0]]<y[1])), list_of_filters)と考えています。

0

あなたが条件をループと繰り返し一緒に& ING(論理と)ブールマスクによってマスクを構築

def chain_lt(df, conditions): 
    for i, (field, val) in enumerate(conditions): 
     res = df[field] < val 
     if i == 0: 
      msk = res 
     else: 
      msk &= res 
    return df[msk] 
1

その後、allを使用してaddような何か、あなたはあなたが

df1[['f1','f2','f3']].add([-2,-3,-4]).lt(0).all(1) 
を必要とするブール値を取得することができます
+0

私はコンセプトが好きです。あなたは 'df'をサブセット化し、' [-2、-3、-4] 'を取る方法を示す必要があります。 – piRSquared

+0

@piRSquaredはい、もう一度:-) – Wen

2

アプローチ1
使用pd.DataFrame.query

c = [('field1', 3), ('field2', 2), ('field3', 4)] 
f = '{0[0]} < {0[1]}'.format 

df.query(' & '.join(f(t) for t in c)) 

アプローチ2

c = [('field1', 3), ('field2', 2), ('field3', 4)] 

df[df[[t[0] for t in c]].lt([t[1] for t in c]).all(1)] 

アプローチ3
cのうちpd.Seriesを作成し、ここで

c = [('field1', 3), ('field2', 2), ('field3', 4)] 

s = pd.Series(dict(c)) 

df[df[s.index].lt(s).all(1)] 
+1

amazing ... :-) LOL – Wen

+0

よく考えていただきありがとうございます。私はアプローチ2が好きです。私はジェームズが提供している最善の解決策だと思います。 – speedyturkey

0

を比較するには、別の方法です:

import pandas as pd 
import numpy as np 

df = pd.DataFrame([np.arange(4),np.arange(3,7),np.arange(5,9)], 
        columns = ["field1","field2","field3","field4"]) 

f = [('field1', 3), ('field2', 4), ('field3', 5)] 

mask = np.array([(df[i[0]] == i[1]) for i in f]) 

# 1 True is enough: 
df[mask.any(axis=0)] # [False True False] in this sample 

# All must be true 
df[mask.all(axis=0)] # [False True False] in this sample 

DFは次のようになります。

field1 field2 field3 field4 
0  0  1  2  3 
1  3  4  5  6 
2  5  6  7  8 
関連する問題