#31 Pythonで実施する統計的検定、チャレンジ AI×100業務(製造業)
あるグループのデータ群の平均に差はあるのでしょうか?
平均値に差があるかどうかの検定に至るまでには、いくつかステップがあります。データは正規分布に従うのか?2群のデータのバラツキに有意性は認められるのか?などです。
今日は、チャレンジ#10、チャレンジ#11で実施した、t検定、F検定など、まとめて実施できるようにしてみました。
*それでは、スタートです。
*執筆者は以下を参照してください。
使ったツール・準備したこと
ChatGPT 4o
Visual Studio Code環境下でのPython
やってみたこと|コード・ステップ紹介
実行した内容の簡単な流れ
ChatGPT 4o;以下を会話しました。
アプリを生成してください。*Pythonで ・データは2群、n=30まで入力可能(エクセルからのコピペOK)
・正規性の検定を実施(表示はp値)
・F検定を実施(正規分布、非正規分布の場合両方)
・F検定で有意差がない場合;等分散を仮定としてt検定を実施(表示はp値)
・F検定で有意差がある場合;等分散を仮定としないt検定を実施(表示はp値)
・グラフは箱ひげ図も合わせて描画
以下が出力されます。グループ名を指定し、検定したいデータをコピペ、解析を実行すると、それぞれの検定量の表示と、箱ひげ図が描画されています。

今後の展開・アイデア
次回取り組みたいこと;
・生成AIと付き合う際の情報の管理
■ 統計学の参考書
*今回のコードは以下です。
import tkinter as tk
from tkinter import messagebox
from tkinter import scrolledtext
import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
plt.rcParams['font.family'] = 'Meiryo' # 日本語フォント
# データ解析関数
def parse_input(text):
try:
text = text.replace('\n', ',')
return [float(x.strip()) for x in text.split(',') if x.strip() != ''][:30]
except ValueError:
return []
def analyze():
group1 = parse_input(text1.get("1.0", tk.END))
group2 = parse_input(text2.get("1.0", tk.END))
label1 = group1_name.get().strip() or "Group1"
label2 = group2_name.get().strip() or "Group2"
if len(group1) < 2 or len(group2) < 2:
messagebox.showwarning("入力エラー", "各グループに最低2つの数値が必要です。")
return
result_text = ""
# 正規性検定
sw1 = stats.shapiro(group1)
sw2 = stats.shapiro(group2)
result_text += f"正規性検定 (Shapiro-Wilk):\n"
result_text += f" {label1} のp値: {sw1.pvalue:.4f} ({'正規分布' if sw1.pvalue > 0.05 else '非正規'})\n"
result_text += f" {label2} のp値: {sw2.pvalue:.4f} ({'正規分布' if sw2.pvalue > 0.05 else '非正規'})\n"
# F検定
f_stat = np.var(group1, ddof=1) / np.var(group2, ddof=1)
dfn = len(group1) - 1
dfd = len(group2) - 1
p_f = 2 * min(stats.f.cdf(f_stat, dfn, dfd), 1 - stats.f.cdf(f_stat, dfn, dfd))
result_text += f"\nF検定:\n F値: {f_stat:.4f}, p値: {p_f:.4f}\n"
# t検定
equal_var = p_f > 0.05
t_res = stats.ttest_ind(group1, group2, equal_var=equal_var)
result_text += f"\nt検定 ({'等分散仮定' if equal_var else '等分散仮定なし'}):\n p値: {t_res.pvalue:.4f}\n"
result_box.delete("1.0", tk.END)
result_box.insert(tk.END, result_text)
# 箱ひげ図描画
ax.clear()
bp = ax.boxplot([group1, group2], labels=[label1, label2], patch_artist=True)
means = [np.mean(group1), np.mean(group2)]
ax.plot([1, 2], means, 'r+', markersize=12, label='平均')
ax.set_title("箱ひげ図", fontsize=12)
ax.legend()
canvas.draw()
# GUI作成
root = tk.Tk()
root.title("2群比較ツール(tkinter版)")
frame = tk.Frame(root)
frame.pack(padx=10, pady=10)
# 名前入力
tk.Label(frame, text="グループ1名").grid(row=0, column=0)
group1_name = tk.Entry(frame, width=20)
group1_name.insert(0, "Group1")
group1_name.grid(row=0, column=1)
tk.Label(frame, text="グループ2名").grid(row=0, column=2)
group2_name = tk.Entry(frame, width=20)
group2_name.insert(0, "Group2")
group2_name.grid(row=0, column=3)
# データ入力欄
label1 = tk.Label(frame, text="グループ1データ")
label1.grid(row=1, column=0, columnspan=2)
text1 = scrolledtext.ScrolledText(frame, width=30, height=5)
text1.grid(row=2, column=0, columnspan=2, padx=5)
label2 = tk.Label(frame, text="グループ2データ")
label2.grid(row=1, column=2, columnspan=2)
text2 = scrolledtext.ScrolledText(frame, width=30, height=5)
text2.grid(row=2, column=2, columnspan=2, padx=5)
analyze_btn = tk.Button(frame, text="解析実行", command=analyze)
analyze_btn.grid(row=3, column=0, columnspan=4, pady=10)
result_box = scrolledtext.ScrolledText(root, width=70, height=10)
result_box.pack(padx=10, pady=5)
fig, ax = plt.subplots(figsize=(5, 4))
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().pack()
root.mainloop()
