サイトアイコン アマチュア無線局JS2IIU

【Streamlit】データの前処理、欠損値処理、外れ値処理

こんにちは、JS2IIUです。
今回はデータ分析に欠かせない、欠損値処理、外れ値除去などのデータクリーニング機能をStreamlit上に実装していきます。今回もよろしくお願いします。

1. はじめに

データ分析や機械学習を行う上で、「前処理」は欠かせないステップです。
生のデータには「欠損値」や「外れ値」が含まれていることが多く、そのままでは正しい分析ができません。

この記事では、Streamlitを使って、GUIから手軽に前処理ができるアプリを作成します。

2. Streamlitとは?

Streamlit は、Pythonで簡単にWebアプリを作れるライブラリです。
以下のような特徴があります。

この記事では、Streamlitを使って、欠損値処理や外れ値除去をボタン一つで行える前処理アプリを作っていきます。

3. データ前処理とは?

データ前処理にはいくつかのステップがありますが、今回は以下の2つにフォーカスします。

欠損値(NaN)の処理

外れ値の処理

4. サンプルデータの準備

まずは、前処理を試すためのサンプルデータを作成しましょう。

Python
import pandas as pd
import numpy as np

# サンプルデータ生成関数
def create_sample_data():
    np.random.seed(42)
    data = {
        "年齢": np.append(np.random.randint(20, 60, 18), [200, np.nan]),  # 外れ値と欠損値あり
        "収入": np.append(np.random.randint(300, 800, 18), [5000, np.nan]),  # 外れ値と欠損値あり
    }
    df = pd.DataFrame(data)
    return df

この関数を使って、Streamlitアプリ内で自動的にデータを生成します。
また、CSVファイルをアップロードして使う機能も後ほど追加します。

作成されるDataFrameデータは次のようなものです。

Plaintext
       年齢      収入
0    58.0   791.0
1    48.0   713.0
2    34.0   593.0
3    27.0   685.0
4    40.0   491.0
5    58.0   743.0
6    38.0   576.0
7    42.0   460.0
8    30.0   759.0
9    30.0   613.0
10   43.0   321.0
11   55.0   552.0
12   59.0   535.0
13   43.0   644.0
14   22.0   348.0
15   41.0   774.0
16   21.0   358.0
17   43.0   469.0
18  200.0  5000.0
19    NaN     NaN

5. Streamlitアプリの実装

🔧 必要なライブラリのインストール

まずは以下のライブラリをインストールしておきましょう。

Bash
pip install streamlit pandas numpy

5-1. アプリの基本構造

Python
import streamlit as st
import pandas as pd
import numpy as np

# サンプルデータ生成
def create_sample_data():
    np.random.seed(42)
    data = {
        "年齢": np.append(np.random.randint(20, 60, 18), [200, np.nan]),
        "収入": np.append(np.random.randint(300, 800, 18), [5000, np.nan]),
    }
    return pd.DataFrame(data)

st.title("📊 データ前処理アプリ")
st.write("欠損値処理・外れ値除去を簡単に体験してみましょう。")

# データの読み込み
uploaded_file = st.file_uploader("CSVファイルをアップロードしてください", type="csv")
if uploaded_file:
    df = pd.read_csv(uploaded_file)
    st.success("CSVファイルを読み込みました。")
else:
    st.info("CSVが未指定のため、サンプルデータを使用します。")
    df = create_sample_data()

st.subheader("📄 元のデータ")
st.dataframe(df)

✅ 1. ライブラリのインポート

Python
import streamlit as st
import pandas as pd
import numpy as np

✅ 2. サンプルデータの作成関数

Python
def create_sample_data():
    np.random.seed(42)
    data = {
        "年齢": np.append(np.random.randint(20, 60, 18), [200, np.nan]),
        "収入": np.append(np.random.randint(300, 800, 18), [5000, np.nan]),
    }
    return pd.DataFrame(data)

✅ 3. タイトルと説明の表示

Python
st.title("📊 データ前処理アプリ")
st.write("欠損値処理・外れ値除去を簡単に体験してみましょう。")

✅ 4. データの読み込み(ファイルアップロード)

Python
uploaded_file = st.file_uploader("CSVファイルをアップロードしてください", type="csv")
if uploaded_file:
    df = pd.read_csv(uploaded_file)
    st.success("CSVファイルを読み込みました。")
else:
    st.info("CSVが未指定のため、サンプルデータを使用します。")
    df = create_sample_data()

✅ 5. データの表示

st.subheader("📄 元のデータ")
st.dataframe(df)

5-2. 欠損値処理の実装

Bash
st.subheader("🧹 欠損値処理")

missing_summary = df.isnull().sum()
st.write("各列の欠損値数:")
st.write(missing_summary)

method = st.radio("欠損値の処理方法を選択してください", ["そのままにする", "行を削除", "平均値で補完", "中央値で補完"])

if method == "行を削除":
    df = df.dropna()
elif method == "平均値で補完":
    df = df.fillna(df.mean(numeric_only=True))
elif method == "中央値で補完":
    df = df.fillna(df.median(numeric_only=True))

st.write("欠損値処理後のデータ:")
st.dataframe(df)

✅ 1. 欠損値処理セクションのタイトル表示

Python
st.subheader("🧹 欠損値処理")

✅ 2. 欠損値の個数を確認

Python
missing_summary = df.isnull().sum()
st.write("各列の欠損値数:")
st.write(missing_summary)

✅ 3. 欠損値の処理方法をユーザーに選ばせる

Python
method = st.radio("欠損値の処理方法を選択してください", ["そのままにする", "行を削除", "平均値で補完", "中央値で補完"])

✅ 4. 選択に応じた処理の実行

Python
if method == "行を削除":
    df = df.dropna()
elif method == "平均値で補完":
    df = df.fillna(df.mean(numeric_only=True))
elif method == "中央値で補完":
    df = df.fillna(df.median(numeric_only=True))

✅ 5. 処理後のデータを表示

Python
st.write("欠損値処理後のデータ:")
st.dataframe(df)

5-3. 外れ値の処理

Python
st.subheader("🚫 外れ値除去")

def remove_outliers_iqr(dataframe):
    df_clean = dataframe.copy()
    for col in df_clean.select_dtypes(include=["number"]).columns:
        q1 = df_clean[col].quantile(0.25)
        q3 = df_clean[col].quantile(0.75)
        iqr = q3 - q1
        lower = q1 - 1.5 * iqr
        upper = q3 + 1.5 * iqr
        df_clean = df_clean[(df_clean[col] >= lower) & (df_clean[col] <= upper)]
    return df_clean

if st.button("外れ値を除去する(IQR)"):
    df = remove_outliers_iqr(df)
    st.success("外れ値を除去しました。")

st.write("外れ値処理後のデータ:")
st.dataframe(df)

✅ 1. セクションの見出し表示

st.subheader("🚫 外れ値除去")

✅ 2. 外れ値を除去する関数の定義(IQR法)

def remove_outliers_iqr(dataframe):
    df_clean = dataframe.copy()
    for col in df_clean.select_dtypes(include=["number"]).columns:
        q1 = df_clean[col].quantile(0.25)
        q3 = df_clean[col].quantile(0.75)
        iqr = q3 - q1
        lower = q1 - 1.5 * iqr
        upper = q3 + 1.5 * iqr
        df_clean = df_clean[(df_clean[col] >= lower) &amp; (df_clean[col] &lt;= upper)]
    return df_clean
🔍 何をしているのか?

この関数は、IQR(四分位範囲) を使って数値データの外れ値を除去します。

🔢 手順の流れ:

✅ 3. ボタンを押したら外れ値を除去

if st.button("外れ値を除去する(IQR)"):
    df = remove_outliers_iqr(df)
    st.success("外れ値を除去しました。")

✅ 4. 外れ値処理後のデータを表示

st.write("外れ値処理後のデータ:")
st.dataframe(df)

🔍 IQR法とは?

IQR(Interquartile Range:四分位範囲) を使って、統計的に“外れた値”を見つけて除外する方法です。

💡 そもそも「四分位数」とは?

データを小さい順に並べて、以下の位置で分割します:

🔢 IQRの計算方法
IQR = Q3 - Q1
🚫 外れ値の定義(IQRルール)

IQRの上下に1.5倍分の幅をとって、それを超える値を「外れ値」と見なします。

下限値 = Q1 - 1.5 × IQR
上限値 = Q3 + 1.5 × IQR
✅ 具体例

たとえば次のようなデータがあったとします:

[10, 12, 13, 15, 18, 19, 21, 22, 200]

計算:

この範囲(1〜33)を超える値 は外れ値 → 200 が外れ値!

✅ なぜIQR法が使われる?
🛠️ 実用面での特徴
特徴内容
メリット簡単で視覚的にわかりやすい、極端な値に強い
デメリット分布の形状を考慮しない、正規分布でないとやや不正確なことも

5-4. CSVとしてダウンロード

Python
st.subheader("💾 処理済みデータのダウンロード")

csv = df.to_csv(index=False).encode("utf-8")
st.download_button(
    label="CSVファイルとしてダウンロード",
    data=csv,
    file_name="cleaned_data.csv",
    mime="text/csv",
)

6. アプリ全体のコード

すべてのコードを1つにまとめると、以下のようになります:

Python
import streamlit as st
import pandas as pd
import numpy as np

# サンプルデータ生成
def create_sample_data():
    np.random.seed(42)
    data = {
        "年齢": np.append(np.random.randint(20, 60, 18), [200, np.nan]),
        "収入": np.append(np.random.randint(300, 800, 18), [5000, np.nan]),
    }
    return pd.DataFrame(data)

st.title("📊 データ前処理アプリ")
st.write("欠損値処理・外れ値除去を簡単に体験してみましょう。")

# データの読み込み
uploaded_file = st.file_uploader("CSVファイルをアップロードしてください", type="csv")
if uploaded_file:
    df = pd.read_csv(uploaded_file)
    st.success("CSVファイルを読み込みました。")
else:
    st.info("CSVが未指定のため、サンプルデータを使用します。")
    df = create_sample_data()

st.subheader("📄 元のデータ")
st.dataframe(df)

st.subheader("🧹 欠損値処理")

missing_summary = df.isnull().sum()
st.write("各列の欠損値数:")
st.write(missing_summary)

method = st.radio("欠損値の処理方法を選択してください", ["そのままにする", "行を削除", "平均値で補完", "中央値で補完"])

if method == "行を削除":
    df = df.dropna()
elif method == "平均値で補完":
    df = df.fillna(df.mean(numeric_only=True))
elif method == "中央値で補完":
    df = df.fillna(df.median(numeric_only=True))

st.write("欠損値処理後のデータ:")
st.dataframe(df)

st.subheader("🚫 外れ値除去")

def remove_outliers_iqr(dataframe):
    df_clean = dataframe.copy()
    for col in df_clean.select_dtypes(include=["number"]).columns:
        q1 = df_clean[col].quantile(0.25)
        q3 = df_clean[col].quantile(0.75)
        iqr = q3 - q1
        lower = q1 - 1.5 * iqr
        upper = q3 + 1.5 * iqr
        df_clean = df_clean[(df_clean[col] >= lower) & (df_clean[col] <= upper)]
    return df_clean

if st.button("外れ値を除去する(IQR)"):
    df = remove_outliers_iqr(df)
    st.success("外れ値を除去しました。")

st.write("外れ値処理後のデータ:")
st.dataframe(df)

st.subheader("💾 処理済みデータのダウンロード")

csv = df.to_csv(index=False).encode("utf-8")
st.download_button(
    label="CSVファイルとしてダウンロード",
    data=csv,
    file_name="cleaned_data.csv",
    mime="text/csv",
)

7. おわりに

このアプリを使えば、Pythonやデータ分析が初めての方でも、視覚的にデータの問題点を確認しながら、前処理を行うことができます

今後は、以下のような機能の追加もおすすめです:

8. 参考リンク

最後に書籍のPRです。
24年11月に第3版が発行された「scikit-learn、Keras、TensorFlowによる実践機械学習 第3版」、Aurélien Géron 著。下田、牧、長尾訳。機械学習のトピックスについて手を動かしながら網羅的に学べる書籍です。ぜひ手に取ってみてください。

最後まで読んでいただきありがとうございます。

モバイルバージョンを終了