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

機械学習のためのデータ前処理:Pandasでデータを集計し、隠れた傾向を見つける方法【Pandas入門】

Tags: データ前処理, Pandas, 機械学習, データ集計, groupby, データ分析

はじめに

機械学習モデルの性能を向上させるためには、データの性質を深く理解し、適切に加工するデータ前処理が不可欠です。これまでの記事では、データの読み込み、欠損値や重複の処理、データ型の変換など、基本的なステップを解説してきました。

今回は、データ前処理における強力な手法の一つである「データ集計」に焦点を当てます。データ集計とは、データを特定の基準(例:製品カテゴリ、地域、顧客属性など)でグループ分けし、各グループについて合計や平均などの統計量を計算する処理です。この処理を行うことで、データ全体の傾向だけでなく、特定のグループが持つ「隠れた」特性やパターンを発見することができます。

ビジネスの現場では、「どの製品カテゴリの売上が最も高いか」「特定の地域ではどのような顧客層が多いか」「広告キャンペーンの効果は顧客の年齢層によってどう異なるか」といった問いに答えるためにデータ集計が頻繁に利用されます。機械学習においても、集計によって得られた情報は新しい特徴量として活用され、モデルの精度向上に大きく貢献します。

本記事では、Pythonのデータ分析ライブラリであるPandasを使用して、データを集計し、ビジネス上の洞察や機械学習に役立つ情報を引き出す方法を、具体的なコード例とともに解説します。

データ集計とは何か?

データ集計は、大量の生データから意味のある情報を抽出するための基本的な手法です。これは、スプレッドシートソフトウェアで「ピボットテーブル」を作成する操作に似ています。

主な目的は以下の通りです。

例えば、顧客データがあったとして、「顧客の居住地域ごと」に「平均購入金額」を計算するといった操作が集計にあたります。これにより、「この地域の顧客は他の地域よりも多く購入する傾向がある」といったビジネス上の重要な知見が得られます。

Pandasでのデータ集計の基本:groupby()メソッド

Pandasでデータ集計を行う際に中心となるのがgroupby()メソッドです。このメソッドは、以下の3つのステップを経て集計を実行します。

  1. 分割 (Splitting): データセットを、指定したキー(列や列のリスト)の値に基づいて複数のグループに分割します。
  2. 適用 (Applying): 各グループに対して、指定した集計関数(sum(), mean(), count(), max(), min()など)や変換関数を適用します。
  3. 結合 (Combining): 各グループに対して適用された結果を一つに結合し、集計結果のデータフレームまたはシリーズを作成します。

このプロセスは「Split-Apply-Combine」とも呼ばれます。

準備:サンプルデータの作成

解説のために、簡単なサンプルデータを作成します。これは、あるオンラインショップの注文履歴を模したデータフレームです。

import pandas as pd

# サンプルデータの作成
data = {
    '注文ID': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    '製品カテゴリ': ['電化製品', '書籍', '電化製品', '食品', '書籍', '食品', '電化製品', '書籍', '食品', '電化製品'],
    '地域': ['東京', '大阪', '東京', '愛知', '大阪', '東京', '愛知', '大阪', '東京', '愛知'],
    '売上金額': [12000, 3500, 8000, 1500, 4000, 2000, 15000, 3000, 1800, 10000],
    '数量': [1, 2, 1, 3, 1, 2, 1, 1, 2, 1],
    '顧客ID': ['A', 'B', 'A', 'C', 'B', 'C', 'A', 'B', 'C', 'A']
}

df = pd.DataFrame(data)

print("元のデータフレーム:")
print(df)
元のデータフレーム:
   注文ID 製品カテゴリ  地域  売上金額  数量 顧客ID
0     1   電化製品  東京   12000   1    A
1     2     書籍  大阪    3500   2    B
2     3   電化製品  東京    8000   1    A
3     4     食品  愛知    1500   3    C
4     5     書籍  大阪    4000   1    B
5     6     食品  東京    2000   2    C
6     7   電化製品  愛知   15000   1    A
7     8     書籍  大阪    3000   1    B
8     9     食品  東京    1800   2    C
9    10   電化製品  愛知   10000   1    A

このデータフレームを使って、様々な集計を行います。

基本的な集計:1つの列でグループ化し、1つの統計量を計算する

最も基本的な集計は、1つの列を基準にグループ化し、別の数値列に対して1つの統計量を計算することです。例えば、「製品カテゴリごとの合計売上金額」を計算してみましょう。

# 製品カテゴリごとに売上金額を合計
sales_by_category = df.groupby('製品カテゴリ')['売上金額'].sum()

print("\n製品カテゴリごとの合計売上金額:")
print(sales_by_category)
製品カテゴリごとの合計売上金額:
製品カテゴリ
書籍        10500
電化製品      45000
食品         5300
Name: 売上金額, dtype: int64

コードの解説:

  1. df.groupby('製品カテゴリ'): データフレームdfを「製品カテゴリ」列の値に基づいてグループ化します。この段階ではまだ集計は実行されていません。グループ化されたオブジェクトが返されます。
  2. ['売上金額']: グループ化されたオブジェクトに対して、集計対象としたい列(ここでは「売上金額」)を選択します。
  3. .sum(): 選択した列に対して、各グループの合計値を計算する集計関数sum()を適用します。

この結果から、「電化製品」の売上が他のカテゴリよりもはるかに高いことがわかります。これは、どの製品カテゴリに注力すべきか、といったビジネス上の意思決定に役立つ情報となります。

同様に、平均売上金額や注文数を計算することも可能です。

# 製品カテゴリごとの平均売上金額
mean_sales_by_category = df.groupby('製品カテゴリ')['売上金額'].mean()
print("\n製品カテゴリごとの平均売上金額:")
print(mean_sales_by_category)

# 製品カテゴリごとの注文数(行数)
count_by_category = df.groupby('製品カテゴリ').size() # size()は各グループの行数を数える
print("\n製品カテゴリごとの注文数:")
print(count_by_category)
製品カテゴリごとの平均売上金額:
製品カテゴリ
書籍         3500.0
電化製品      11250.0
食品         1766.666667
Name: 売上金額, dtype: float64

製品カテゴリごとの注文数:
製品カテゴリ
書籍        3
電化製品      4
食品        3
dtype: int64

これらの結果から、「電化製品は注文数はやや多いが、1件あたりの平均売上金額が圧倒的に高い」といったより詳細な分析が可能になります。

複数の列でグループ化する

集計の基準を複数指定することもできます。例えば、「地域別」かつ「製品カテゴリ別」の合計売上金額を計算してみましょう。

# 地域別かつ製品カテゴリ別に売上金額を合計
sales_by_region_category = df.groupby(['地域', '製品カテゴリ'])['売上金額'].sum()

print("\n地域別・製品カテゴリごとの合計売上金額:")
print(sales_by_region_category)
地域別・製品カテゴリごとの合計売上金額:
地域  製品カテゴリ
大阪  書籍          7500
    電化製品         NaN
    食品           NaN
愛知  書籍           NaN
    電化製品      25000
    食品          1500
東京  書籍           NaN
    電化製品      20000
    食品          3800
Name: 売上金額, dtype: float64

この結果を見ると、例えば「大阪では書籍の売上があり、電化製品と食品の売上はない(NaNは該当データがないことを示す)」、「愛知と東京では電化製品と食品の売上があり、書籍の売上はない」といった傾向が読み取れます。

結果がSeries形式で表示されていますが、reset_index()を使うとデータフレームに変換できます。

# 結果をデータフレームに変換
sales_by_region_category_df = df.groupby(['地域', '製品カテゴリ'])['売上金額'].sum().reset_index()

print("\n地域別・製品カテゴリごとの合計売上金額 (データフレーム形式):")
print(sales_by_region_category_df)
地域別・製品カテゴリごとの合計売上金額 (データフレーム形式):
   地域 製品カテゴリ  売上金額
0   大阪     書籍   7500
1   愛知   電化製品  25000
2   愛知     食品   1500
3   東京   電化製品  20000
4   東京     食品   3800

このように、複数の基準でグループ化することで、よりきめ細やかなデータ分析が可能になります。機械学習においては、これらの集計結果を新しい特徴量として元のデータに結合したり、特定のセグメントに対するモデルを構築する際の分析に活用したりします。

複数の統計量を同時に計算する:agg()メソッド

グループごとに複数の統計量を同時に計算したい場合は、agg()メソッド(aggregateの略)を使用します。例えば、「製品カテゴリごと」に「売上金額」の合計と平均、そして「数量」の合計を計算してみましょう。

# 製品カテゴリごとに、売上金額の合計と平均、数量の合計を計算
aggregated_data = df.groupby('製品カテゴリ').agg({
    '売上金額': ['sum', 'mean'],
    '数量': 'sum'
})

print("\n製品カテゴリごとの複数統計量:")
print(aggregated_data)
製品カテゴリごとの複数統計量:
       売上金額          数量
          sum     mean  sum
製品カテゴリ
書籍      10500  3500.0     4
電化製品    45000  11250.0     4
食品       5300  1766.666667     7

コードの解説:

  1. df.groupby('製品カテゴリ'): 同様に「製品カテゴリ」でグループ化します。
  2. .agg({...}): agg()メソッドを使います。引数には辞書を指定します。
    • 辞書のキー:集計対象の列名('売上金額', '数量')。
    • 辞書の値:その列に適用したい集計関数。単一の場合は文字列(例: 'sum')、複数の場合は関数の名前をリストで指定します(例: ['sum', 'mean'])。Pandasが認識する関数名('sum', 'mean', 'count', 'max', 'min', 'median', 'std', 'var'など)を文字列で指定できます。NumPyやカスタム関数も指定可能です。

結果は、集計対象列と統計量の名前が階層的に並んだMultiIndexの列を持つデータフレームになります。これにより、各カテゴリの売上合計、平均売上、合計数量が一度に確認できます。

この情報を活用することで、例えば「食品は単価(平均売上/数量)は低いが、数量が多く出ている」といった傾向が見えてきます。このような洞察は、在庫管理やマーケティング戦略の立案に役立ちます。機械学習においては、これらの集計値を新たな特徴量としてモデルに加えることが考えられます。

集計結果を元のデータに結合する

集計によって得られた情報は、元のデータフレームに結合することで、各行(例:各注文、各顧客)に対して、その行が属するグループの特性を示す新しい特徴量を追加できます。これは、機械学習における特徴量エンジニアリングで非常によく行われる手法です。

例えば、元のデータフレームに「その注文の製品カテゴリ全体の平均売上金額」という情報を追加したい場合を考えます。

まず、「製品カテゴリごとの平均売上金額」を計算します。

# 製品カテゴリごとの平均売上金額を計算
mean_sales_by_category = df.groupby('製品カテゴリ')['売上金額'].mean().reset_index()
mean_sales_by_category.columns = ['製品カテゴリ', 'カテゴリ平均売上金額'] # 列名を分かりやすく変更

print("\n製品カテゴリごとの平均売上金額:")
print(mean_sales_by_category)
製品カテゴリごとの平均売上金額:
   製品カテゴリ  カテゴリ平均売上金額
0     書籍      3500.000000
1   電化製品     11250.000000
2     食品      1766.666667

次に、この集計結果を元のデータフレームdfに、「製品カテゴリ」列をキーとして結合(マージ)します。

# 元のデータフレームに集計結果を結合
df_merged = pd.merge(df, mean_sales_by_category, on='製品カテゴリ', how='left')

print("\n集計結果を結合したデータフレーム:")
print(df_merged)
集計結果を結合したデータフレーム:
   注文ID 製品カテゴリ  地域  売上金額  数量 顧客ID  カテゴリ平均売上金額
0     1   電化製品  東京   12000   1    A  11250.000000
1     2     書籍  大阪    3500   2    B   3500.000000
2     3   電化製品  東京    8000   1    A  11250.000000
3     4     食品  愛知    1500   3    C   1766.666667
4     5     書籍  大阪    4000   1    B   3500.000000
5     6     食品  東京    2000   2    C   1766.666667
6     7   電化製品  愛知   15000   1    A  11250.000000
7     8     書籍  大阪    3000   1    B   3500.000000
8     9     食品  東京    1800   2    C   1766.666667
9    10   電化製品  愛知   15000   1    A  11250.000000

新しい列「カテゴリ平均売上金額」が追加されました。各注文に対して、その注文の製品カテゴリ全体の平均売上金額が紐付けられています。この情報があると、例えば「この注文の売上金額は、同じカテゴリの平均と比べて高いか低いか」といった相対的な評価が可能になります。機械学習モデルは、このような相対的な情報から特定のパターンを学習しやすくなることがあります。

まとめ

本記事では、機械学習のためのデータ前処理における「データ集計」の重要性と、Pandasライブラリのgroupby()メソッドを用いた基本的な集計方法について解説しました。

データ集計は、データを特定の基準でグループ分けし、各グループの統計量を計算することで、データに隠された傾向やパターンを発見する強力な手法です。これにより、以下のようなことが可能になります。

Pandasのgroupby()メソッドを使えば、1つまたは複数の列を基準としたグループ化、sum(), mean(), count()などの基本的な統計量の計算、さらにはagg()メソッドを用いた複数の統計量の同時計算が柔軟に行えます。また、集計結果を元のデータフレームに結合することで、グループの特性を示す新しい特徴量を作成し、機械学習モデルの精度向上に貢献することも可能です。

データ前処理において、集計はデータの理解を深め、より豊かな特徴量を作り出すための必須スキルです。今回解説した内容を参考に、ご自身のデータに対して様々な集計を試み、データに隠された価値ある情報を見つけ出してください。

次回の記事では、さらに別のデータ前処理手法について解説する予定です。