note.nkmk.me

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

Date: 2017-12-29 / tags: Python, pandas

pandasで複数の条件のand, or, notから行を抽出(選択)する方法を説明する。

注意点は以下の二つ。

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

以下のようなエラーが出る。

andornotを使ったときのエラー。

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ファイルはコチラ。

例は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をとったboolpandas.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
スポンサーリンク
シェア

関連カテゴリー

関連記事