見出し画像

制作物#3 CSVの外れ値探索


1.概要

本システムは、指定されたCSVファイル内の数値データに対して複数の外れ値検出方法を適用し、検出された外れ値の情報をCSVファイルに保存する。また、各外れ値検出方法の結果を視覚化し、結果の分析を容易にすることを目的としています。

2.使用言語

Python

3.使用ライブラリ

  • pandas:データフレームの操作

  • numpy:数値計算

  • matplotlib:データの可視化

  • scipy:統計計算

  • sklearn.ensemble.IsolationForest:Isolation Forestによる外れ値検出

  • sklearn.neighbors.LocalOutlierFactor:LOF(Local Outlier Factor)による外れ値検出

4.機能概要

  1. CSVファイルの読み込み

    • CSVファイルからデータを読み込み、指定されたカラムに対して外れ値検出を行います。

    • 読み込むファイルはユーザーが指定します。

  2. 外れ値検出

    • 指定された複数のカラムに対して、以下の外れ値検出方法を適用します。

      1. IQR方式:四分位範囲を用いた方法

      2. Zスコア方式:標準偏差を基にした方法

      3. MAD方式:中央値からの偏差を用いた方法

      4. Isolation Forest方式:機械学習アルゴリズムを用いた方法

      5. LOF方式:局所的な密度に基づく方法

  3. データの可視化

    • 各外れ値検出方法に基づいて、以下の形式でデータを可視化します。

      1. IQR方式:箱ひげ図

      2. Zスコア方式:散布図

      3. MAD方式:散布図

      4. Isolation Forest方式:散布図

      5. LOF方式:散布図

    • 可視化は、異常値の分布を理解しやすくするために色分けが行われます。

  4. 外れ値結果の保存

    • 各カラムに対する外れ値検出の結果をCSVファイルとして保存します。

    • 出力ファイルには、データのNo、データ収集日、検出された外れ値の値、使用した検出方法が含まれます。

    • 保存場所とファイル名はユーザーが指定します。

5.入力

  1. CSVファイル

    • 外れ値を検出したいデータが格納されたCSVファイル。

    • ファイル内の各カラムに数値データが含まれている必要があります。

  2. ターゲットカラム

    • 外れ値を検出したいカラム名をリスト形式で指定します。

6.出力

  1. 外れ値検出結果

    • 各ターゲットカラムに対して外れ値検出結果をCSVファイルに保存します。

    • ファイル名は次の形式で指定されます:outliers_detection_results_カラム名.csv

  2. 可視化グラフ

    • 外れ値検出結果に基づく各検出方法のグラフが生成され、画面に表示されます。

7.エラー処理

  1. 数値データ以外のカラム指定エラー

    • 数値データではないカラムを指定した場合、該当するカラムに対して処理が行われず、次のカラムに進むように設計されています。

  2. ファイル読み込みエラー

    • 指定されたファイルが存在しない場合や、読み込みに失敗した場合、エラーメッセージを表示し処理を停止します。

8.要求されるシステム要件

  • Python 3.8以上

  • pandas, numpy, matplotlib, scipy, sklearnの各ライブラリがインストールされていること

9.コード

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from sklearn.ensemble import IsolationForest
from sklearn.neighbors import LocalOutlierFactor

# 1. CSVファイルを読み込みます
df = pd.read_csv('外れ値を算出したいCSVファイル.csv')

# 2. 外れ値を検出するカラムを指定します(複数可)
target_columns = ['Colum1', 'Colum2', 'Colum3']  # ここに検出したいカラム名を指定してください

for target_column in target_columns:
    # 3. 出力用のリストを初期化します
    outliers_list = []

    # 4. 指定したカラムに対して外れ値検出を行います
    if pd.api.types.is_numeric_dtype(df[target_column]):  # 数値データのみ処理

        # 4-1. IQR方式
        # IQRを計算し、1.5倍の範囲外のデータポイントを外れ値として検出
        Q1 = df[target_column].quantile(0.25) # 第1四分位数(25パーセンタイル)
        Q3 = df[target_column].quantile(0.75) # 第3四分位数(75パーセンタイル)
        IQR = Q3 - Q1                         # IQR(Interquartile Range)の計算
        lower_bound = Q1 - 1.5 * IQR          # 外れ値の下限
        upper_bound = Q3 + 1.5 * IQR          #外れ値の上限
        iqr_outliers = df[(df[target_column] < lower_bound) | (df[target_column] > upper_bound)]
        for idx in iqr_outliers.index:
            outliers_list.append([df.loc[idx, 'No'], df.loc[idx, 'Data collection date'], df.loc[idx, target_column], 'IQR'])

        # 4-2. Zスコア方式 (Z-Score)
        # 各データポイントのZスコアを計算し、絶対値が3を超えるデータポイントを外れ値として検出します。
        z_scores = np.abs(stats.zscore(df[target_column].dropna()))  # Zスコアの計算
        z_scores = pd.Series(z_scores, index=df[target_column].dropna().index)  # インデックスを保持してZスコアをシリーズ化
        zscore_outliers = df[target_column][df[target_column].index.isin(z_scores[z_scores > 3].index)]  # Zスコアが3を超えるデータを外れ値として抽出
        zscore_colors = pd.Series(0.0, index=df.index)  # カラーマッピング用のシリーズをfloat64で初期化
        zscore_colors.loc[z_scores.index] = (z_scores > 3).astype(float)  # Zスコアが3を超える箇所を色分け
        for idx in zscore_outliers.index:
            outliers_list.append([df.loc[idx, 'No'], df.loc[idx, 'Data collection date'], df.loc[idx, target_column], 'Z-Score'])

        # 4-3. MAD方式
        # 中央値からの偏差の絶対値の中央値(MAD)を使用して外れ値を検出します。
        median = df[target_column].median()  # 中央値の計算
        mad = np.median(np.abs(df[target_column] - median))  # 中央絶対偏差(MAD)の計算
        if mad == 0:  # MADが0の場合、非常に小さい値を設定
            mad = np.finfo(float).eps
        modified_z_scores = 0.6745 * (df[target_column] - median) / mad  # 修正Zスコアの計算
        mad_outliers = df[target_column][np.abs(modified_z_scores) > 3.5]  # 修正Zスコアが3.5を超えるデータを外れ値として検出
        for idx in mad_outliers.index:
            outliers_list.append([df.loc[idx, 'No'], df.loc[idx, 'Data collection date'], df.loc[idx, target_column], 'MAD'])

        # 4-4. Isolation Forest方式
        # 木を用いた機械学習アルゴリズムであるIsolation Forestを使って外れ値を検出します。
        iso_forest = IsolationForest(contamination=0.05)  # Isolation Forestモデルのインスタンス化、汚染率0.05
        df_subset = df[[target_column]].dropna()  # 欠損値を除いたサブセットを作成
        anomaly_iso = iso_forest.fit_predict(df_subset)  # モデルの適用と異常値の検出
        df['anomaly_iso'] = np.nan  # 新しいカラムを初期化
        df.loc[df_subset.index, 'anomaly_iso'] = anomaly_iso  # 検出結果を元のデータフレームに配置
        iso_forest_outliers = df[df['anomaly_iso'] == -1][target_column]  # 異常値として検出されたデータを抽出
        for idx in iso_forest_outliers.index:
            outliers_list.append([df.loc[idx, 'No'], df.loc[idx, 'Data collection date'], df.loc[idx, target_column], 'Isolation Forest'])
        
        # 4-5. LOF方式
        # 各データポイントが属する局所的な密度に基づいて外れ値を検出します。
        lof = LocalOutlierFactor(n_neighbors=20)  # LOFモデルのインスタンス化、近傍数20
        anomaly_lof = lof.fit_predict(df_subset)  # モデルの適用と異常値の検出
        df['anomaly_lof'] = np.nan  # 新しいカラムを初期化
        df.loc[df_subset.index, 'anomaly_lof'] = anomaly_lof  # 検出結果を元のデータフレームに配置
        lof_outliers = df[df['anomaly_lof'] == -1][target_column]  # 異常値として検出されたデータを抽出
        for idx in lof_outliers.index:
            outliers_list.append([df.loc[idx, 'No'], df.loc[idx, 'Data collection date'], df.loc[idx, target_column], 'LOF'])

    # 5. データのプロット設定
    plt.figure(figsize=(14, 10))

    # 6. データの可視化

    # 6-1. IQR方式 - 箱ひげ図
    plt.subplot(3, 2, 1)
    plt.boxplot(df[target_column].dropna())
    plt.title(f'IQR - Box Plot ({target_column})')
    plt.xlabel(target_column)
    plt.ylabel('Values')

    # 6-2. Zスコア方式 - 散布図
    plt.subplot(3, 2, 2)
    plt.scatter(df.index, df[target_column], c=zscore_colors, cmap='coolwarm', edgecolors='k')
    plt.title(f'Z-Score - Scatter Plot ({target_column})')
    plt.xlabel('Index')
    plt.ylabel(target_column)

    # 6-3. MAD方式 - 散布図
    median = df[target_column].median()
    mad = np.median(np.abs(df[target_column] - median))
    modified_z_scores = 0.6745 * (df[target_column] - median) / mad
    mad_colors = pd.Series(0.0, index=df.index)  # float64で初期化
    mad_colors.loc[df.index] = (np.abs(modified_z_scores) > 3.5).astype(float)
    plt.subplot(3, 2, 3)
    plt.scatter(df.index, df[target_column], c=mad_colors, cmap='coolwarm', edgecolors='k')
    plt.title(f'MAD - Scatter Plot ({target_column})')
    plt.xlabel('Index')
    plt.ylabel(target_column)

    # 6-4. Isolation Forest方式 - 散布図
    plt.subplot(3, 2, 4)
    plt.scatter(df.index, df[target_column], c=(df['anomaly_iso'] == -1).astype(float), cmap='coolwarm', edgecolors='k')
    plt.title(f'Isolation Forest - Scatter Plot ({target_column})')
    plt.xlabel('Index')
    plt.ylabel(target_column)

    # 6-5. LOF方式 - 散布図
    plt.subplot(3, 2, 5)
    plt.scatter(df.index, df[target_column], c=(df['anomaly_lof'] == -1).astype(float), cmap='coolwarm', edgecolors='k')
    plt.title(f'LOF - Scatter Plot ({target_column})')
    plt.xlabel('Index')
    plt.ylabel(target_column)

    plt.tight_layout()
    plt.show()

    # 7. 外れ値の結果をCSVに書き出します
    outliers_df = pd.DataFrame(outliers_list, columns=['No', 'Data collection date', target_column, 'Outlier Reason'])
    output_file = f'格納先フォルダー名/X.外れ値/outliers_detection_results_{target_column}.csv' #保存先とファイル名を指定
    outliers_df.to_csv(output_file, index=False)

    print(f"外れ値の結果が保存されました: {output_file}")

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