機械学習データ前処理入門

機械学習データ前処理:特定の条件を満たす行・列を抽出する方法【Pandas入門】

Tags: データ前処理, Pandas, Python, データ分析, フィルタリング

はじめに

データ分析や機械学習のプロジェクトでは、最初に手元にあるデータ全体を扱うのではなく、特定の条件を満たすデータだけを抜き出して分析を進めることがよくあります。例えば、ある特定の期間のデータだけを見たい、特定の地域や属性を持つ顧客データだけを対象にしたい、といった場合です。

このような作業は、データ前処理における重要なステップの一つであり、「データの抽出」や「フィルタリング」と呼ばれます。必要なデータだけに焦点を当てることで、分析の効率を高め、より精度の高いモデル構築につなげることができます。

この記事では、Pythonのデータ分析ライブラリであるPandasを使って、データフレームから特定の条件を満たす行や列を抽出する基本的な方法を、具体的なコード例とともに解説します。プログラミング経験があまりない方でも理解できるよう、基本的な考え方から丁寧にご説明します。

なぜデータの抽出・フィルタリングが必要なのか

データ全体のサイズが大きい場合や、特定の分析タスクにとって無関係な情報が含まれている場合、データをそのまま使うと以下のような問題が生じる可能性があります。

これらの問題を解決し、分析対象を明確にするために、データの抽出・フィルタリングが必要となるのです。

Pandasでの基本的なデータ選択

PandasのDataFrameオブジェクトでは、様々な方法でデータを選択・抽出することができます。まずは基本的な列や行の選択方法から見ていきましょう。

ここでは、簡単なサンプルデータ(架空の顧客データ)を使って解説します。

import pandas as pd

# サンプルデータの作成
data = {
    'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'age': [25, 32, 45, 28, 55, 30, 40, 22, 35, 48],
    'gender': ['Male', 'Female', 'Male', 'Female', 'Male', 'Female', 'Male', 'Female', 'Male', 'Female'],
    'purchase_amount': [1500, 3200, 500, 8000, 1200, 4500, 6000, 2000, 3800, 7500],
    'product_category': ['Book', 'Electronics', 'Book', 'Clothing', 'Book', 'Clothing', 'Electronics', 'Book', 'Electronics', 'Clothing']
}
df = pd.DataFrame(data)

print(df)
   customer_id  age  gender  purchase_amount product_category
0            1   25    Male             1500             Book
1            2   32  Female             3200      Electronics
2            3   45    Male              500             Book
3            4   28  Female             8000         Clothing
4            5   55    Male             1200             Book
5            6   30  Female             4500         Clothing
6            7   40    Male             6000      Electronics
7            8   22  Female             2000             Book
8            9   35    Male             3800      Electronics
9           10   48  Female             7500         Clothing

特定の列を選択する

特定の列を選択するには、列名を指定します。1つの列を選ぶ場合はdf['列名']、複数の列を選ぶ場合はdf[['列名1', '列名2', ...]]のようにリストで指定します。

# 1つの列を選択
ages = df['age']
print("年齢カラム:\n", ages.head()) # 先頭5件を表示

# 複数の列を選択
customer_info = df[['customer_id', 'gender']]
print("\n顧客IDと性別カラム:\n", customer_info.head())

特定の行を選択する(インデックス指定)

行を選択するには、行のインデックス(左端の数字)を指定します。特定のインデックスの行を選ぶ場合はdf.loc[インデックス]またはdf.iloc[位置]、複数のインデックスの行を選ぶ場合はリストで指定します。.locはラベルベース(インデックス名)、.ilocは整数位置ベースで選択します。

# 特定のインデックスの行を選択 (インデックス3の行)
row_3 = df.loc[3]
print("インデックス3の行:\n", row_3)

# 複数のインデックスの行を選択 (インデックス1, 5, 8の行)
rows_1_5_8 = df.loc[[1, 5, 8]]
print("\nインデックス1, 5, 8の行:\n", rows_1_5_8)

条件に基づいたデータの抽出(フィルタリング)

いよいよ本題の、特定の条件を満たす行を抽出する方法です。これはPandasの最も強力で頻繁に使われる機能の一つです。

条件を指定するには、「ブールインデックス参照」という仕組みを使います。これは、データフレームと同じ長さを持つTrue/Falseのリスト(PandasではSeriesになります)を作成し、データフレームに渡すことで、Trueに対応する行だけを抽出する方法です。

例:df[df['age'] > 30] この式は、まず df['age'] > 30 という部分で、各行のageが30より大きいかどうかを判定したTrue/FalseのSeriesを作成します。

0    False  (age=25, 30以下)
1     True  (age=32, 30超え)
2     True  (age=45, 30超え)
3    False  (age=28, 30以下)
...

そして、このTrue/FalseのSeriesを df[] の中に渡すことで、Trueである行だけがフィルタリングされて抽出される、という仕組みです。

単一条件での行抽出

特定の列の値に対する条件(等しい、より大きい、より小さいなど)を指定して行を抽出します。

# 年齢が30歳より大きい顧客を抽出
adult_customers = df[df['age'] > 30]
print("年齢30歳超の顧客:\n", adult_customers)

# 性別が'Female'の顧客を抽出
female_customers = df[df['gender'] == 'Female']
print("\n女性顧客:\n", female_customers)

# 購入金額が5000円以上の顧客を抽出
high_value_customers = df[df['purchase_amount'] >= 5000]
print("\n購入金額5000円以上の顧客:\n", high_value_customers)

比較演算子 (>, <, >=, <=, ==, !=) を条件式に利用できます。

複数条件での行抽出

複数の条件を組み合わせてデータを抽出することも頻繁に行われます。複数の条件を組み合わせるには、以下の論理演算子を使用します。

条件式はそれぞれ丸括弧 () で囲む必要があります。

# 性別が'Female'かつ購入金額が5000円以上の顧客を抽出
female_high_value_customers = df[(df['gender'] == 'Female') & (df['purchase_amount'] >= 5000)]
print("女性かつ購入金額5000円以上の顧客:\n", female_high_value_customers)

# 年齢が30歳未満 または 購入金額が2000円未満の顧客を抽出
young_or_low_purchase = df[(df['age'] < 30) | (df['purchase_amount'] < 2000)]
print("\n年齢30歳未満または購入金額2000円未満の顧客:\n", young_or_low_purchase)

# 製品カテゴリが'Book'ではない顧客を抽出
not_book_category = df[~(df['product_category'] == 'Book')]
print("\n製品カテゴリが'Book'ではない顧客:\n", not_book_category)

特定の値のリストに含まれるかで抽出

特定の列の値が、あらかじめ指定したリスト内のいずれかの値と一致する行を抽出したい場合があります。例えば、「製品カテゴリが'Book'または'Electronics'のいずれかである顧客」を抽出する場合などです。これには.isin()メソッドが便利です。

# 製品カテゴリが'Book'または'Electronics'である顧客を抽出
target_categories = ['Book', 'Electronics']
book_or_electronics_customers = df[df['product_category'].isin(target_categories)]
print("製品カテゴリがBookまたはElectronicsの顧客:\n", book_or_electronics_customers)

欠損値かどうかで抽出

データに欠損値(値がないセル)が含まれている場合、欠損値のある行や欠損値のない行を抽出したいことがあります。これには.isnull()メソッドと.notnull()メソッドを使用します。

# 購入金額が欠損している行を抽出 (今回は欠損値がないデータなので空になる)
# 実際のデータでは欠損値(NaN)が存在するカラムで実行すると該当行が抽出されます
missing_purchase_customers = df[df['purchase_amount'].isnull()]
print("購入金額が欠損している顧客:\n", missing_purchase_customers)

# purchase_amountカラムに意図的に欠損値を加えて再度試す
df_with_missing = df.copy()
df_with_missing.loc[[2, 7], 'purchase_amount'] = None # または pd.NA, np.nan

missing_purchase_customers_actual = df_with_missing[df_with_missing['purchase_amount'].isnull()]
print("\n(欠損値追加後) 購入金額が欠損している顧客:\n", missing_purchase_customers_actual)

# 購入金額が欠損していない(値が存在する)行を抽出
non_missing_purchase_customers = df_with_missing[df_with_missing['purchase_amount'].notnull()]
print("\n(欠損値追加後) 購入金額が欠損していない顧客:\n", non_missing_purchase_customers)

(注:サンプルデータには元々欠損値がないため、例示のために欠損値を加えて再度実行しています)

文字列を含むかで抽出

列のデータ型が文字列の場合、特定の文字列を含んでいるかどうかで抽出したい場合があります。例えば、「製品名に'限定'という言葉が含まれる製品」を探すなどです。これには.str.contains()メソッドを使用します。

# product_categoryに'Elec'という文字列を含む行を抽出
electronics_like_products = df[df['product_category'].str.contains('Elec', na=False)] # na=Falseは欠損値をFalseとして扱うオプション
print("カテゴリ名に'Elec'を含む顧客:\n", electronics_like_products)

na=False オプションは、対象の列に欠損値(NaN)がある場合にエラーを防ぐためによく指定されます。

特定の条件を満たす行と列を同時に選択

これまでは、条件で「行」を抽出した後、結果のデータフレーム全体が表示されていました。抽出した行に対して、さらに特定の列だけを選択することもよくあります。

例えば、「年齢が30歳より大きい顧客」の中から、「customer_id」と「purchase_amount」の列だけを取り出したい場合などです。

これには、df.loc[行の条件, 列の指定] という形式を使用するのが最も一般的で分かりやすい方法です。

# 年齢が30歳より大きい顧客の、顧客IDと購入金額を抽出
adult_customers_info = df.loc[df['age'] > 30, ['customer_id', 'purchase_amount']]
print("年齢30歳超の顧客IDと購入金額:\n", adult_customers_info)

# 性別が'Male'かつ製品カテゴリが'Book'の顧客の、年齢と購入金額を抽出
male_book_purchases = df.loc[(df['gender'] == 'Male') & (df['product_category'] == 'Book'), ['age', 'purchase_amount']]
print("\n男性かつ製品カテゴリBookの顧客の年齢と購入金額:\n", male_book_purchases)

.loc[]を使うことで、行の選択(条件式)と列の選択(列名のリスト)を同時に指定できるため、非常に効率的にデータの絞り込みが可能です。

まとめ

この記事では、機械学習のためのデータ前処理の基本として、Pandasを使ったデータの抽出・フィルタリング方法を学びました。特定の条件に基づき、必要な行や列だけを選択して新しいデータフレームを作成する手法は、その後の分析やモデル構築の精度に大きく影響します。

これらの基本的な操作を習得することで、手元のデータを分析しやすい形に整形し、次のステップであるデータの整形や変換、分析へとスムーズに進むことができるようになります。ぜひ、様々な条件でデータを抽出する練習をしてみてください。

データの抽出・フィルタリングは、データ前処理のほんの一歩です。この後も、欠損値の処理、外れ値への対応、カテゴリ変数のエンコーディング、数値データのスケーリングなど、様々な重要なステップが続きます。引き続き、体系的にデータ前処理のスキルを習得していきましょう。