Wen1201 commited on
Commit
0010b2e
·
verified ·
1 Parent(s): 0035c48

Delete app_bayesian.py.py

Browse files
Files changed (1) hide show
  1. app_bayesian.py.py +0 -654
app_bayesian.py.py DELETED
@@ -1,654 +0,0 @@
1
- import streamlit as st
2
- import pandas as pd
3
- import uuid
4
- from datetime import datetime, timedelta
5
- import atexit
6
- import os
7
- import sys
8
-
9
- # 頁面配置
10
- st.set_page_config(
11
- page_title="Bayesian Hierarchical Model - Pokémon Speed Analysis",
12
- page_icon="🎲",
13
- layout="wide",
14
- initial_sidebar_state="expanded"
15
- )
16
-
17
- # 自定義 CSS
18
- st.markdown("""
19
- <style>
20
- .streamlit-expanderHeader {
21
- background-color: #e8f1f8;
22
- border: 1px solid #b0cfe8;
23
- border-radius: 5px;
24
- font-weight: 600;
25
- color: #1b4f72;
26
- }
27
- .streamlit-expanderHeader:hover {
28
- background-color: #d0e7f8;
29
- }
30
- .stMetric {
31
- background-color: #f8fbff;
32
- padding: 10px;
33
- border-radius: 5px;
34
- border: 1px solid #d0e4f5;
35
- }
36
- .stButton > button {
37
- width: 100%;
38
- border-radius: 20px;
39
- font-weight: 600;
40
- transition: all 0.3s ease;
41
- }
42
- .stButton > button:hover {
43
- transform: translateY(-2px);
44
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
45
- }
46
- .success-box {
47
- background-color: #d4edda;
48
- border: 1px solid #c3e6cb;
49
- border-radius: 5px;
50
- padding: 10px;
51
- margin: 10px 0;
52
- }
53
- .warning-box {
54
- background-color: #fff3cd;
55
- border: 1px solid #ffeaa7;
56
- border-radius: 5px;
57
- padding: 10px;
58
- margin: 10px 0;
59
- }
60
- </style>
61
- """, unsafe_allow_html=True)
62
-
63
- # 導入自定義模組
64
- from bayesian_core import BayesianHierarchicalAnalyzer
65
- from bayesian_llm_assistant import BayesianLLMAssistant
66
- from bayesian_utils import (
67
- plot_trace,
68
- plot_posterior,
69
- plot_forest,
70
- plot_model_dag,
71
- create_summary_table,
72
- create_trial_results_table,
73
- export_results_to_text,
74
- plot_odds_ratio_comparison
75
- )
76
-
77
- # 清理函數
78
- def cleanup_old_sessions():
79
- """清理超過 1 小時的 session"""
80
- current_time = datetime.now()
81
- for session_id in list(BayesianHierarchicalAnalyzer._session_results.keys()):
82
- result = BayesianHierarchicalAnalyzer._session_results.get(session_id)
83
- if result:
84
- result_time = datetime.fromisoformat(result['timestamp'])
85
- if current_time - result_time > timedelta(hours=1):
86
- BayesianHierarchicalAnalyzer.clear_session_results(session_id)
87
-
88
- # 註冊清理函數
89
- atexit.register(cleanup_old_sessions)
90
-
91
- # 初始化 session state
92
- if 'session_id' not in st.session_state:
93
- st.session_state.session_id = str(uuid.uuid4())
94
- if 'analysis_results' not in st.session_state:
95
- st.session_state.analysis_results = None
96
- if 'chat_history' not in st.session_state:
97
- st.session_state.chat_history = []
98
- if 'analyzer' not in st.session_state:
99
- st.session_state.analyzer = None
100
- if 'trace_img' not in st.session_state:
101
- st.session_state.trace_img = None
102
- if 'posterior_img' not in st.session_state:
103
- st.session_state.posterior_img = None
104
- if 'forest_img' not in st.session_state:
105
- st.session_state.forest_img = None
106
- if 'dag_img' not in st.session_state:
107
- st.session_state.dag_img = None
108
-
109
- # 標題
110
- st.title("🎲 Bayesian Hierarchical Model Analysis")
111
- st.markdown("### 寶可夢速度對勝率影響的貝氏階層分析")
112
- st.markdown("---")
113
-
114
- # Sidebar
115
- with st.sidebar:
116
- st.header("⚙️ 配置設定")
117
-
118
- # Google Gemini API Key
119
- api_key = st.text_input(
120
- "Google Gemini API Key",
121
- type="password",
122
- help="輸入您的 Google Gemini API Key 以使用 AI 助手"
123
- )
124
-
125
- if api_key:
126
- st.session_state.api_key = api_key
127
- st.success("✅ API Key 已載入")
128
-
129
- st.markdown("---")
130
-
131
- # MCMC 參數設定
132
- st.subheader("🔬 MCMC 參數")
133
-
134
- n_samples = st.number_input(
135
- "抽樣數 (Samples)",
136
- min_value=500,
137
- max_value=10000,
138
- value=2000,
139
- step=500,
140
- help="每條鏈的抽樣數量"
141
- )
142
-
143
- n_tune = st.number_input(
144
- "調整期 (Tune)",
145
- min_value=200,
146
- max_value=5000,
147
- value=1000,
148
- step=200,
149
- help="調整期的樣本數"
150
- )
151
-
152
- n_chains = st.selectbox(
153
- "鏈數 (Chains)",
154
- options=[1, 2, 4],
155
- index=1,
156
- help="平行運行的鏈數"
157
- )
158
-
159
- target_accept = st.slider(
160
- "目標接受率",
161
- min_value=0.80,
162
- max_value=0.99,
163
- value=0.95,
164
- step=0.01,
165
- help="NUTS 採樣器的目標接受率"
166
- )
167
-
168
- st.markdown("---")
169
-
170
- # 清理按鈕
171
- if st.button("🧹 清理過期資料"):
172
- cleanup_old_sessions()
173
- st.success("✅ 清理完成")
174
- st.rerun()
175
-
176
- st.markdown("---")
177
-
178
- # 資料來源選擇
179
- st.subheader("📊 資料來源")
180
- data_source = st.radio(
181
- "選擇資料來源:",
182
- ["使用預設資料集", "上傳您的資料"]
183
- )
184
-
185
- uploaded_file = None
186
- if data_source == "上傳您的資料":
187
- uploaded_file = st.file_uploader(
188
- "上傳 CSV 檔案",
189
- type=['csv'],
190
- help="上傳寶可夢速度對戰資料"
191
- )
192
-
193
- with st.expander("📖 資料格式說明"):
194
- st.markdown("""
195
- **必要欄位格式:**
196
- - `Trial_Type`: 屬性名稱(例如:Water, Fire, Grass)
197
- - `rc`: 控制組(速度慢)的勝場數
198
- - `nc`: 控制組的總場數
199
- - `rt`: 實驗組(速度快)的勝場數
200
- - `nt`: 實驗組的總場數
201
-
202
- **範例:**
203
- ```
204
- Trial_Type,rc,nc,rt,nt
205
- Water,45,100,62,100
206
- Fire,38,100,55,100
207
- Grass,42,100,58,100
208
- ```
209
- """)
210
-
211
- st.markdown("---")
212
-
213
- # 關於系統
214
- with st.expander("ℹ️ 關於此系統"):
215
- st.markdown("""
216
- **貝氏階層模型分析系統**
217
-
218
- 本系統使用貝氏階層模型來分析速度對寶可夢勝率的影響,
219
- 並考慮不同屬性之間的異質性。
220
-
221
- **主要功能:**
222
- - 🎲 貝氏推論與後驗分佈
223
- - 📊 階層模型(借用資訊)
224
- - 📈 4 種視覺化圖表
225
- - 💬 AI 助手解釋
226
- - 🎮 對戰策略建議
227
-
228
- **適用場景:**
229
- - 分析速度對不同屬性的影響
230
- - 理解屬性間的異質性
231
- - 制定基於統計的對戰策略
232
- """)
233
-
234
- # 主要內容區 - 雙 Tab
235
- tab1, tab2 = st.tabs(["📊 貝氏分析", "💬 AI 助手"])
236
-
237
- # Tab 1: 貝氏分析
238
- with tab1:
239
- st.header("📊 貝氏階層模型分析")
240
-
241
- # 載入資料
242
- if data_source == "使用預設資料集":
243
- # 檢查預設資料是否存在
244
- default_data_path = "pokemon_speed_meta_results.csv"
245
- if os.path.exists(default_data_path):
246
- df = pd.read_csv(default_data_path)
247
- st.success(f"✅ 已載入預設資料集({len(df)} 個屬性)")
248
- else:
249
- st.warning("⚠️ 找不到預設資料集,請上傳您的資料")
250
- df = None
251
- else:
252
- if uploaded_file is not None:
253
- df = pd.read_csv(uploaded_file)
254
- st.success(f"✅ 已載入資料({len(df)} 個屬性)")
255
- else:
256
- df = None
257
- st.info("📁 請在左側上傳 CSV 檔案")
258
-
259
- if df is not None:
260
- # 顯示資料預覽
261
- with st.expander("👀 資料預覽"):
262
- st.dataframe(df, use_container_width=True)
263
-
264
- st.markdown("---")
265
-
266
- # 分析按鈕
267
- col1, col2, col3 = st.columns([1, 2, 1])
268
-
269
- with col2:
270
- analyze_button = st.button(
271
- "🔬 開始貝氏分析",
272
- type="primary",
273
- use_container_width=True
274
- )
275
-
276
- # 執行分析
277
- if analyze_button:
278
- with st.spinner(f"正在執行貝氏分析... (抽樣 {n_samples} × {n_chains} 條鏈)"):
279
- try:
280
- # 初始化分析器
281
- if st.session_state.analyzer is None:
282
- st.session_state.analyzer = BayesianHierarchicalAnalyzer(st.session_state.session_id)
283
-
284
- # 載入資料
285
- st.session_state.analyzer.load_data(df)
286
-
287
- # 執行分析
288
- results = st.session_state.analyzer.run_analysis(
289
- n_samples=n_samples,
290
- n_tune=n_tune,
291
- n_chains=n_chains,
292
- target_accept=target_accept
293
- )
294
-
295
- st.session_state.analysis_results = results
296
-
297
- # 生成圖表
298
- with st.spinner("生成視覺化圖表..."):
299
- st.session_state.trace_img = plot_trace(st.session_state.analyzer.trace)
300
- st.session_state.posterior_img = plot_posterior(st.session_state.analyzer.trace)
301
- st.session_state.forest_img = plot_forest(
302
- st.session_state.analyzer.trace,
303
- results['trial_labels']
304
- )
305
- st.session_state.dag_img = plot_model_dag(st.session_state.analyzer)
306
-
307
- st.success("✅ 分析完成!")
308
- st.balloons()
309
-
310
- except Exception as e:
311
- st.error(f"❌ 分析失敗: {str(e)}")
312
-
313
- # 顯示結果
314
- if st.session_state.analysis_results is not None:
315
- results = st.session_state.analysis_results
316
-
317
- st.markdown("---")
318
- st.subheader("📊 分析結果")
319
-
320
- # 創建 4 個子頁面
321
- result_tabs = st.tabs([
322
- "📊 概覽",
323
- "📈 Trace & Posterior",
324
- "🌲 Forest Plot",
325
- "🔍 DAG 模型圖",
326
- "📋 詳細報告"
327
- ])
328
-
329
- # Tab: 概覽
330
- with result_tabs[0]:
331
- st.markdown("### 🎯 整體效應摘要")
332
-
333
- overall = results['overall']
334
- interp = results['interpretation']
335
-
336
- # 關鍵指標
337
- col1, col2, col3 = st.columns(3)
338
-
339
- with col1:
340
- st.metric(
341
- "d (整體效應)",
342
- f"{overall['d_mean']:.4f}",
343
- delta=f"HDI: [{overall['d_hdi_low']:.3f}, {overall['d_hdi_high']:.3f}]"
344
- )
345
-
346
- with col2:
347
- st.metric(
348
- "勝算比 (OR)",
349
- f"{overall['or_mean']:.3f}",
350
- delta=f"HDI: [{overall['or_hdi_low']:.3f}, {overall['or_hdi_high']:.3f}]"
351
- )
352
-
353
- with col3:
354
- st.metric(
355
- "sigma (異質性)",
356
- f"{overall['sigma_mean']:.4f}",
357
- delta=f"HDI: [{overall['sigma_hdi_low']:.3f}, {overall['sigma_hdi_high']:.3f}]"
358
- )
359
-
360
- st.markdown("---")
361
-
362
- # 結果解釋
363
- st.markdown("### 📖 結果解釋")
364
-
365
- st.info(f"""
366
- **整體效應**: {interp['overall_effect']}
367
-
368
- **顯著性**: {interp['overall_significance']}
369
-
370
- **效果大小**: {interp['effect_size']}
371
-
372
- **異質性**: {interp['heterogeneity']}
373
- """)
374
-
375
- st.markdown("---")
376
-
377
- # 收斂診斷
378
- st.markdown("### 🔍 模型收斂診斷")
379
-
380
- diag = results['diagnostics']
381
-
382
- col1, col2 = st.columns(2)
383
-
384
- with col1:
385
- st.markdown("**R-hat 診斷** (應 < 1.1):")
386
- if diag['rhat_d']:
387
- st.metric("R-hat (d)", f"{diag['rhat_d']:.4f}",
388
- delta="✓ 良好" if diag['rhat_d'] < 1.1 else "✗ 需改善")
389
- if diag['rhat_sigma']:
390
- st.metric("R-hat (sigma)", f"{diag['rhat_sigma']:.4f}",
391
- delta="✓ 良好" if diag['rhat_sigma'] < 1.1 else "✗ 需改善")
392
-
393
- with col2:
394
- st.markdown("**有效樣本數 (ESS)**:")
395
- if diag['ess_d']:
396
- st.metric("ESS (d)", f"{int(diag['ess_d'])}")
397
- if diag['ess_sigma']:
398
- st.metric("ESS (sigma)", f"{int(diag['ess_sigma'])}")
399
-
400
- if diag['converged']:
401
- st.success("✅ 模型已收斂,結果可信")
402
- else:
403
- st.warning("⚠️ 模型可能未完全收斂,建議增加抽樣數或鏈數")
404
-
405
- st.markdown("---")
406
-
407
- # 摘要表格
408
- st.markdown("### 📊 統計摘要表")
409
- summary_df = create_summary_table(results)
410
- st.dataframe(summary_df, use_container_width=True)
411
-
412
- st.markdown("---")
413
-
414
- # 各屬性結果
415
- st.markdown("### 🎮 各屬性詳細結果")
416
- trial_df = create_trial_results_table(results)
417
- st.dataframe(trial_df, use_container_width=True)
418
-
419
- st.markdown("---")
420
-
421
- # 勝算比比較圖
422
- st.markdown("### 📊 各屬性速度效應比較")
423
- or_fig = plot_odds_ratio_comparison(results)
424
- st.plotly_chart(or_fig, use_container_width=True)
425
-
426
- # Tab: Trace & Posterior
427
- with result_tabs[1]:
428
- st.markdown("### 📈 Trace Plot(收斂診斷)")
429
- st.markdown("""
430
- **Trace Plot 用途**:
431
- - 檢查 MCMC 抽樣是否收斂
432
- - 左圖:抽樣軌跡(應該像「毛毛蟲」)
433
- - 右圖:後驗分佈密度
434
- """)
435
-
436
- if st.session_state.trace_img:
437
- st.image(st.session_state.trace_img, use_column_width=True)
438
- else:
439
- st.info("請先執行分析以生成 Trace Plot")
440
-
441
- st.markdown("---")
442
-
443
- st.markdown("### 📊 Posterior Plot(後驗分佈)")
444
- st.markdown("""
445
- **Posterior Plot 用途**:
446
- - 顯示參數的後驗分佈
447
- - 包含 95% HDI(最高密度區間)
448
- - 顯示平均值
449
- """)
450
-
451
- if st.session_state.posterior_img:
452
- st.image(st.session_state.posterior_img, use_column_width=True)
453
- else:
454
- st.info("請先執行分析以生成 Posterior Plot")
455
-
456
- # Tab: Forest Plot
457
- with result_tabs[2]:
458
- st.markdown("### 🌲 Forest Plot(各屬性效應)")
459
- st.markdown("""
460
- **Forest Plot 用途**:
461
- - 顯示每個屬性的速度效應(delta)
462
- - 點:平均效應
463
- - 線:95% HDI
464
- - ★ 標記:顯著正效應(HDI 不包含 0)
465
- - ☆ 標記:顯著負效應
466
- """)
467
-
468
- if st.session_state.forest_img:
469
- st.image(st.session_state.forest_img, use_column_width=True)
470
- else:
471
- st.info("請先執行分析以生成 Forest Plot")
472
-
473
- # Tab: DAG 模型圖
474
- with result_tabs[3]:
475
- st.markdown("### 🔍 模型結構圖 (DAG)")
476
- st.markdown("""
477
- **DAG(有向無環圖)用途**:
478
- - 視覺化模型的階層結構
479
- - 顯示變數之間的依賴關係
480
- - 圓形/橢圓:隨機變數
481
- - 矩形:觀測資料
482
- - 菱形:推導變數
483
- """)
484
-
485
- if st.session_state.dag_img:
486
- st.image(st.session_state.dag_img, use_column_width=True)
487
- else:
488
- st.warning("⚠️ 無法生成 DAG 圖(可能需要安裝 Graphviz)")
489
- st.markdown("""
490
- **安裝 Graphviz:**
491
- - Windows: `choco install graphviz`
492
- - Mac: `brew install graphviz`
493
- - Ubuntu: `sudo apt-get install graphviz`
494
- """)
495
-
496
- # Tab: 詳細報告
497
- with result_tabs[4]:
498
- st.markdown("### 📋 完整分析報告")
499
-
500
- # 生成文字報告
501
- text_report = export_results_to_text(results)
502
-
503
- st.text_area(
504
- "報告內容",
505
- text_report,
506
- height=500
507
- )
508
-
509
- # 下載按鈕
510
- st.download_button(
511
- label="📥 下載完整報告 (.txt)",
512
- data=text_report,
513
- file_name=f"bayesian_report_{results['timestamp'][:10]}.txt",
514
- mime="text/plain"
515
- )
516
-
517
- # Tab 2: AI 助手
518
- with tab2:
519
- st.header("💬 AI 分析助手")
520
-
521
- if not st.session_state.get('api_key'):
522
- st.warning("⚠️ 請在左側輸入您的 Google Gemini API Key 以使用 AI 助手")
523
- elif st.session_state.analysis_results is None:
524
- st.info("ℹ️ 請先在「貝氏分析」頁面執行分析")
525
- else:
526
- # 初始化 LLM 助手
527
- if 'llm_assistant' not in st.session_state:
528
- st.session_state.llm_assistant = BayesianLLMAssistant(
529
- api_key=st.session_state.api_key,
530
- session_id=st.session_state.session_id
531
- )
532
-
533
- # 聊天容器
534
- chat_container = st.container()
535
-
536
- with chat_container:
537
- for message in st.session_state.chat_history:
538
- with st.chat_message(message["role"]):
539
- st.markdown(message["content"])
540
-
541
- # 使用者輸入
542
- if prompt := st.chat_input("詢問關於分析結果的任何問題..."):
543
- # 添加使用者訊息
544
- st.session_state.chat_history.append({
545
- "role": "user",
546
- "content": prompt
547
- })
548
-
549
- with st.chat_message("user"):
550
- st.markdown(prompt)
551
-
552
- # AI 回應
553
- with st.chat_message("assistant"):
554
- with st.spinner("思考中..."):
555
- try:
556
- response = st.session_state.llm_assistant.get_response(
557
- user_message=prompt,
558
- analysis_results=st.session_state.analysis_results
559
- )
560
- st.markdown(response)
561
- except Exception as e:
562
- error_msg = f"❌ 錯誤: {str(e)}\n\n請檢查 API key 或重新表達問題。"
563
- st.error(error_msg)
564
- response = error_msg
565
-
566
- # 添加助手回應
567
- st.session_state.chat_history.append({
568
- "role": "assistant",
569
- "content": response
570
- })
571
-
572
- st.markdown("---")
573
-
574
- # 快速問題按鈕
575
- st.subheader("💡 快速問題")
576
-
577
- quick_questions = [
578
- "📊 給我這次分析的總結",
579
- "🎯 解釋 d 和勝算比",
580
- "🔍 解釋 sigma(異質性)",
581
- "❓ 什麼是階層模型?",
582
- "🆚 貝氏 vs 頻率論",
583
- "⚔️ 對戰策略建議",
584
- "🎮 比較不同屬性"
585
- ]
586
-
587
- cols = st.columns(4)
588
- for idx, question in enumerate(quick_questions):
589
- col_idx = idx % 4
590
- if cols[col_idx].button(question, key=f"quick_{idx}"):
591
- # 根據問題選擇對應的方法
592
- if "總結" in question:
593
- response = st.session_state.llm_assistant.generate_summary(
594
- st.session_state.analysis_results
595
- )
596
- elif "d 和勝算比" in question:
597
- response = st.session_state.llm_assistant.explain_metric(
598
- 'd',
599
- st.session_state.analysis_results
600
- )
601
- elif "sigma" in question or "異質性" in question:
602
- response = st.session_state.llm_assistant.explain_metric(
603
- 'sigma',
604
- st.session_state.analysis_results
605
- )
606
- elif "階層模型" in question:
607
- response = st.session_state.llm_assistant.explain_hierarchical_model()
608
- elif "貝氏" in question and "頻率論" in question:
609
- response = st.session_state.llm_assistant.explain_bayesian_vs_frequentist()
610
- elif "策略" in question:
611
- response = st.session_state.llm_assistant.battle_strategy_advice(
612
- st.session_state.analysis_results
613
- )
614
- elif "比較" in question:
615
- response = st.session_state.llm_assistant.compare_types(
616
- st.session_state.analysis_results
617
- )
618
- else:
619
- response = st.session_state.llm_assistant.get_response(
620
- question,
621
- st.session_state.analysis_results
622
- )
623
-
624
- st.session_state.chat_history.append({
625
- "role": "user",
626
- "content": question
627
- })
628
-
629
- st.session_state.chat_history.append({
630
- "role": "assistant",
631
- "content": response
632
- })
633
-
634
- st.rerun()
635
-
636
- # 重置對話按鈕
637
- st.markdown("---")
638
- if st.button("🔄 重置對話"):
639
- st.session_state.llm_assistant.reset_conversation()
640
- st.session_state.chat_history = []
641
- st.success("✅ 對話已重置")
642
- st.rerun()
643
-
644
- # Footer
645
- st.markdown("---")
646
- st.markdown(
647
- f"""
648
- <div style='text-align: center'>
649
- <p>🎲 Bayesian Hierarchical Model Analysis for Pokémon Speed | Built with Streamlit & PyMC</p>
650
- <p>Session ID: {st.session_state.session_id[:8]} | Powered by Google Gemini 2.0 Flash</p>
651
- </div>
652
- """,
653
- unsafe_allow_html=True
654
- )