見出し画像

#43 Python+GPTでつくる統計解析アプリ(ANOVA)、チャレンジ AI×100業務(製造業)

前回の記事(#42 Python+GPTでつくる統計解析Webアプリ;正規性検定→F検定→t検定)では、正規性検定→F検定→t検定をまとめて描画するとともに、データをcsvファイルからよみとり、任意の2群の検定を実施するものとしました。

今日は、上記のANOVA編です。


*それでは、スタートです。
*執筆者は以下を参照してください。


使ったツール・準備したこと

  • Visual Studio Code環境下でのPython

  • ChatGPT

やってみたこと|コード・ステップ紹介

実行した内容の簡単な流れ

ChatGPTに次の会話をしました。

多群(3群以上)のANOVA検定対応版を生成してください。

入力したプロンプト

Tukeyの多重比較や非パラメトリック検定(Kruskall-Wallis)への拡張願います。

会話が進んでいった際の追加の要望

■ 下のグラフが描画されました。

p値からバラツキに有意性はなく、平均値では有意性が認められます。

箱ひげ図と合わせるとわかりやすいですね。

今後の展開・アイデア

次回取り組みたいこと;

・回帰分析を予定しています。


■ 今日のコード

import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import pandas as pd
import numpy as np
import scipy.stats as stats
from statsmodels.stats.multicomp import pairwise_tukeyhsd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

plt.rcParams['font.family'] = 'Meiryo'  # 日本語フォント

df = None  # グローバル変数でDataFrameを保持

def load_csv():
    global df
    filepath = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
    if not filepath:
        return
    try:
        df = pd.read_csv(filepath, encoding='cp932')
        if df.shape[1] < 2:
            messagebox.showerror("エラー", "CSVファイルには少なくとも2列必要です。")
            return

        # チェックボックス用の因子列を再構成
        for widget in checkbox_frame.winfo_children():
            widget.destroy()

        var_dict.clear()
        for col in df.columns:
            var = tk.BooleanVar()
            chk = tk.Checkbutton(checkbox_frame, text=col, variable=var)
            chk.pack(anchor='w')
            var_dict[col] = var

    except Exception as e:
        messagebox.showerror("読み込みエラー", f"CSVの読み込みに失敗しました: {e}")

def run_anova():
    global df
    if df is None:
        messagebox.showwarning("警告", "先にCSVファイルを読み込んでください。")
        return

    selected_cols = [col for col, var in var_dict.items() if var.get()]
    if len(selected_cols) < 2:
        messagebox.showwarning("警告", "2群以上の列を選択してください。")
        return

    try:
        data = [df[col].dropna().astype(float).tolist()[:30] for col in selected_cols]
        result_text = "多群比較(ANOVA + Kruskal-Wallis + Tukey)\n\n"

        # 正規性検定
        for i, col in enumerate(selected_cols):
            sw = stats.shapiro(data[i])
            result_text += f"{col} の正規性検定 p値: {sw.pvalue:.4f} ({'正規分布' if sw.pvalue > 0.05 else '非正規'})\n"

        # 等分散性検定(バートレット)
        bart_p = stats.bartlett(*data).pvalue
        result_text += f"\nバートレット検定(等分散性)p値: {bart_p:.4f}\n"

        # ANOVA検定
        anova = stats.f_oneway(*data)
        result_text += f"\n一元配置分散分析(ANOVA)結果: F値={anova.statistic:.4f}, p値={anova.pvalue:.4f}\n"

        # Kruskal-Wallis検定(非正規性・非等分散性対応)
        kw = stats.kruskal(*data)
        result_text += f"Kruskal-Wallis検定(ノンパラメトリック): H値={kw.statistic:.4f}, p値={kw.pvalue:.4f}\n"

        # Tukey HSD(ANOVAが有意なとき)
        melted_df = pd.DataFrame({"値": [], "群": []})
        for i, col in enumerate(selected_cols):
            temp = pd.DataFrame({"値": data[i], "群": [col] * len(data[i])})
            melted_df = pd.concat([melted_df, temp], ignore_index=True)

        tukey_result = pairwise_tukeyhsd(endog=melted_df["値"], groups=melted_df["群"], alpha=0.05)
        result_text += f"\nTukeyの多重比較結果:\n{tukey_result}\n"

        result_box.delete("1.0", tk.END)
        result_box.insert(tk.END, result_text)

        # 箱ひげ図
        ax.clear()
        ax.boxplot(data, labels=selected_cols, patch_artist=True)
        means = [np.mean(d) for d in data]
        ax.plot(range(1, len(data) + 1), means, 'r+', markersize=12, label='平均')
        ax.set_title("箱ひげ図(多群)", fontsize=12)
        ax.legend()
        canvas.draw()

    except Exception as e:
        messagebox.showerror("解析エラー", f"解析に失敗しました: {e}")

# GUI作成
root = tk.Tk()
root.title("多群比較ツール(ANOVA + Tukey + Kruskal-Wallis 対応)")

frame = tk.Frame(root)
frame.pack(padx=10, pady=10)

load_btn = tk.Button(frame, text="CSVファイル読込", command=load_csv)
load_btn.pack(pady=5)

checkbox_frame = tk.LabelFrame(root, text="比較対象列の選択(2群以上)")
checkbox_frame.pack(fill="both", padx=10, pady=5)

var_dict = {}  # 選択された列を保持

run_btn = tk.Button(root, text="解析実行(ANOVA)", command=run_anova)
run_btn.pack(pady=10)

result_box = tk.Text(root, width=90, height=20)
result_box.pack(padx=10, pady=5)

fig, ax = plt.subplots(figsize=(7, 5))
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().pack()

root.mainloop()


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