STEP 7:Pandasによるデータクリーニング①

🧹 STEP 7: Pandasによるデータクリーニング①

欠損値・重複・データ型を処理してデータをきれいにする方法を学びます

📋 このステップで学ぶこと

  • データクリーニングの重要性と基本概念
  • 欠損値の検出方法(isnull、isna)
  • 欠損値の削除方法(dropna)
  • 欠損値の補完方法(fillna)と補完戦略
  • 重複データの検出(duplicated)
  • 重複データの削除(drop_duplicates)
  • データ型の確認と変換(astype、to_numeric、to_datetime)

🎯 1. データクリーニングとは?

1-1. なぜデータクリーニングが必要なのか?

現実のデータは汚いです。欠損値、重複、間違ったデータ型など、そのままでは分析や機械学習に使えません。
データクリーニングで、データを使える状態に整えます。

🧹 例え話:部屋の掃除

部屋が散らかっていると、必要なものが見つかりません。

  • 散らかった部屋 = 汚いデータ
  • 掃除 = データクリーニング
  • きれいな部屋 = 分析可能なデータ

データも同じで、まずきれいにしてから分析します!

1-2. よくあるデータの問題

❌ 欠損値(Missing Value)

データが抜けている状態
例:年齢が空欄、メールがNULL

❌ 重複データ(Duplicate)

同じデータが複数回登録
例:同じ顧客が2回登録

❌ 間違ったデータ型

数値が文字列になっている
例:”1000″(文字列)

❌ 異常値(Outlier)

明らかにおかしい
例:年齢が-5歳、価格が0円

💡 ETLでのクリーニングの重要性

ETLのT(Transform:変換)の大部分は、実はデータクリーニングです。
統計によると、データサイエンティストの作業時間の60〜80%がデータクリーニングに費やされると言われています。

1-3. データクリーニングの基本的な流れ

順番 ステップ 内容
1 データの確認 データの形状、型、基本統計量を確認
2 欠損値の処理 欠損値を検出し、削除または補完
3 重複の処理 重複データを検出し、削除
4 データ型の変換 適切なデータ型に変換
5 異常値の処理 異常値を検出し、対処(STEP 8で学習)

🕳️ 2. 欠損値の処理

2-1. 欠損値とは?

欠損値(Missing Value)とは、データが入っていない状態です。
PandasではNaN(Not a Number)NoneNaT(日付の欠損)で表されます。

📝 欠損値が発生する主な原因
  • データ入力ミス:ユーザーが入力を忘れた
  • システムエラー:データ転送中に欠落
  • アンケート未回答:特定の質問に回答しなかった
  • データ統合:異なるソースのデータを結合したときのミスマッチ

2-2. 欠損値の検出

# ===== 欠損値を検出する ===== import pandas as pd import numpy as np # サンプルデータ(欠損値あり) df = pd.DataFrame({ ‘name’: [‘山田’, ‘佐藤’, ‘鈴木’, ‘田中’, ‘高橋’], ‘age’: [25, np.nan, 30, 28, np.nan], ‘email’: [‘yamada@ex.com’, None, ‘suzuki@ex.com’, ‘tanaka@ex.com’, None], ‘score’: [80, 90, np.nan, 85, 70] }) print(“=== 元のデータ ===”) print(df) print() # 1. isnull() – 欠損値ならTrue、そうでなければFalse print(“=== isnull() で欠損値の位置を確認 ===”) print(df.isnull()) print() # 2. 各カラムの欠損値の数をカウント print(“=== 各カラムの欠損値の数 ===”) print(df.isnull().sum()) print() # 3. 欠損値の割合を計算 print(“=== 欠損値の割合(%)===”) print((df.isnull().sum() / len(df) * 100).round(1)) print() # 4. 欠損値がある行だけを表示 print(“=== 欠損値を含む行 ===”) print(df[df.isnull().any(axis=1)])
【実行結果】 === 元のデータ === name age email score 0 山田 25.0 yamada@ex.com 80.0 1 佐藤 NaN None 90.0 2 鈴木 30.0 suzuki@ex.com NaN 3 田中 28.0 tanaka@ex.com 85.0 4 高橋 NaN None 70.0 === 各カラムの欠損値の数 === name 0 age 2 email 2 score 1 dtype: int64 === 欠損値の割合(%)=== name 0.0 age 40.0 email 40.0 score 20.0 dtype: float64
📝 欠損値検出のメソッド
  • isnull() = isna():同じ機能(どちらを使ってもOK)
  • notnull() = notna():isnull()の逆(欠損でなければTrue)
  • any(axis=1):行方向に1つでもTrueがあればTrue
  • all(axis=1):行方向にすべてTrueならTrue

2-3. 欠損値の削除(dropna)

欠損値を含む行や列を削除する方法です。

# ===== 欠損値を削除する ===== import pandas as pd import numpy as np df = pd.DataFrame({ ‘A’: [1, 2, np.nan, 4], ‘B’: [5, np.nan, np.nan, 8], ‘C’: [9, 10, 11, 12] }) print(“=== 元のデータ ===”) print(df) print() # 1. 欠損値を含む行を削除(デフォルト) df_dropped_rows = df.dropna() print(“=== 欠損値を含む行を削除 ===”) print(df_dropped_rows) print() # 2. 欠損値を含む列を削除 df_dropped_cols = df.dropna(axis=1) print(“=== 欠損値を含む列を削除 ===”) print(df_dropped_cols) print() # 3. すべてのカラムが欠損している行だけ削除 df_dropped_all = df.dropna(how=’all’) print(“=== すべてNaNの行だけ削除 ===”) print(df_dropped_all) print() # 4. 特定のカラムに欠損がある行を削除 df_dropped_subset = df.dropna(subset=[‘A’]) print(“=== カラムAに欠損がある行を削除 ===”) print(df_dropped_subset) print() # 5. 欠損値がN個以上ある行を削除(thresh) df_dropped_thresh = df.dropna(thresh=2) # 非欠損が2個以上ある行を残す print(“=== 非欠損値が2個以上ある行を残す ===”) print(df_dropped_thresh)
パラメータ 説明
axis=0(デフォルト) 行を削除
axis=1 列を削除
how='any'(デフォルト) 1つでも欠損があれば削除
how='all' すべて欠損の場合のみ削除
subset=['A', 'B'] 指定したカラムだけで欠損をチェック
thresh=N 非欠損値がN個以上ある行を残す

2-4. 欠損値の補完(fillna)

欠損値を特定の値で埋める方法です。削除よりもデータを保持できます。

# ===== 欠損値を補完する ===== import pandas as pd import numpy as np df = pd.DataFrame({ ‘age’: [25, np.nan, 30, 28, np.nan], ‘price’: [1000, 1500, np.nan, 2000, 1800], ‘category’: [‘A’, np.nan, ‘A’, ‘B’, np.nan] }) print(“=== 元のデータ ===”) print(df) print() # 1. 固定値で埋める df1 = df.copy() df1[‘age’] = df1[‘age’].fillna(0) print(“=== ageを0で補完 ===”) print(df1) print() # 2. 平均値で埋める df2 = df.copy() mean_price = df2[‘price’].mean() df2[‘price’] = df2[‘price’].fillna(mean_price) print(f”=== priceを平均値({mean_price:.0f})で補完 ===”) print(df2) print() # 3. 中央値で埋める df3 = df.copy() median_age = df3[‘age’].median() df3[‘age’] = df3[‘age’].fillna(median_age) print(f”=== ageを中央値({median_age})で補完 ===”) print(df3) print() # 4. 最頻値で埋める(カテゴリデータに有効) df4 = df.copy() mode_category = df4[‘category’].mode()[0] # mode()はSeriesを返すので[0] df4[‘category’] = df4[‘category’].fillna(mode_category) print(f”=== categoryを最頻値({mode_category})で補完 ===”) print(df4)

時系列データの補完

# ===== 時系列データの補完 ===== import pandas as pd import numpy as np df = pd.DataFrame({ ‘date’: pd.date_range(‘2024-01-01’, periods=5), ‘value’: [100, np.nan, np.nan, 130, 140] }) print(“=== 元のデータ ===”) print(df) print() # 1. 前の値で埋める(forward fill) df1 = df.copy() df1[‘value’] = df1[‘value’].ffill() # fillna(method=’ffill’)と同じ print(“=== 前の値で補完(ffill)===”) print(df1) print() # 2. 次の値で埋める(backward fill) df2 = df.copy() df2[‘value’] = df2[‘value’].bfill() # fillna(method=’bfill’)と同じ print(“=== 次の値で補完(bfill)===”) print(df2) print() # 3. 線形補間 df3 = df.copy() df3[‘value’] = df3[‘value’].interpolate() print(“=== 線形補間 ===”) print(df3)

2-5. 補完方法の選び方

補完方法 適した場面
0で埋める 欠損=ゼロと解釈できる場合 購入回数、クリック数
平均値 数値データで偏りがない場合 身長、体重
中央値 外れ値がある場合 年収、価格
最頻値 カテゴリデータ 性別、都道府県
前の値/次の値 時系列データ 株価、センサーデータ
線形補間 連続的な時系列データ 気温、売上推移
削除 欠損値が少ない場合(5%以下) データ量が十分ある場合
⚠️ 補完の注意点
  • 平均値補完は分布を歪めることがある(分散が小さくなる)
  • 前の値で埋めるのは、最初の値が欠損だと埋まらない
  • 補完した値は実際の値ではないことを忘れない
  • 欠損が多すぎる場合(50%以上)は、そのカラム自体を削除することも検討

2-6. 実践例:ユーザーデータの欠損値処理

# ===== 実践的な欠損値処理 ===== import pandas as pd import numpy as np # ユーザーデータ(欠損あり) df = pd.DataFrame({ ‘user_id’: [1, 2, 3, 4, 5], ‘name’: [‘山田’, ‘佐藤’, np.nan, ‘田中’, ‘鈴木’], ‘age’: [25, np.nan, 30, 28, np.nan], ‘gender’: [‘M’, ‘F’, np.nan, ‘M’, ‘F’], ‘email’: [‘yamada@ex.com’, None, ‘test@ex.com’, None, ‘suzuki@ex.com’], ‘purchase_count’: [5, np.nan, 3, 8, np.nan] }) print(“=== 元のデータ ===”) print(df) print(f”\n欠損値の数:\n{df.isnull().sum()}”) print(f”\n欠損値の割合:\n{(df.isnull().sum() / len(df) * 100).round(1)}%”) # クリーニング処理 df_clean = df.copy() # 1. nameの欠損は削除(名前がないユーザーは無効) df_clean = df_clean.dropna(subset=[‘name’]) # 2. ageの欠損は中央値で補完(外れ値の影響を避ける) median_age = df_clean[‘age’].median() df_clean[‘age’] = df_clean[‘age’].fillna(median_age) # 3. genderの欠損は最頻値で補完 mode_gender = df_clean[‘gender’].mode()[0] df_clean[‘gender’] = df_clean[‘gender’].fillna(mode_gender) # 4. emailの欠損は固定値で補完 df_clean[‘email’] = df_clean[‘email’].fillna(‘unknown@example.com’) # 5. purchase_countの欠損は0で補完(購入なし=0回) df_clean[‘purchase_count’] = df_clean[‘purchase_count’].fillna(0) print(“\n=== クリーニング後 ===”) print(df_clean) print(f”\n欠損値の数:\n{df_clean.isnull().sum()}”)

🔄 3. 重複データの処理

3-1. 重複データとは?

重複データとは、同じデータが複数回登録されている状態です。
データベースのエラーや、複数システムの統合時によく発生します。

📝 重複が発生する主な原因
  • データ入力ミス:同じユーザーを2回登録
  • システム統合:異なるシステムのデータをマージした際の重複
  • ETLのバグ:同じデータを複数回ロードしてしまった
  • リトライ処理:エラー後の再実行でデータが重複

3-2. 重複の検出(duplicated)

# ===== 重複を検出する ===== import pandas as pd df = pd.DataFrame({ ‘user_id’: [1, 2, 3, 2, 4, 3], ‘name’: [‘山田’, ‘佐藤’, ‘鈴木’, ‘佐藤’, ‘田中’, ‘鈴木’], ‘email’: [‘yamada@ex.com’, ‘sato@ex.com’, ‘suzuki@ex.com’, ‘sato@ex.com’, ‘tanaka@ex.com’, ‘suzuki@ex.com’] }) print(“=== 元のデータ ===”) print(df) print() # 1. 重複している行を検出(Trueなら重複) print(“=== duplicated()(全カラムで判定)===”) print(df.duplicated()) print() # 2. 重複している行を表示 print(“=== 重複している行 ===”) print(df[df.duplicated()]) print() # 3. 特定のカラムだけで重複をチェック print(“=== emailカラムで重複チェック ===”) print(df.duplicated(subset=[‘email’])) print() # 4. 重複の数をカウント print(f”=== 重複数 ===”) print(f”全カラム: {df.duplicated().sum()}件”) print(f”emailのみ: {df.duplicated(subset=[‘email’]).sum()}件”)

keep パラメータの違い

# ===== keepパラメータの違い ===== import pandas as pd df = pd.DataFrame({ ‘id’: [1, 2, 2, 3, 3, 3], ‘value’: [‘A’, ‘B’, ‘B’, ‘C’, ‘C’, ‘C’] }) print(“=== 元のデータ ===”) print(df) print() # keep=’first’(デフォルト):最初の出現を残し、2回目以降をTrueに print(“=== keep=’first’(最初を残す)===”) print(df.duplicated(keep=’first’)) print() # keep=’last’:最後の出現を残し、それ以前をTrueに print(“=== keep=’last’(最後を残す)===”) print(df.duplicated(keep=’last’)) print() # keep=False:すべての重複をTrueに(重複しているものをすべて見つける) print(“=== keep=False(すべての重複をマーク)===”) print(df.duplicated(keep=False))
keep 動作 用途
'first'(デフォルト) 最初の出現を残す 最も古いデータを残したい場合
'last' 最後の出現を残す 最新のデータを残したい場合
False すべての重複をマーク 重複をすべて確認したい場合

3-3. 重複の削除(drop_duplicates)

# ===== 重複を削除する ===== import pandas as pd df = pd.DataFrame({ ‘user_id’: [1, 2, 3, 2, 4], ‘name’: [‘山田’, ‘佐藤’, ‘鈴木’, ‘佐藤’, ‘田中’], ‘email’: [‘yamada@ex.com’, ‘sato@ex.com’, ‘suzuki@ex.com’, ‘sato@ex.com’, ‘tanaka@ex.com’] }) print(“=== 元のデータ ===”) print(df) print(f”行数: {len(df)}”) print() # 1. 完全に同じ行を削除(最初の出現を残す) df_unique = df.drop_duplicates() print(“=== 重複削除(全カラム)===”) print(df_unique) print(f”行数: {len(df_unique)}”) print() # 2. 特定のカラムで重複チェック df_unique_email = df.drop_duplicates(subset=[‘email’]) print(“=== 重複削除(emailカラムのみ)===”) print(df_unique_email) print() # 3. 最後の出現を残す df_last = df.drop_duplicates(subset=[‘email’], keep=’last’) print(“=== 重複削除(最後を残す)===”) print(df_last)

3-4. 実践例:顧客データの重複処理

# ===== 実践的な重複処理 ===== import pandas as pd # 顧客データ(重複あり) df = pd.DataFrame({ ‘customer_id’: [1, 2, 3, 2, 4, 3], ‘name’: [‘山田太郎’, ‘佐藤花子’, ‘鈴木一郎’, ‘佐藤花子’, ‘田中美咲’, ‘鈴木一郎’], ‘email’: [‘yamada@ex.com’, ‘sato@ex.com’, ‘suzuki@ex.com’, ‘sato@ex.com’, ‘tanaka@ex.com’, ‘suzuki@ex.com’], ‘purchase_date’: [‘2024-01-01’, ‘2024-01-02’, ‘2024-01-03’, ‘2024-01-15’, ‘2024-01-05’, ‘2024-01-20’], ‘amount’: [1000, 2000, 1500, 3000, 2500, 1800] }) print(“=== 元のデータ ===”) print(df) # 重複チェック(emailで判定) dup_count = df.duplicated(subset=[‘email’]).sum() print(f”\n重複数(emailで判定): {dup_count}件”) # 重複の詳細を確認 print(“\n=== 重複しているすべての行 ===”) print(df[df.duplicated(subset=[‘email’], keep=False)]) # 重複を削除(最新の購入日を残す) # まず日付でソート(降順) df[‘purchase_date’] = pd.to_datetime(df[‘purchase_date’]) df_sorted = df.sort_values(‘purchase_date’, ascending=False) # 重複削除(keep=’first’ = 最新を残す) df_clean = df_sorted.drop_duplicates(subset=[‘email’], keep=’first’) # customer_idでソートして元の順序に近づける df_clean = df_clean.sort_values(‘customer_id’).reset_index(drop=True) print(“\n=== 重複削除後(最新のデータを保持)===”) print(df_clean) print(f”\n削除前: {len(df)}行 → 削除後: {len(df_clean)}行”)
✅ 重複処理のベストプラクティス
  • どのカラムで判定するかを明確にする(主キー?メール?)
  • どの行を残すかを決める(最初?最後?最新?)
  • 削除前に重複の数と内容を確認する
  • 削除後に行数を確認する
  • 重要なデータはバックアップしてから削除する

🔢 4. データ型の確認と変換

4-1. なぜデータ型が重要なのか?

データ型が間違っていると、計算ができない並び替えがおかしいメモリを無駄に使うなどの問題が起きます。

❌ データ型が間違っていると起きる問題
# 数値が文字列になっていると… df = pd.DataFrame({ ‘price’: [‘1000’, ‘500’, ‘2000’] # 文字列! }) # 合計を計算しようとすると… print(df[‘price’].sum()) # 出力: ‘100050002000’(文字列の連結になる!) # 並び替えもおかしい df = pd.DataFrame({ ‘price’: [‘100′, ’50’, ‘9’] # 文字列! }) print(df.sort_values(‘price’)) # 出力: 100, 50, 9(辞書順!正しくは 9, 50, 100)

4-2. データ型の確認

# ===== データ型を確認する ===== import pandas as pd df = pd.DataFrame({ ‘user_id’: [1, 2, 3], ‘age’: [25, 30, 28], ‘price’: [1000.0, 1500.5, 2000.0], ‘name’: [‘山田’, ‘佐藤’, ‘鈴木’], ‘is_active’: [True, False, True] }) # 1. 各カラムのデータ型を表示 print(“=== dtypes ===”) print(df.dtypes) print() # 2. 詳細情報(メモリ使用量も) print(“=== info() ===”) df.info()
【実行結果】 === dtypes === user_id int64 age int64 price float64 name object is_active bool dtype: object === info() === <class ‘pandas.core.frame.DataFrame’> RangeIndex: 3 entries, 0 to 2 Data columns (total 5 columns): # Column Non-Null Count Dtype — —— ————– —– 0 user_id 3 non-null int64 1 age 3 non-null int64 2 price 3 non-null float64 3 name 3 non-null object 4 is_active 3 non-null bool dtypes: bool(1), float64(1), int64(2), object(1) memory usage: 227.0+ bytes
dtype 説明
int64 整数(64ビット) 1, 2, 3, -100
float64 浮動小数点(64ビット) 1.5, 3.14, -0.5
object 文字列など ‘山田’, ‘hello’
bool 真偽値 True, False
datetime64 日時 2024-01-01
category カテゴリ ‘M’, ‘F’, ‘東京’, ‘大阪’

4-3. データ型の変換(astype)

# ===== astype()で型変換 ===== import pandas as pd df = pd.DataFrame({ ‘user_id’: [‘1’, ‘2’, ‘3’], # 文字列 ‘age’: [’25’, ’30’, ’28’], # 文字列 ‘price’: [‘1000.5’, ‘1500’, ‘2000’] # 文字列 }) print(“=== 変換前 ===”) print(df.dtypes) print() # 文字列 → 整数 df[‘user_id’] = df[‘user_id’].astype(‘int64’) df[‘age’] = df[‘age’].astype(‘int32’) # 文字列 → 浮動小数点 df[‘price’] = df[‘price’].astype(‘float64’) print(“=== 変換後 ===”) print(df.dtypes) print() # 計算ができるようになった! print(f”年齢の合計: {df[‘age’].sum()}”) print(f”価格の平均: {df[‘price’].mean():.1f}”)

4-4. 安全な数値変換(to_numeric)

astype()は変換できない値があるとエラーになります。
pd.to_numeric()はエラーを柔軟に処理できます。

# ===== pd.to_numeric()で安全に変換 ===== import pandas as pd df = pd.DataFrame({ ‘price’: [‘1000’, ‘1500’, ‘invalid’, ‘2000’, ‘N/A’] }) print(“=== 元のデータ ===”) print(df) print() # 1. errors=’coerce’:変換できないものはNaNに df1 = df.copy() df1[‘price’] = pd.to_numeric(df1[‘price’], errors=’coerce’) print(“=== errors=’coerce’(NaNに変換)===”) print(df1) print() # 2. errors=’ignore’:変換できないものは元の値を保持 df2 = df.copy() df2[‘price’] = pd.to_numeric(df2[‘price’], errors=’ignore’) print(“=== errors=’ignore’(元の値を保持)===”) print(df2) print() # 3. errors=’raise’(デフォルト):エラーを発生 try: df3 = df.copy() df3[‘price’] = pd.to_numeric(df3[‘price’], errors=’raise’) except ValueError as e: print(f”=== errors=’raise’(エラー発生)===”) print(f”エラー: {e}”)
📝 errorsパラメータの使い分け
  • errors='coerce':変換できないものをNaNにする(推奨)
  • errors='ignore':変換できないものをそのままにする
  • errors='raise':変換できないときエラーを発生(デフォルト)

4-5. 日付型への変換(to_datetime)

# ===== pd.to_datetime()で日付に変換 ===== import pandas as pd # 様々な形式の日付 df = pd.DataFrame({ ‘date1’: [‘2024-01-01’, ‘2024-01-02’, ‘2024-01-03’], ‘date2’: [‘2024/1/1’, ‘2024/1/2’, ‘2024/1/3’], ‘date3’: [‘2024年1月1日’, ‘2024年1月2日’, ‘2024年1月3日’], ‘date4′: [’01-Jan-2024′, ’02-Jan-2024′, ’03-Jan-2024’] }) print(“=== 変換前(すべてobject型)===”) print(df.dtypes) print() # 標準的な形式は自動認識 df[‘date1’] = pd.to_datetime(df[‘date1’]) df[‘date2’] = pd.to_datetime(df[‘date2’]) # 日本語形式はformatを指定 df[‘date3’] = pd.to_datetime(df[‘date3′], format=’%Y年%m月%d日’) # 英語形式もformatを指定 df[‘date4’] = pd.to_datetime(df[‘date4′], format=’%d-%b-%Y’) print(“=== 変換後(すべてdatetime64)===”) print(df.dtypes) print() # 日付の各要素を取り出す print(“=== 日付の要素を取り出す ===”) print(f”年: {df[‘date1’].dt.year.tolist()}”) print(f”月: {df[‘date1’].dt.month.tolist()}”) print(f”日: {df[‘date1’].dt.day.tolist()}”) print(f”曜日: {df[‘date1’].dt.day_name().tolist()}”)
フォーマット 意味
%Y 4桁の年 2024
%m 2桁の月 01, 12
%d 2桁の日 01, 31
%H 時(24時間) 00, 23
%M 00, 59
%S 00, 59

4-6. 実践例:CSVデータの型変換

# ===== 実践的なデータ型変換 ===== import pandas as pd # CSVから読み込んだデータ(型が適切でない) df = pd.DataFrame({ ‘user_id’: [‘1’, ‘2’, ‘3’, ‘4’], ‘age’: [’25’, ’30’, ’28’, ’35’], ‘price’: [‘1000’, ‘1500’, ‘N/A’, ‘2000’], ‘order_date’: [‘2024-01-01’, ‘2024-01-02’, ‘2024-01-03’, ‘2024-01-04’], ‘category’: [‘A’, ‘B’, ‘A’, ‘C’], ‘is_premium’: [‘True’, ‘False’, ‘True’, ‘False’] }) print(“=== 変換前 ===”) print(df.dtypes) print() # データ型を変換 df_clean = df.copy() # 整数に変換 df_clean[‘user_id’] = df_clean[‘user_id’].astype(‘int32’) df_clean[‘age’] = df_clean[‘age’].astype(‘int32’) # 数値に変換(N/AはNaNに) df_clean[‘price’] = pd.to_numeric(df_clean[‘price’], errors=’coerce’) # 日付に変換 df_clean[‘order_date’] = pd.to_datetime(df_clean[‘order_date’]) # カテゴリに変換(メモリ効率化) df_clean[‘category’] = df_clean[‘category’].astype(‘category’) # 真偽値に変換 df_clean[‘is_premium’] = df_clean[‘is_premium’].map({‘True’: True, ‘False’: False}) print(“=== 変換後 ===”) print(df_clean.dtypes) print() print(df_clean)

📝 STEP 7 のまとめ

✅ このステップで学んだこと
  • 欠損値の検出isnull()isnull().sum()
  • 欠損値の削除dropna()(行/列削除)
  • 欠損値の補完fillna()(平均値、中央値、最頻値、前後の値)
  • 重複の検出duplicated()
  • 重複の削除drop_duplicates()
  • データ型の確認dtypesinfo()
  • データ型の変換astype()pd.to_numeric()pd.to_datetime()
💡 データクリーニングのベストプラクティス
  1. まずデータを確認する(shape、dtypes、info、describe)
  2. 欠損値を確認し、適切に処理(削除 or 補完)
  3. 重複を確認し、削除
  4. データ型を確認し、適切に変換
  5. 処理前後でデータの件数と内容を確認する
🎯 次のステップの予告

次のSTEP 8では、「Pandasによるデータクリーニング②」を学びます。

  • 異常値の検出と対処
  • 外れ値の処理
  • データの正規化

より高度なクリーニング技術を習得しましょう!

📝 練習問題

問題 1 基礎

DataFrameの各カラムの欠損値の数を表示するコードを書いてください。

【解答例】
print(df.isnull().sum())
問題 2 基礎

欠損値を含む行をすべて削除するコードを書いてください。

【解答例】
df_clean = df.dropna()
問題 3 基礎

ageカラムの欠損値を平均値で埋めるコードを書いてください。

【解答例】
mean_age = df[‘age’].mean() df[‘age’] = df[‘age’].fillna(mean_age)
問題 4 基礎

DataFrameの重複行の数をカウントするコードを書いてください。

【解答例】
dup_count = df.duplicated().sum() print(f”重複行: {dup_count}件”)
問題 5 応用

emailカラムで重複をチェックし、最初の出現を残して重複を削除するコードを書いてください。

【解答例】
df_unique = df.drop_duplicates(subset=[‘email’], keep=’first’)
問題 6 応用

文字列のpriceカラムを数値に変換し、変換できない値はNaNにするコードを書いてください。

【解答例】
df[‘price’] = pd.to_numeric(df[‘price’], errors=’coerce’)
問題 7 応用

order_dateカラム(’2024年1月1日’形式)を日付型に変換するコードを書いてください。

【解答例】
df[‘order_date’] = pd.to_datetime(df[‘order_date’], format=’%Y年%m月%d日’)
問題 8 応用

categoryカラムの欠損値を最頻値で埋めるコードを書いてください。

【解答例】
mode_category = df[‘category’].mode()[0] df[‘category’] = df[‘category’].fillna(mode_category)
問題 9 発展

欠損値の割合が50%を超えるカラムを削除するコードを書いてください。

【解答例】
# 欠損値の割合を計算 missing_ratio = df.isnull().sum() / len(df) # 50%以下のカラムだけを残す cols_to_keep = missing_ratio[missing_ratio <= 0.5].index df_clean = df[cols_to_keep] print(f"削除前: {len(df.columns)}カラム") print(f"削除後: {len(df_clean.columns)}カラム")
問題 10 発展

以下の条件でデータクリーニングを行うコードを書いてください。
① nameが欠損の行は削除
② ageの欠損は中央値で補完
③ emailで重複があれば最新のorder_dateを残して削除

【解答例】
import pandas as pd # ① nameが欠損の行は削除 df = df.dropna(subset=[‘name’]) # ② ageの欠損は中央値で補完 median_age = df[‘age’].median() df[‘age’] = df[‘age’].fillna(median_age) # ③ emailで重複があれば最新のorder_dateを残して削除 df[‘order_date’] = pd.to_datetime(df[‘order_date’]) df = df.sort_values(‘order_date’, ascending=False) df = df.drop_duplicates(subset=[‘email’], keep=’first’) df = df.sort_index().reset_index(drop=True) print(df)
📝

学習メモ

ETL・データパイプライン構築 - Step 7

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE