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

機械学習のためのデータ前処理:重複データを見つけて取り除く方法【Pandas入門】

Tags: Python, Pandas, データ前処理, 重複データ, 機械学習

はじめに:なぜ重複データの処理が重要なのか

機械学習モデルを構築する際、元となるデータの品質はモデルの性能に大きく影響します。データ前処理は、このデータの品質を高め、モデルが正確なパターンを学習できるようデータを整える重要な工程です。

データ前処理を行う上でしばしば遭遇する問題の一つに「重複データ」があります。同じ情報を持つ行が複数存在している状態を指します。例えば、顧客リストで同じ顧客情報が誤って二重に登録されていたり、センサーデータで同じ時刻に全く同じ計測値が複数記録されていたりする場合です。

このような重複データがデータセットに含まれていると、機械学習モデルは特定のパターンを過剰に学習したり、分析結果が歪められたりする可能性があります。正確な分析や予測を行うためには、これらの重複データを見つけ出し、適切に処理する必要があります。

この記事では、データ分析ライブラリであるPandasを使って、データセット内の重複データを見つけ、そして取り除く方法を解説します。初心者の方でも理解できるよう、具体的なコード例を交えながら進めていきます。

重複データとは?

重複データとは、データセット内の複数の行が全く同じ値を持っている状態を指します。

例えば、以下のような簡単な顧客リストを考えてみましょう。

| 顧客ID | 氏名 | メールアドレス | 登録日 | | :----- | :------- | :--------------- | :------- | | 101 | 山田太郎 | taro.y@example.com | 2023-01-15 | | 102 | 佐藤花子 | hanako.s@example.com | 2023-02-20 | | 101 | 山田太郎 | taro.y@example.com | 2023-01-15 | | 103 | 田中一郎 | ichiro.t@example.com | 2023-03-10 | | 102 | 佐藤花子 | hanako.s@example.com | 2023-02-20 |

このリストを見ると、1行目と3行目が全く同じ内容です。また、2行目と5行目も全く同じ内容になっています。これらが重複データです。

このように、すべての列の値が一致している行が重複データとして扱われるのが一般的ですが、「特定の列の組み合わせが一致している場合に重複とみなす」という考え方もあります。例えば、「顧客ID」が同じであれば重複とみなす、といったケースです。

Pandasで重複データを見つける: duplicated() メソッド

Pandasでは、duplicated() というメソッドを使ってデータフレーム内の重複行を簡単に検出できます。このメソッドは、各行が前の行までに登場した行と重複しているかどうかを示す真偽値(True/False)のシリーズ(Series)を返します。

基本的な使い方は以下の通りです。

import pandas as pd

# サンプルデータの作成
data = {
    '顧客ID': [101, 102, 101, 103, 102],
    '氏名': ['山田太郎', '佐藤花子', '山田太郎', '田中一郎', '佐藤花子'],
    'メールアドレス': ['taro.y@example.com', 'hanako.s@example.com', 'taro.y@example.com', 'ichiro.t@example.com', 'hanako.s@example.com'],
    '登録日': ['2023-01-15', '2023-02-20', '2023-01-15', '2023-03-10', '2023-02-20']
}
df = pd.DataFrame(data)

print("元のデータフレーム:")
print(df)

# 重複行を検出
# duplicated() は、最初の出現行をFalse、それ以降の重複行をTrueと判定します。
duplicated_rows = df.duplicated()

print("\n重複しているかどうかの結果:")
print(duplicated_rows)

実行結果:

元のデータフレーム:
   顧客ID     氏名        メールアドレス        登録日
0   101  山田太郎  taro.y@example.com  2023-01-15
1   102  佐藤花子  hanako.s@example.com  2023-02-20
2   101  山田太郎  taro.y@example.com  2023-01-15
3   103  田中一郎  ichiro.t@example.com  2023-03-10
4   102  佐藤花子  hanako.s@example.com  2023-02-20

重複しているかどうかの結果:
0    False
1    False
2     True
3    False
4     True
dtype: bool

この結果を見ると、インデックス2と4の行が True になっています。これは、これらの行がそれより前に出現した行(インデックス0と1)と全く同じ内容であることを示しています。

重複している行だけを表示したい場合は、この真偽値のシリーズを使ってデータフレームをフィルタリングします。

# 重複している行だけを表示
print("\n重複している行:")
print(df[df.duplicated()])

実行結果:

重複している行:
   顧客ID     氏名        メールアドレス        登録日
2   101  山田太郎  taro.y@example.com  2023-01-15
4   102  佐藤花子  hanako.s@example.com  2023-02-20

特定の列を基準に重複を検出する

duplicated() メソッドは、デフォルトではすべての列を比較して重複を判定します。しかし、特定の列(または列のリスト)の値が一致している場合に重複とみなしたいこともあります。その場合は、subset 引数を使用します。

例えば、「顧客ID」と「氏名」が同じであれば重複とみなしたい場合は、以下のように記述します。

# 「顧客ID」と「氏名」を基準に重複を検出
duplicated_subset = df.duplicated(subset=['顧客ID', '氏名'])

print("\n「顧客ID」と「氏名」を基準にした重複結果:")
print(duplicated_subset)

# 基準にした列で重複している行だけを表示
print("\n「顧客ID」と「氏名」を基準に重複している行:")
print(df[df.duplicated(subset=['顧客ID', '氏名'])])

実行結果:

「顧客ID」と「氏名」を基準にした重複結果:
0    False
1    False
2     True
3    False
4     True
dtype: bool

「顧客ID」と「氏名」を基準に重複している行:
   顧客ID     氏名        メールアドレス        登録日
2   101  山田太郎  taro.y@example.com  2023-01-15
4   102  佐藤花子  hanako.s@example.com  2023-02-20

この例ではたまたま全体重複と同じ結果になりましたが、データによっては特定の列の組み合わせでだけ重複が見られる場合があります。

最初の出現行を残すか、最後の出現行を残すか

duplicated() メソッドは、デフォルトでは重複と判定された行のうち「最初の出現」以外を True とします。これは、重複を削除する際に最初の1つを残し、それ以降を削除するのに便利です。

この挙動は keep 引数で変更できます。 - keep='first' (デフォルト): 最初の出現行を False、それ以外を True - keep='last': 最後の出現行を False、それ以外を True - keep=False: 全ての重複行を True (元の行と完全に一致する行が複数あれば、それら全てがTrueになる)

例えば、全ての重複行を True としたい場合は、keep=False を指定します。

# 全ての重複行をTrueと判定
all_duplicates = df.duplicated(keep=False)

print("\n全ての重複行をTrueと判定した結果:")
print(all_duplicates)

# 全ての重複行を表示
print("\n全ての重複行:")
print(df[df.duplicated(keep=False)])

実行結果:

全ての重複行をTrueと判定した結果:
0     True
1     True
2     True
3    False
4     True
dtype: bool

全ての重複行:
   顧客ID     氏名        メールアドレス        登録日
0   101  山田太郎  taro.y@example.com  2023-01-15
1   102  佐藤花子  hanako.s@example.com  2023-02-20
2   101  山田太郎  taro.y@example.com  2023-01-15
4   102  佐藤花子  hanako.s@example.com  2023-02-20

この結果から、インデックス0, 1, 2, 4の行が何らかの重複グループに属していることがわかります。

Pandasで重複データを取り除く: drop_duplicates() メソッド

重複データを見つけたら、次はそのデータを削除します。Pandasでは、drop_duplicates() というメソッドを使用します。

drop_duplicates() メソッドは、duplicated() メソッドと同様の引数を持ち、重複と判定された行をデータフレームから削除した新しいデータフレームを返します。

基本的な使い方は以下の通りです。

# 重複行を削除
# デフォルトではkeep='first'となり、最初の出現行を残してそれ以降を削除します
df_cleaned = df.drop_duplicates()

print("\n重複行削除後のデータフレーム (デフォルト):")
print(df_cleaned)

実行結果:

重複行削除後のデータフレーム (デフォルト):
   顧客ID     氏名        メールアドレス        登録日
0   101  山田太郎  taro.y@example.com  2023-01-15
1   102  佐藤花子  hanako.s@example.com  2023-02-20
3   103  田中一郎  ichiro.t@example.com  2023-03-10

元のデータフレームから、インデックス2と4の行が削除され、重複のないデータフレームが得られました。

特定の列を基準に重複を削除する

drop_duplicates() メソッドにも subset 引数があります。これを使用すると、指定した列を基準に重複を判定し、削除することができます。

# 「顧客ID」と「氏名」を基準に重複を削除
# keep='first' (デフォルト) なので、各グループの最初の行が残ります
df_cleaned_subset = df.drop_duplicates(subset=['顧客ID', '氏名'])

print("\n「顧客ID」と「氏名」を基準に重複行削除後のデータフレーム:")
print(df_cleaned_subset)

実行結果:

「顧客ID」と「氏名」を基準に重複行削除後のデータフレーム:
   顧客ID     氏名        メールアドレス        登録日
0   101  山田太郎  taro.y@example.com  2023-01-15
1   102  佐藤花子  hanako.s@example.com  2023-02-20
3   103  田中一郎  ichiro.t@example.com  2023-03-10

この場合も結果は同じですが、これはサンプルデータが単純なためです。データによっては、全体重複はしていなくても、特定の組み合わせでは重複しているというケースがあります。

残す重複行の指定

drop_duplicates() メソッドの keep 引数も、duplicated() と同様に機能します。 - keep='first' (デフォルト): 最初の出現行を残す - keep='last': 最後の出現行を残す - keep=False: 全ての重複行を削除 (重複グループの全ての行が削除される)

例えば、最後の出現行を残したい場合は keep='last' と指定します。

# 重複行を削除 (最後の出現行を残す)
df_cleaned_last = df.drop_duplicates(keep='last')

print("\n重複行削除後のデータフレーム (最後の行を残す):")
print(df_cleaned_last)

実行結果:

重複行削除後のデータフレーム (最後の行を残す):
   顧客ID     氏名        メールアドレス        登録日
2   101  山田太郎  taro.y@example.com  2023-01-15
3   103  田中一郎  ichiro.t@example.com  2023-03-10
4   102  佐藤花子  hanako.s@example.com  2023-02-20

インデックス2と4の行が残り、インデックス0と1の行が削除されました。

元のデータフレームを直接変更する

drop_duplicates() は新しいデータフレームを返しますが、元のデータフレームを直接変更したい場合は、inplace=True 引数を指定します。

# 元のデータフレームを直接変更して重複を削除
df.drop_duplicates(inplace=True)

print("\n重複行削除後の元のデータフレーム:")
print(df)

実行結果:

重複行削除後の元のデータフレーム:
   顧客ID     氏名        メールアドレス        登録日
0   101  山田太郎  taro.y@example.com  2023-01-15
1   102  佐藤花子  hanako.s@example.com  2023-02-20
3   103  田中一郎  ichiro.t@example.com  2023-03-10

inplace=True を指定すると、関数は何も返さず、元の df オブジェクト自体が変更されます。

まとめ

この記事では、データ分析や機械学習の準備段階で重要な重複データの処理方法について解説しました。

データ前処理において、重複データの処理は欠損値の処理やカテゴリ変数のエンコーディングなどと同様に基本的なステップです。今回学んだPandasのメソッドを活用して、データセットをクリーンな状態に整え、より信頼性の高い機械学習モデル構築につなげてください。

データ前処理には、他にも様々な手法があります。引き続き他の記事も参照し、データ前処理の知識を体系的に深めていきましょう。