Pythonによる欠損値分析の実践

データ分析において、欠損値の適切な処理は精度の高い分析結果を得るための重要なステップです。本記事では、Pythonを使用した欠損値の分析方法について、実践的なコードと共に解説していきます。

1.欠損値を含むデータセットの生成

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import missingno as msno  # 欠損値可視化用ライブラリ

# サンプルデータの生成
np.random.seed(42)  # 再現性のため乱数シードを設定

# サンプルデータの作成
n_samples = 1000

# 年齢データ(正規分布)- 一部欠損値を含む
age = np.random.normal(35, 10, n_samples)
age[np.random.choice(n_samples, 50, replace=False)] = np.nan  # 5%の欠損値

# 給与データ(対数正規分布)- 高所得者ほど回答率が低い(MNAR)
salary = np.random.lognormal(10, 0.5, n_samples)
salary[salary > np.percentile(salary, 80)] = np.nan  # 上位20%を欠損に

# 性別データ - ランダムな欠損(MCAR)
gender = np.random.choice(['Male', 'Female'], n_samples)
gender[np.random.choice(n_samples, 100, replace=False)] = np.nan  # 3%の欠損値

# 教育レベル - 年齢との相関がある欠損(MAR)
education = np.random.choice(['High School', 'Bachelor', 'Master', 'PhD'], n_samples)
education[age > 45] = np.nan  # 45歳以上で欠損が多い

# 満足度スコア - 一部欠損(float型に変更)
satisfaction = np.random.randint(1, 6, n_samples).astype(float)  # float型に変換
satisfaction[np.random.choice(n_samples, 40, replace=False)] = np.nan  # 4%の欠損値

# データフレームの作成
df = pd.DataFrame({
    '年齢': age,
    '給与': salary,
    '性別': gender,
    '教育レベル': education,
    '満足度': satisfaction
})

print("生成されたデータの最初の5行:")
print(df.head())
print("\nデータの基本情報:")
print(df.info())

2. 基本的な欠損値の確認

まずは、データセット内の欠損値の概要を把握することから始めましょう。

# 基本的な欠損値の確認
def check_missing_values(df):
    # 各列の欠損値数と割合を計算
    missing_summary = pd.DataFrame({
        '欠損値数': df.isnull().sum(),
        '欠損率(%)': (df.isnull().sum() / len(df) * 100).round(2)
    })
    
    # 欠損値がある列のみを抽出し、欠損率で降順ソート
    missing_summary = missing_summary[missing_summary['欠損値数'] > 0].sort_values('欠損率(%)', ascending=False)
    
    return missing_summary

# 結果の表示
missing_summary = check_missing_values(df)
print("\n欠損値の概要:")
print(missing_summary)

3. 欠損値パターンの可視化

missingnoライブラリを使用して欠損値のパターンを可視化します。

# 欠損値パターンの可視化
def visualize_missing_patterns(df):
    plt.figure(figsize=(4, 4))
    msno.matrix(df)
    plt.title('欠損値パターン')
    plt.show()
    
    plt.figure(figsize=(4, 4))
    msno.heatmap(df)
    plt.title('欠損値の相関関係')
    plt.show()

# 可視化の実行
visualize_missing_patterns(df)



# 変数ごとの欠損値分布の可視化
def plot_missing_percentages(df):
    #plt.figure(figsize=(12, 6))
    
    # 欠損率の計算と可視化
    missing_percent = (df.isnull().sum() / len(df) * 100).sort_values(ascending=True)
    missing_percent[missing_percent > 0].plot(kind='barh')
    
    plt.title('変数ごとの欠損率')
    plt.xlabel('欠損率 (%)')
    plt.tight_layout()
    plt.show()

# 可視化の実行
plot_missing_percentages(df)


4. カテゴリー変数ごとの欠損率を可視化

def analyze_categorical_missing(df):
    """
    カテゴリー変数ごとの欠損率を可視化
    """
    # カテゴリー変数を抽出
    categorical_cols = df.select_dtypes(include=['object']).columns
    
    for col in categorical_cols:
        # カテゴリーごとの分布を可視化
        plt.figure(figsize=(10, 5))
        df[col].value_counts(dropna=False).plot(kind='bar')
        plt.title(f'{col}のカテゴリー別分布(欠損値含む)')
        plt.xlabel('カテゴリー')
        plt.ylabel('出現回数')
        plt.xticks(rotation=45)
        plt.tight_layout()
        plt.show()

# 分析の実行
analyze_categorical_missing(df)


5. 分析結果の解釈とアクション

欠損値分析の結果を基に、以下のような判断と対応を行います

  1. 欠損率の評価

    • 5%未満:リストワイズ削除を検討

    • 5-30%:代入法を検討

    • 30%以上:変数の除外を検討

  2. 欠損パターンの判断

    • MCARの場合:単純な代入法も検討可能

    • MARの場合:多重代入法や回帰代入を推奨

    • MNARの場合:欠損メカニズムのモデル化が必要

  3. 変数間の関係性

    • 強い相関がある場合:回帰代入や多重代入法が有効

    • 非線形な関係:決定木ベースの手法を検討


いいなと思ったら応援しよう!