pandasで複数条件のand, or, notから行を抽出(選択)

pandasで複数の条件のand, or, notから行を抽出(選択)する方法を説明します。 注意点は以下の二つ。

&、|、~を使う(and、or、notだとエラー) 比較演算子を使うときは条件ごとに括弧で囲む(括弧がないとエラー)

以下のようなエラーが出る。 and、or、notを使ったときのエラー。 ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

括弧がないときのエラー。 TypeError: cannot compare a dtyped [object] array with a scalar of type [bool]

なお、ここではブールインデックスを用いたレガシーな方法を説明するが、query()メソッドを使うとより簡潔に書ける。以下の記事を参照。

今回は例として以下のデータを使用します。

import pandas as pd

df = pd.read_csv('data/src/sample_pandas_normal.csv')
print(df)
#       name  age state  point
# 0    Alice   24    NY     64
# 1      Bob   42    CA     92
# 2  Charlie   18    CA     70
# 3     Dave   68    TX     70
# 4    Ellen   24    CA     88
# 5    Frank   30    NY     57

サンプルのcsvファイルはコチラ。

sample_pandas_normal.csv

例はpandas.DataFrameだが、pandas.Seriesでも同様。

行を抽出(選択)する方法

まず、pandas.DataFrameから行を抽出(選択)して新しいpandas.DataFrameを取得する方法を示す。 真偽値boolのリスト(配列)またはpandas.Seriesを使うと、Trueの行だけが抽出(選択)できます。

mask = [True, False, True, False, True, False]
df_mask = df[mask]
print(df_mask)
#       name  age state  point
# 0    Alice   24    NY     64
# 2  Charlie   18    CA     70
# 4    Ellen   24    CA     88

したがって、複数条件のand, or, notからboolのリストまたはpandas.Seriesを取得できればよい。 複数条件のand, or, notで行を抽出(選択)するコード例 2つの条件のandをとったboolのpandas.Seriesは、&を使って以下のように取得できます。

print(df['age'] < 35)
# 0     True
# 1    False
# 2     True
# 3    False
# 4     True
# 5     True
# Name: age, dtype: bool

print(~(df['state'] == 'NY'))
# 0    False
# 1     True
# 2     True
# 3     True
# 4     True
# 5    False
# Name: state, dtype: bool

print((df['age'] < 35) & ~(df['state'] == 'NY'))
# 0    False
# 1    False
# 2     True
# 3    False
# 4     True
# 5    False
# dtype: bool

これを使ってTrueの行だけを抽出(選択)します。

df_and = df[(df['age'] < 35) & ~(df['state'] == 'NY')]
print(df_and)
#       name  age state  point
# 2  Charlie   18    CA     70
# 4    Ellen   24    CA     88

orも同様。|を使います。

print((df['age'] < 20) | (df['point'] > 90))
# 0    False
# 1     True
# 2     True
# 3    False
# 4    False
# 5    False
# dtype: bool

df_or = df[(df['age'] < 20) | (df['point'] > 90)]
print(df_or)
#       name  age state  point
# 1      Bob   42    CA     92
# 2  Charlie   18    CA     70

3個以上の条件では演算子の優先順位に注意

演算子としての優先順位は、高い順にnot(~)、and(&)、or(|)。したがって、順番によって結果が異なる。

df_multi_1 = df[(df['age'] < 35) | ~(df['state'] == 'NY') & (df['point'] < 75)]
print(df_multi_1)
#       name  age state  point
# 0    Alice   24    NY     64
# 2  Charlie   18    CA     70
# 3     Dave   68    TX     70
# 4    Ellen   24    CA     88
# 5    Frank   30    NY     57

df_multi_2 = df[(df['age'] < 35) & (df['point'] < 75) | ~(df['state'] == 'NY')]
print(df_multi_2)
#       name  age state  point
# 0    Alice   24    NY     64
# 1      Bob   42    CA     92
# 2  Charlie   18    CA     70
# 3     Dave   68    TX     70
# 4    Ellen   24    CA     88
# 5    Frank   30    NY     57

まとまりごとに括弧で囲ったほうが無難。

df_multi_3 = df[((df['age'] < 35) | ~(df['state'] == 'NY')) & (df['point'] < 75)]
print(df_multi_3)
#       name  age state  point
# 0    Alice   24    NY     64
# 2  Charlie   18    CA     70
# 3     Dave   68    TX     70
# 5    Frank   30    NY     57

シェア

関連カテゴリー

Python pandas

pandasで分位数・パーセンタイルを取得するquantile pandasで窓関数を適用するrollingを使って移動平均などを算出 pandas.DataFrameをGroupByでグルーピングし統計量を算出 pandas参考書『Python for Data Analysis, 2nd Edition』 pandasのデータ型dtype一覧とastypeによる変換(キャスト) pandasで文字列と数値を相互変換、書式変更 pandasで日付・時間の列を処理(文字列変換、年月日抽出など) pandas-datareaderで株価や人口のデータを取得 pandas.DataFrame, SeriesとPython標準のリストを相互に変換 pandas.DataFrame, Seriesの行をランダムソート(シャッフル) pandas, Matplotlib(mpl_finance)でローソク足チャートを作成 pandas.Seriesのインデックスと値を入れ替え(スワップ) pandas.DataFrameの行・列を指定して削除するdrop pandasで特定の条件を満たす要素数をカウント(全体、行・列ごと) pandasのMultiindexで階層ごとの統計量・サンプル数を算出

Last Updated: 6/26/2019, 10:34:03 PM