(学習ログ)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