🐍

(学習ログ)Python015:pandasでデータの前処理と欠損値補完

に公開

1. はじめに

この記事の目的

実務でよく使うpandasのデータクレンジング手法を学びます。特に、欠損値を適切なロジックで補完する方法を理解することが目標です。

この記事の概要

売上データと顧客台帳を読み込み、日付の変換、文字列の正規化、欠損値の検出と補完を行います。

2. サンプルコード

コード全文

import pandas as pd

# CSVファイルとExcelファイルを読み込む
sample_uriage_data = pd.read_csv("002_サンプル/sample_uriage_data.csv")
sample_customer_ledger = pd.read_excel("002_サンプル/sample_customer_ledger.xlsx")

# 購入日を日付型に変換
sample_uriage_data["purchase_date"] = pd.to_datetime(sample_uriage_data["purchase_date"])

# 購入月を"YYYYMM"形式で追加
sample_uriage_data["purchase_month"] = sample_uriage_data["purchase_date"].dt.strftime("%Y%m")

# 商品名を大文字に統一
sample_uriage_data["item_name"] = sample_uriage_data["item_name"].str.upper()

# 商品名から全角スペースを削除
sample_uriage_data["item_name"] = sample_uriage_data["item_name"].str.replace(" ", "")

# 商品名から半角スペースを削除
sample_uriage_data["item_name"] = sample_uriage_data["item_name"].str.replace(" ", "")

# 商品名でソート(昇順)
sample_uriage_data.sort_values(by=["item_name"], ascending=True)

# 各列に欠損値があるかをチェック
sample_uriage_data.isnull().any(axis=0)

# item_priceが欠損している行を特定
flg_is_null = sample_uriage_data["item_price"].isnull()

# 欠損値を持つ商品名ごとに処理
for NaN_item_name in list(sample_uriage_data.loc[flg_is_null, "item_name"].unique()):
    # 同じ商品名で欠損していない価格の最大値を取得
    impute_price = sample_uriage_data.loc[(~flg_is_null) & (sample_uriage_data["item_name"]==NaN_item_name), "item_price"].max()
    # 欠損値を最大値で補完
    sample_uriage_data.loc[(flg_is_null) & (sample_uriage_data["item_name"]==NaN_item_name), "item_price"] = impute_price

# 処理後のデータを確認
sample_uriage_data.head()

コード解説

データ読み込み部分

sample_uriage_data = pd.read_csv("002_サンプル/sample_uriage_data.csv")
sample_customer_ledger = pd.read_excel("002_サンプル/sample_customer_ledger.xlsx")

売上データ(CSV)と顧客台帳(Excel)を読み込みます。pandasは複数のファイル形式に対応しているため、異なる形式のデータを統一的に扱えます。

日付データの変換

sample_uriage_data["purchase_date"] = pd.to_datetime(sample_uriage_data["purchase_date"])
sample_uriage_data["purchase_month"] = sample_uriage_data["purchase_date"].dt.strftime("%Y%m")

文字列として保存された日付をdatetime型に変換し、さらに年月だけを取り出して新しい列を作成します。strftimeで"202501"のような形式に整形できます。

文字列の正規化

sample_uriage_data["item_name"] = sample_uriage_data["item_name"].str.upper()
sample_uriage_data["item_name"] = sample_uriage_data["item_name"].str.replace(" ", "")
sample_uriage_data["item_name"] = sample_uriage_data["item_name"].str.replace(" ", "")

商品名を大文字に統一し、全角・半角スペースを削除します。これにより「Apple Juice」「apple juice」「APPLE JUICE」などの表記ゆれを統一できます。

欠損値の補完ロジック

flg_is_null = sample_uriage_data["item_price"].isnull()
for NaN_item_name in list(sample_uriage_data.loc[flg_is_null, "item_name"].unique()):
    impute_price = sample_uriage_data.loc[(~flg_is_null) & (sample_uriage_data["item_name"]==NaN_item_name), "item_price"].max()
    sample_uriage_data.loc[(flg_is_null) & (sample_uriage_data["item_name"]==NaN_item_name), "item_price"] = impute_price

価格が欠損している行を見つけ、同じ商品名を持つ他の行の最大価格で補完します。これは「同じ商品なら価格も同じはず」という仮定に基づいた処理です。

実行結果例

元データ(一部)

   customer_id  item_name     purchase_date  item_price
0          101  apple juice    2025-01-05        350.0
1          102  APPLE JUICE    2025-01-06          NaN
2          103  Orange Juice   2025-01-07        400.0
3          101  orange juice  2025-01-08        420.0

処理後のデータ

   customer_id  item_name     purchase_date  purchase_month  item_price
0          101  APPLEJUICE   2025-01-05      202501          350.0
1          102  APPLEJUICE   2025-01-06      202501          350.0
2          103  ORANGEJUICE  2025-01-07      202501          420.0
3          101  ORANGEJUICE  2025-01-08      202501          420.0

商品名が統一され、欠損していた価格が同じ商品の最大値(350円)で補完されていることが確認できます。

3. エラーと確認のポイント

代表的なエラー文

FileNotFoundError

FileNotFoundError: [Errno 2] No such file or directory: '002_サンプル/sample_uriage_data.csv'

原因: ファイルパスが間違っているか、ファイルが存在しない場合に発生します。相対パスではなく絶対パスを使うか、カレントディレクトリを確認しましょう。

KeyError

KeyError: 'item_price'

原因: 指定した列名がDataFrameに存在しない場合に発生します。columnsメソッドで実際の列名を確認しましょう。

AttributeError

AttributeError: 'Series' object has no attribute 'str'

原因: 文字列型でない列に.strメソッドを使おうとした場合に発生します。dtypeで型を確認し、必要に応じてastype(str)で変換してください。

よく使う確認メソッドと出力例

データの形状を確認

sample_uriage_data.shape
# 出力例: (1000, 5)  # 1000行、5列

列名を確認

sample_uriage_data.columns
# 出力例: Index(['customer_id', 'item_name', 'purchase_date', 'purchase_month', 'item_price'], dtype='object')

先頭のデータを確認

sample_uriage_data.head()
# 最初の5行が表形式で表示されます

欠損値の数を確認

sample_uriage_data.isnull().sum()
# 出力例:
# customer_id        0
# item_name          0
# purchase_date      0
# purchase_month     0
# item_price        15
# dtype: int64

データ型を確認

sample_uriage_data.dtypes
# 出力例:
# customer_id               int64
# item_name                object
# purchase_date    datetime64[ns]
# purchase_month           object
# item_price              float64
# dtype: object

4. まとめ

本記事を通じて、以下のスキルが身につきました。

  • データ読み込みと型変換: CSVやExcelファイルの読み込み、文字列を日付型に変換する方法
  • 文字列の正規化: 大文字変換やスペース削除による表記ゆれの統一手法
  • 欠損値の補完ロジック: 条件に応じて欠損値を適切な値で埋める実践的なアプローチ

Discussion