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
関数を使わずに条件検索
まずは関数を使わない方法から解説します。name
がSatoh
の行を抽出します。
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の通常の条件指定で使うand
、or
、not
はつかうことができず、代わりに&
、|
、~
を使います。
名前が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
Egawa
かSatoh
を探します。
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のやり方に慣れられると見た目もすっきりして後で見返しても意味がわかりやすいコードになるかと思います。
参考
- Python for Data Analysis 2nd edition –Wes McKinney(書籍)
- pandasで複数条件のand, or, notから行を抽出(選択) note.nkmk.me
- pandas.DataFrame.query — pandas 0.23.4 documentation
- Python pandas データ選択処理をちょっと詳しく <後編> StatsFragme