📋 このステップで学ぶこと
- データクリーニングの重要性と基本概念
- 欠損値の検出方法(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)やNone、NaT(日付の欠損)で表されます。
📝 欠損値が発生する主な原因
- データ入力ミス:ユーザーが入力を忘れた
- システムエラー:データ転送中に欠落
- アンケート未回答:特定の質問に回答しなかった
- データ統合:異なるソースのデータを結合したときのミスマッチ
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()
- データ型の確認:
dtypes、info()
- データ型の変換:
astype()、pd.to_numeric()、pd.to_datetime()
💡 データクリーニングのベストプラクティス
- まずデータを確認する(shape、dtypes、info、describe)
- 欠損値を確認し、適切に処理(削除 or 補完)
- 重複を確認し、削除
- データ型を確認し、適切に変換
- 処理前後でデータの件数と内容を確認する
🎯 次のステップの予告
次の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)