機械学習データ前処理:データを「グループ化」して分析の切り口を見つける方法【Pandas入門】
機械学習モデルを構築する際には、その基盤となるデータの質が非常に重要です。生データはそのままでは分析やモデル学習に適していないことが多く、様々な前処理が必要となります。本記事では、数あるデータ前処理の中でも、データを特定の条件でまとめ、分析の切り口を見つけるための強力な手法である「グループ化」について解説します。
データを「グループ化」するとは?
データにおける「グループ化」とは、特定の列(または複数の列)の値に基づいて、データをいくつかのまとまりに分ける処理を指します。例えば、顧客ごとの購入履歴データがある場合に、顧客IDでグループ化すれば、各顧客の全購入履歴をまとめて扱うことができます。
この操作は、Excelを使ったデータ分析の経験がある方であれば、「ピボットテーブル」をイメージすると分かりやすいかもしれません。ピボットテーブルでは、特定の項目(行ラベルや列ラベル)でデータを集計しますが、これも広い意味でのグループ化と集計の組み合わせと言えます。
なぜデータ前処理でグループ化が重要なのか
機械学習の文脈において、グループ化は以下のような目的で重要な前処理となります。
-
傾向の把握と分析:
- データをグループ化することで、特定の属性(例: 顧客、地域、商品カテゴリ)ごとの合計値、平均値、個数などを簡単に計算できます。これにより、データ全体の傾向や、グループ間の比較を通じてビジネス上の重要な洞察を得ることができます。
- 例えば、「商品カテゴリごとの売上合計」や「地域ごとの平均購入金額」などを算出できます。
-
新しい「特徴量」の生成:
- グループ化とそれに続く集計は、機械学習モデルの入力となる新しい特徴量(説明変数)を生み出す強力な手段です。
- 例えば、顧客ごとの購入履歴データから、「顧客ごとの購入回数」「顧客ごとの合計購入金額」「顧客が最後に購入してからの日数」などを集計することで、顧客の購買行動を表す特徴量を作成できます。これらの特徴量は、顧客の将来の購買確率予測などに役立つ可能性があります。
-
データの粒度の調整:
- データの粒度が高すぎる(細かすぎる)場合、グループ化によってデータを集約し、分析に適した粒度に変更することができます。
このように、グループ化は単にデータを整理するだけでなく、分析の質を高めたり、モデルの性能向上に繋がる新しい情報を引き出したりするための、非常に価値のある前処理手法です。
Pandasを使ったデータのグループ化(groupby()
)
Pythonでデータ分析を行う際に広く使われるpandas
ライブラリには、データを効率的にグループ化するためのgroupby()
メソッドが用意されています。groupby()
は、以下の3つのステップで処理を行います。
- Split (分割): 指定したキー(列)の値に基づいて、DataFrameを複数のグループに分割します。
- Apply (適用): 各グループに対して、集計関数(合計、平均、個数など)や変換関数、フィルタリングなどを適用します。
- Combine (結合): 適用した結果を一つのDataFrameやSeriesとして結合します。
groupby()
メソッドは、この「Split-Apply-Combine」のプロセスを効率的に実行します。
groupby()
の基本的な使い方
簡単な例として、売上データを使って、商品カテゴリごとの合計売上を計算してみましょう。まずはサンプルデータを作成します。
import pandas as pd
# サンプルデータの作成
data = {
'商品ID': ['A001', 'A002', 'B001', 'B002', 'A001', 'C001', 'B001', 'A002'],
'商品カテゴリ': ['家電', '書籍', '衣料品', '家電', '家電', '食品', '衣料品', '書籍'],
'売上金額': [10000, 3000, 5000, 12000, 9000, 2000, 6000, 3500]
}
df = pd.DataFrame(data)
print("元のデータ:")
print(df)
元のデータ:
商品ID 商品カテゴリ 売上金額
0 A001 家電 10000
1 A002 書籍 3000
2 B001 衣料品 5000
3 B002 家電 12000
4 A001 家電 9000
5 C001 食品 2000
6 B001 衣料品 6000
7 A002 書籍 3500
このデータを使って、「商品カテゴリ」ごとに「売上金額」の合計を計算します。groupby()
メソッドにグループ化したい列名を指定し、その後に集計したい列名と集計関数をドット(.)でつなげて記述します。
# '商品カテゴリ'でグループ化し、'売上金額'の合計を計算
category_sales = df.groupby('商品カテゴリ')['売上金額'].sum()
print("\n商品カテゴリごとの合計売上:")
print(category_sales)
商品カテゴリごとの合計売上:
商品カテゴリ
家電 31000
書籍 6500
衣料品 11000
食品 2000
Name: 売上金額, dtype: int64
コードの解説:
df.groupby('商品カテゴリ')
: DataFramedf
を'商品カテゴリ'列の値でグループ化します。この時点ではまだ集計は行われず、グループ化されたオブジェクトが生成されます。['売上金額']
: グループ化された各グループに対して、'売上金額'列を選択します。.sum()
: 選択した'売上金額'列に対して、合計(sum)を計算する集計関数を適用します。
結果として、各商品カテゴリの合計売上が計算されたSeriesが得られます。このSeriesのインデックスはグループ化に使用した'商品カテゴリ'列の値となっています。
複数の列でグループ化する
複数の列を組み合わせてグループ化することも可能です。例えば、「商品カテゴリ」と「商品ID」の組み合わせごとの合計売上を見たい場合は、groupby()
に列名のリストを指定します。
# '商品カテゴリ'と'商品ID'でグループ化し、'売上金額'の合計を計算
category_item_sales = df.groupby(['商品カテゴリ', '商品ID'])['売上金額'].sum()
print("\n商品カテゴリと商品IDの組み合わせごとの合計売上:")
print(category_item_sales)
商品カテゴリと商品IDの組み合わせごとの合計売上:
商品カテゴリ 商品ID
家電 A001 19000
B002 12000
書籍 A002 6500
衣料品 B001 11000
食品 C001 2000
Name: 売上金額, dtype: int64
この場合、グループ化のキーが複数あるため、結果のSeriesのインデックスも複数のレベルを持つMultiIndexとなります。
複数の集計関数を適用する
同じグループに対して、複数の集計関数を一度に適用することもできます。例えば、「商品カテゴリ」ごとの合計売上だけでなく、平均売上も知りたい場合などです。これには、集計関数をリストとして.agg()
メソッドに渡します。
# '商品カテゴリ'でグループ化し、'売上金額'の合計と平均を計算
category_agg_sales = df.groupby('商品カテゴリ')['売上金額'].agg(['sum', 'mean', 'count'])
print("\n商品カテゴリごとの合計・平均・件数:")
print(category_agg_sales)
商品カテゴリごとの合計・平均・件数:
sum mean count
商品カテゴリ
家電 31000 10333.333333 3
書籍 6500 3250.000000 2
衣料品 11000 5500.000000 2
食品 2000 2000.000000 1
.agg(['sum', 'mean', 'count'])
とすることで、指定した3つの集計関数が一度に適用され、結果はDataFrameとして返されます。列名には指定した集計関数の名前が使われます。
グループ化結果をDataFrameとして扱う(as_index=False
)
デフォルトでは、groupby()
のキーは結果のDataFrame(またはSeries)のインデックスになります。これを通常の列として扱いたい場合は、groupby()
の引数にas_index=False
を指定します。
# '商品カテゴリ'でグループ化し、'売上金額'の合計を計算(キーを列として保持)
category_sales_df = df.groupby('商品カテゴリ', as_index=False)['売上金額'].sum()
print("\n商品カテゴリごとの合計売上(DataFrame形式、インデックスを列として保持):")
print(category_sales_df)
商品カテゴリごとの合計売上(DataFrame形式、インデックスを列として保持):
商品カテゴリ 売上金額
0 家電 31000
1 書籍 6500
2 衣料品 11000
3 食品 2000
この形式で得られたDataFrameは、後続のデータ処理や、機械学習モデルへの入力としてそのまま使いやすい形となります。
特徴量生成への応用例:顧客ごとの集計特徴量
ビジネスデータの分析でよくあるシナリオとして、顧客レベルでの特徴量を作成するタスクがあります。例えば、各顧客がどれだけ購入しているかを数値で表現したい場合などです。先ほどの売上データに「顧客ID」列を追加して考えてみましょう。
import pandas as pd
# 顧客IDを追加したサンプルデータの作成
data_customer = {
'注文ID': [1, 2, 3, 4, 5, 6, 7, 8],
'顧客ID': ['C001', 'C002', 'C001', 'C003', 'C002', 'C001', 'C003', 'C002'],
'商品カテゴリ': ['家電', '書籍', '衣料品', '家電', '家電', '食品', '衣料品', '書籍'],
'売上金額': [10000, 3000, 5000, 12000, 9000, 2000, 6000, 3500],
'購入日時': pd.to_datetime(['2023-01-10', '2023-01-15', '2023-01-20', '2023-02-01', '2023-02-05', '2023-02-10', '2023-02-15', '2023-02-20'])
}
df_customer = pd.DataFrame(data_customer)
print("顧客IDを含む元のデータ:")
print(df_customer)
顧客IDを含む元のデータ:
注文ID 顧客ID 商品カテゴリ 売上金額 購入日時
0 1 C001 家電 10000 2023-01-10
1 2 C002 書籍 3000 2023-01-15
2 3 C001 衣料品 5000 2023-01-20
3 4 C003 家電 12000 2023-02-01
4 5 C002 家電 9000 2023-02-05
5 6 C001 食品 2000 2023-02-10
6 7 C003 衣料品 6000 2023-02-15
7 8 C002 書籍 3500 2023-02-20
このデータから、顧客ごとの「合計売上」「購入回数」「平均購入金額」といった特徴量を作成できます。
# '顧客ID'でグループ化し、複数の集計関数を適用して特徴量を作成
customer_features = df_customer.groupby('顧客ID').agg(
合計売上=('売上金額', 'sum'), # 合計売上
購入回数=('注文ID', 'count'), # 購入回数(注文IDの数)
平均購入金額=('売上金額', 'mean') # 平均購入金額
).reset_index() # インデックスを列に戻す
print("\n顧客ごとの集計特徴量:")
print(customer_features)
顧客ごとの集計特徴量:
顧客ID 合計売上 購入回数 平均購入金額
0 C001 17000 3 5666.666667
1 C002 15500 3 5166.666667
2 C003 18000 2 9000.000000
コードの解説:
df_customer.groupby('顧客ID')
: '顧客ID'でデータをグループ化します。.agg(...)
: 各グループに対して複数の集計処理を適用します。合計売上=('売上金額', 'sum')
: '売上金額'列に対して'sum'(合計)関数を適用し、その結果を'合計売上'という新しい列名で出力します。他の行も同様です。このようにタプル形式で('元の列名', '集計関数名')
と指定することで、新しい列名を自由に設定できます。.reset_index()
: デフォルトでインデックスになった'顧客ID'を通常の列に戻します。
このように、groupby()
と.agg()
を組み合わせることで、ビジネス上意味のある顧客レベルの集計特徴量(合計売上、購入回数、平均購入金額など)を簡単に生成できます。これらの特徴量は、例えば顧客のLTV予測やセグメンテーションといった機械学習タスクにおいて、モデルの予測精度を向上させるために非常に有効です。
さらに応用すると、購入日時データを使って、各顧客の「最後に購入してからの日数」や「初回購入からの日数」といった時間に関連する特徴量も、グループ化と適切な集計・変換処理を組み合わせて作成することが可能です。(日付・時刻データの処理については、別の記事で詳しく解説します)。
まとめ
本記事では、機械学習のためのデータ前処理における「グループ化」の重要性と、PythonのPandasライブラリを使った具体的な実装方法を解説しました。
- グループ化は、特定の条件でデータをまとめ、傾向分析や新しい特徴量生成に役立つ重要な手法です。
- Pandasの
groupby()
メソッドを使うことで、効率的にデータのグループ化と集計を行うことができます。 groupby()
と.agg()
を組み合わせることで、複数の列や複数の集計関数を使った複雑な集計も柔軟に対応できます。- 顧客ごとの購入履歴などを集計し、新しい特徴量を作成する応用例も紹介しました。
データを「グループ化」して様々な切り口から眺めたり、ビジネス上の意味を持つ集計値を作成したりすることは、データ分析の基礎であり、機械学習モデルの性能向上にも直結する重要なスキルです。ぜひご自身のデータで試してみてください。
データ前処理には様々な手法があり、グループ化もその一部です。他の重要な前処理手法についても、本サイトで体系的に学習を進めていただければ幸いです。