ホーム > python > pandas > pandas.DataFrame、pandas.Seriesから特定条件のデータを抽出

pandas.DataFrame、pandas.Seriesから特定条件のデータを抽出

pythonpandas

環境

今回動作の確認を行った際のバージョンは下記の通り
python:3.10.9
pandas:1.5.3
データセット:scikit-learnのirisを使用(scikit-learnは1.2.2)


データセットの準備

前回までと同じirisデータセットを使用して動作を確認していきます。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
print(df.head())
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 0
# 1 4.9 3.0 ... 0.2 0
# 2 4.7 3.2 ... 0.2 0
# 3 4.6 3.1 ... 0.2 0
# 4 5.0 3.6 ... 0.2 0
# [5 rows x 5 columns]


booleanのリストを使用したデータ抽出

pandas.DataFrame、pandas.Seriesは共に[]に[True, False]の様なbooleanのリストを渡すことで特定の行(Trueが指定された行)を抽出することが可能です。
例えば、下記の様に[True, False, True, False, ・・・]というリストを渡すことで偶数行のデータを抽出することが出来ます。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# sepal length (cm)列をSeriesとして抽出
s = df['sepal length (cm)']
# TrueとFalseが交互に存在するリストを作成
bool_list = [True, False]*int(len(df)/2)
# データフレームから偶数行のみ抽出
print(df[bool_list])
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 0
# 2 4.7 3.2 ... 0.2 0
# 4 5.0 3.6 ... 0.2 0
# 6 4.6 3.4 ... 0.3 0
# 8 4.4 2.9 ... 0.2 0
# .. ... ... ... ... ...
# 140 6.7 3.1 ... 2.4 2
# 142 5.8 2.7 ... 1.9 2
# 144 6.7 3.3 ... 2.5 2
# 146 6.3 2.5 ... 1.9 2
# 148 6.2 3.4 ... 2.3 2
#
# [75 rows x 5 columns]
# seriesから偶数行のみ抽出
print(s[bool_list])
# 0 5.1
# 2 4.7
# 4 5.0
# 6 4.6
# 8 4.4
# ...
# 140 6.7
# 142 5.8
# 144 6.7
# 146 6.3
# 148 6.2
# Name: sepal length (cm), Length: 75, dtype: float64

また、pandas.DataFrame、pandas.Seriesでは比較演算子を使うことで条件に合致する行のみをTrueとして取得することが可能です。
これを使って「sepal length (cm)が5より大きいデータ」を抽出してみます。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# sepal length (cm)列をSeriesとして抽出
s = df['sepal length (cm)']
# Dataframeからsepal length (cm)が5より大きいデータを選択
print(df['sepal length (cm)'] > 5)
# 0 True
# 1 False
# 2 False
# 3 False
# 4 False
# ...
# 145 True
# 146 True
# 147 True
# 148 True
# 149 True
# Name: sepal length (cm), Length: 150, dtype: bool
# seriesからsepal length (cm)が5より大きいデータを選択
print(s > 5)
# 0 True
# 1 False
# 2 False
# 3 False
# 4 False
# ...
# 145 True
# 146 True
# 147 True
# 148 True
# 149 True
# Name: sepal length (cm), Length: 150, dtype: bool
# 上記のリストを使ってDataframeからsepal length (cm)が5より大きいデータのみ抽出
print(df[df['sepal length (cm)'] > 5])
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 0
# 5 5.4 3.9 ... 0.4 0
# 10 5.4 3.7 ... 0.2 0
# 14 5.8 4.0 ... 0.2 0
# 15 5.7 4.4 ... 0.4 0
# .. ... ... ... ... ...
# 145 6.7 3.0 ... 2.3 2
# 146 6.3 2.5 ... 1.9 2
# 147 6.5 3.0 ... 2.0 2
# 148 6.2 3.4 ... 2.3 2
# 149 5.9 3.0 ... 1.8 2
#
# [118 rows x 5 columns]
# 上記のリストを使ってseriesからsepal length (cm)が5より大きいデータのみ抽出
print(s[s > 5])
# 0 5.1
# 5 5.4
# 10 5.4
# 14 5.8
# 15 5.7
# ...
# 145 6.7
# 146 6.3
# 147 6.5
# 148 6.2
# 149 5.9
# Name: sepal length (cm), Length: 118, dtype: float64

下記の様に「&」「|」を使用することで複数条件を指定することも可能です。
各条件を()で括らないとエラーとなるので注意が必要です。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# Dataframeからsepal length (cm)が5より大きく5.5より小さいデータのみ抽出
print(df[(df['sepal length (cm)'] > 5) & (df['sepal length (cm)'] < 5.5)])
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 0
# 5 5.4 3.9 ... 0.4 0
# 10 5.4 3.7 ... 0.2 0
# 16 5.4 3.9 ... 0.4 0
# 17 5.1 3.5 ... 0.3 0
# 19 5.1 3.8 ... 0.3 0
# 20 5.4 3.4 ... 0.2 0
# 21 5.1 3.7 ... 0.4 0
# 23 5.1 3.3 ... 0.5 0
# 27 5.2 3.5 ... 0.2 0
# 28 5.2 3.4 ... 0.2 0
# 31 5.4 3.4 ... 0.4 0
# 32 5.2 4.1 ... 0.1 0
# 39 5.1 3.4 ... 0.2 0
# 44 5.1 3.8 ... 0.4 0
# 46 5.1 3.8 ... 0.2 0
# 48 5.3 3.7 ... 0.2 0
# 59 5.2 2.7 ... 1.4 1
# 84 5.4 3.0 ... 1.5 1
# 98 5.1 2.5 ... 1.1 1
#
# [20 rows x 5 columns]


queryを使用したデータ抽出

pandas.DataFrame.queryを使用することでも条件を指定してデータ抽出を行うことが可能です。
ただしpandas.DataFrame.queryはpandas.DataFrameのみで使用可能です。
普通はquery('5 < 列名')の様な使い方をしますが、今回は列名に空白が入っているためそのままだとエラーが発生します。
今回のデータの様に列名に空白が入っている場合はバッククォート「``」で列をくくる必要があります。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# Dataframeからsepal length (cm)が5より大きく5.5より小さいデータのみ抽出
print(df.query('5 < `sepal length (cm)` < 5.5'))
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 0
# 5 5.4 3.9 ... 0.4 0
# 10 5.4 3.7 ... 0.2 0
# 16 5.4 3.9 ... 0.4 0
# 17 5.1 3.5 ... 0.3 0
# 19 5.1 3.8 ... 0.3 0
# 20 5.4 3.4 ... 0.2 0
# 21 5.1 3.7 ... 0.4 0
# 23 5.1 3.3 ... 0.5 0
# 27 5.2 3.5 ... 0.2 0
# 28 5.2 3.4 ... 0.2 0
# 31 5.4 3.4 ... 0.4 0
# 32 5.2 4.1 ... 0.1 0
# 39 5.1 3.4 ... 0.2 0
# 44 5.1 3.8 ... 0.4 0
# 46 5.1 3.8 ... 0.2 0
# 48 5.3 3.7 ... 0.2 0
# 59 5.2 2.7 ... 1.4 1
# 84 5.4 3.0 ... 1.5 1
# 98 5.1 2.5 ... 1.1 1
#
# [20 rows x 5 columns]

変数を使用する場合は、「@変数」とすることで条件式に使用することが可能です。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# Dataframeからsepal length (cm)が5より大きく5.5より小さいデータのみ抽出
min = 5
max = 5.5
print(df.query('@min < `sepal length (cm)` < @max'))
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 0
# 5 5.4 3.9 ... 0.4 0
# 10 5.4 3.7 ... 0.2 0
# 16 5.4 3.9 ... 0.4 0
# 17 5.1 3.5 ... 0.3 0
# 19 5.1 3.8 ... 0.3 0
# 20 5.4 3.4 ... 0.2 0
# 21 5.1 3.7 ... 0.4 0
# 23 5.1 3.3 ... 0.5 0
# 27 5.2 3.5 ... 0.2 0
# 28 5.2 3.4 ... 0.2 0
# 31 5.4 3.4 ... 0.4 0
# 32 5.2 4.1 ... 0.1 0
# 39 5.1 3.4 ... 0.2 0
# 44 5.1 3.8 ... 0.4 0
# 46 5.1 3.8 ... 0.2 0
# 48 5.3 3.7 ... 0.2 0
# 59 5.2 2.7 ... 1.4 1
# 84 5.4 3.0 ... 1.5 1
# 98 5.1 2.5 ... 1.1 1
#
# [20 rows x 5 columns]

特定の値と一致するデータのみ抽出する場合はリストとinを使って下記の様に記述することもできます。

from sklearn.datasets import load_iris
if __name__ == '__main__':
df = load_iris(as_frame=True).frame
# Dataframeからsepal length (cm)が5.1、5.2のデータのみ抽出
print(df.query('`sepal length (cm)` in [5.1, 5.2]'))
# sepal length (cm) sepal width (cm) ... petal width (cm) target
# 0 5.1 3.5 ... 0.2 0
# 17 5.1 3.5 ... 0.3 0
# 19 5.1 3.8 ... 0.3 0
# 21 5.1 3.7 ... 0.4 0
# 23 5.1 3.3 ... 0.5 0
# 27 5.2 3.5 ... 0.2 0
# 28 5.2 3.4 ... 0.2 0
# 32 5.2 4.1 ... 0.1 0
# 39 5.1 3.4 ... 0.2 0
# 44 5.1 3.8 ... 0.4 0
# 46 5.1 3.8 ... 0.2 0
# 59 5.2 2.7 ... 1.4 1
# 98 5.1 2.5 ... 1.1 1
#
# [13 rows x 5 columns]