DataFrameの条件抽出はデータ分析において必須の作業です。

この記事では、条件に合致する手法のなかから、

  • 関数を使わない方法
  • query関数を使う方法

について解説します。

今回は以下のデータsample_extract.csvを使います。

name,age,state,id
Satoh,32,Kanagawa,1021
Takahashi,28,NaN,2152
Egawa,NaN,Ohsaka,1432
Maeda,25,Hiroshima,1104
Satoh,29,Ohsaka,2413
Egawa,32,Kanagawa,NaN

関数を使わずに条件検索

まずは関数を使わない方法から解説します。nameSatohの行を抽出します。

In [1]: import pandas as pd

In [2]: df = pd.read_csv("sample_extract.csv")

In [3]: df
Out[3]:
        name   age      state      id
0      Satoh  32.0   Kanagawa  1021.0
1  Takahashi  28.0        NaN  2152.0
2      Egawa   NaN     Ohsaka  1432.0
3      Maeda  25.0  Hiroshima  1104.0
4      Satoh  29.0     Ohsaka  2413.0
5      Egawa  32.0   Kanagawa     NaN

In [4]: df["name"] == "Satoh" # 名前がSatohの行がどれかをみる  
Out[4]:
0     True
1    False
2    False
3    False
4     True
5    False
Name: name, dtype: bool

In [5]: bool_list = df["name"] == "Satoh"

In [6]: df[bool_list] # boolリストで行指定するとTrueの行だけ返ってくる  
Out[6]:
    name   age     state      id
0  Satoh  32.0  Kanagawa  1021.0
4  Satoh  29.0    Ohsaka  2413.0

これを1行でまとめると、以下のように書くことができます。

In [7]: df[df["name"] == "Satoh"]
Out[7]:
    name   age     state      id
0  Satoh  32.0  Kanagawa  1021.0
4  Satoh  29.0    Ohsaka  2413.0

dfの文字列が2回出てくるなど、若干見にくさはありますが、素直な実装と言えるかもしれません。次は年齢が30を超える人を抽出してみます。

In [8]: df[df["age"]>30]
Out[8]:
    name   age     state      id
0  Satoh  32.0  Kanagawa  1021.0
5  Egawa  32.0  Kanagawa     NaN

and, or, notは &, |, ~

Pandasでの複数条件指定のとき、Pythonの通常の条件指定で使うandornotはつかうことができず、代わりに&|~を使います。

名前がEgawaで都市が大阪の人を探してみます。

それぞれの条件をカッコで囲った上で&を繋げる必要があることに注意しましょう。(条件1)&(条件2)のように書けば複数の条件を同時に満たすように指定することができます。

In [10]: df[(df["name"] == "Satoh") & (df["state"] == "Ohsaka")]
Out[10]:
    name   age   state      id
4  Satoh  29.0  Ohsaka  2413.0

では逆に名前がEgawaではない人を探してみます。

In [11]: df[~(df["name"] == "Egawa")]
Out[11]:
        name   age      state      id
0      Satoh  32.0   Kanagawa  1021.0
1  Takahashi  28.0        NaN  2152.0
3      Maeda  25.0  Hiroshima  1104.0
4      Satoh  29.0     Ohsaka  2413.0

EgawaSatohを探します。

In [13]: df[(df["name"] == "Egawa") | (df["name"] == "Satoh")]
Out[13]:
    name   age     state      id
0  Satoh  32.0  Kanagawa  1021.0
2  Egawa   NaN    Ohsaka  1432.0
4  Satoh  29.0    Ohsaka  2413.0
5  Egawa  32.0  Kanagawa     NaN

複雑な条件で検索してみましょう。条件演算子には順位がついており自分が意図したものではない条件で検索されることがあります。

多少面倒ですが、まとまりごとに括弧で囲うと読みやすくなります。

In [14]: df[(~(df["name"]=="Satoh") | df["age"] < 30 ) & (df["state"] == "Ohsaka")]
Out[14]:
    name   age   state      id
2  Egawa   NaN  Ohsaka  1432.0
4  Satoh  29.0  Ohsaka  2413.0

関数queryを使った方法

同様のことがquery関数で行うことができます。ただし、先ほどの関数を使わない例と違い、ある程度シンプルに条件を指定できます。

In [17]: df.query("name=='Satoh'") # 名前がSatohの行を探す
Out[17]:
    name   age     state      id
0  Satoh  32.0  Kanagawa  1021.0
4  Satoh  29.0    Ohsaka  2413.0

In [18]: df.query("name=='Satoh'&age>25") # 名前がSatohで年齢が25より上の人
Out[18]:
    name   age     state      id
0  Satoh  32.0  Kanagawa  1021.0
4  Satoh  29.0    Ohsaka  2413.0

In [19]: df.query("~(name=='Satoh') & age > 25 ") # 名前がSatohではない人で年齢が25より上の人
Out[19]:
        name   age     state      id
1  Takahashi  28.0       NaN  2152.0
5      Egawa  32.0  Kanagawa     NaN

In [20]: df.query("~(name=='Satoh') | age > 30 ") # 名前Satohではないか、年齢が30を超える人  
Out[20]:
        name   age      state      id
0      Satoh  32.0   Kanagawa  1021.0
1  Takahashi  28.0        NaN  2152.0
2      Egawa   NaN     Ohsaka  1432.0
3      Maeda  25.0  Hiroshima  1104.0
5      Egawa  32.0   Kanagawa     NaN

条件指定のところで変数を使いたかったらqueryの記述の中で@を頭につければ使えるようになります。

In [21]: age = 25

In [22]: df.query("age > @age")
Out[22]:
        name   age     state      id
0      Satoh  32.0  Kanagawa  1021.0
1  Takahashi  28.0       NaN  2152.0
4      Satoh  29.0    Ohsaka  2413.0
5      Egawa  32.0  Kanagawa     NaN

in演算子を使うことで複数の値を指定することが可能です。

In [26]: df.query("id in [1021, 2152]")
Out[26]:
        name   age     state      id
0      Satoh  32.0  Kanagawa  1021.0
1  Takahashi  28.0       NaN  2152.0

inplace=Trueにすると元のDataFrameの中身が条件検索の結果と入れ替わります。

In [23]: df_cp = df.copy()

In [24]: df_cp.query("name=='Egawa'", inplace=True)

In [25]: df_cp
Out[25]:
    name   age     state      id
2  Egawa   NaN    Ohsaka  1432.0
5  Egawa  32.0  Kanagawa     NaN

まとめ

今回は条件検索の方法を、関数を特に使わないやり方と、関数queryを使ったやり方とに分けて解説しました。

queryのやり方とDataFrameに直接書き込むやり方でも記述の仕方は似ているところがあるので、コードが煩雑にならないqueryのやり方に慣れられると見た目もすっきりして後で見返しても意味がわかりやすいコードになるかと思います。

参考