Upload 2 files
Browse files
app.py
CHANGED
@@ -11,10 +11,12 @@ import shap
|
|
11 |
from pycaret.regression import *
|
12 |
from sklearn.tree import plot_tree
|
13 |
from sklearn.inspection import permutation_importance
|
|
|
|
|
14 |
import matplotlib.font_manager as fm
|
15 |
|
16 |
# フォントファイルのパスを指定
|
17 |
-
font_path = 'ipaexg.ttf'
|
18 |
|
19 |
# フォントプロパティを作成
|
20 |
font_prop = fm.FontProperties(fname=font_path)
|
@@ -49,7 +51,7 @@ if 'model_configs' not in st.session_state:
|
|
49 |
|
50 |
# メインアプリケーション
|
51 |
st.title("easyAutoML(回帰)")
|
52 |
-
|
53 |
|
54 |
with st.expander("このアプリケーションについて", expanded=False):
|
55 |
st.markdown("""
|
@@ -93,15 +95,6 @@ with st.expander("このアプリケーションについて", expanded=False):
|
|
93 |
- トレーニング済みモデルのダウンロード
|
94 |
""")
|
95 |
|
96 |
-
st.markdown("### 💡 使用方法")
|
97 |
-
st.markdown("""
|
98 |
-
1. CSVまたはExcelファイルをアップロード
|
99 |
-
2. 予測したい目的変数を選択
|
100 |
-
3. モデルの比較と選択
|
101 |
-
4. 選択したモデルのチューニングと評価
|
102 |
-
5. 最終モデルの保存
|
103 |
-
""")
|
104 |
-
|
105 |
st.info("⚠️ 注意: データの前処理(欠損値の処理など)は自動的に行われますが、データの品質が結果に大きく影響します。")
|
106 |
|
107 |
# 1. データアップロード部分
|
@@ -196,9 +189,17 @@ if uploaded_file is not None:
|
|
196 |
st.session_state.model_configs['ignore_features'] = ignore_features
|
197 |
|
198 |
# データ処理オプション
|
199 |
-
col1, col2 = st.columns(
|
200 |
with col1:
|
201 |
remove_outliers = st.checkbox('外れ値を除去する', value=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
202 |
|
203 |
# モデル比較の実行
|
204 |
if st.button('モデルの比較を開始', use_container_width=True):
|
@@ -208,19 +209,23 @@ if uploaded_file is not None:
|
|
208 |
progress_bar = st.progress(0)
|
209 |
status_text = st.empty()
|
210 |
|
211 |
-
#
|
212 |
status_text.text("データの前処理を実行中...")
|
213 |
progress_bar.progress(20)
|
214 |
|
215 |
-
#
|
216 |
-
|
217 |
-
data
|
218 |
-
target
|
219 |
-
ignore_features
|
220 |
-
remove_outliers
|
221 |
-
session_id
|
222 |
-
verbose
|
223 |
-
|
|
|
|
|
|
|
|
|
224 |
|
225 |
# 特徴量の保存
|
226 |
X_train = get_config('X_train')
|
@@ -385,9 +390,7 @@ if uploaded_file is not None:
|
|
385 |
fig, ax = plt.subplots(figsize=(10, 6))
|
386 |
sns.barplot(data=importance_df, x='重要度', y='特徴量', ax=ax)
|
387 |
st.pyplot(fig)
|
388 |
-
# キャプションを追加
|
389 |
st.caption("**モデルが学習した結果、各特徴量が目的変数の予測にどれだけ寄与したかを示しています。重要度が高い特徴量ほど、モデルの予測に大きな影響を与えています。**")
|
390 |
-
# データフレームを表示
|
391 |
with st.expander("特徴量重要度データ", expanded=False):
|
392 |
st.dataframe(importance_df, use_container_width=True)
|
393 |
else:
|
@@ -399,16 +402,12 @@ if uploaded_file is not None:
|
|
399 |
st.write("SHAP値による特徴量重要度")
|
400 |
with st.spinner('SHAP値を計算中...'):
|
401 |
try:
|
402 |
-
# SHAP値の計算
|
403 |
explainer = shap.Explainer(model, X_train_transformed)
|
404 |
shap_values = explainer(X_train_transformed)
|
405 |
-
# SHAPサマリープロット
|
406 |
shap.summary_plot(shap_values, X_train_transformed, plot_type="bar", show=False)
|
407 |
st.pyplot(plt.gcf())
|
408 |
-
# キャプションを追加
|
409 |
st.caption("**SHAP値に基づく特徴量の重要度を示しています。各特徴量が予測結果に与える影響を定量的に評価できます。(青:正の影響 緑:負の影響)**")
|
410 |
plt.clf()
|
411 |
-
# SHAP値をデータフレームで表示
|
412 |
with st.expander("SHAP値データ", expanded=False):
|
413 |
shap_df = pd.DataFrame({
|
414 |
'特徴量': feature_names,
|
@@ -437,7 +436,6 @@ if uploaded_file is not None:
|
|
437 |
plot_model(model, plot='error', display_format="streamlit")
|
438 |
st.caption("予測値と実測値の差を示しています。誤差が小さいほど、モデルの予測精度が高いことを示します。")
|
439 |
|
440 |
-
# 追加の評価図を表示
|
441 |
col3, col4 = st.columns(2)
|
442 |
with col3:
|
443 |
st.write("学習曲線")
|
@@ -458,8 +456,6 @@ if uploaded_file is not None:
|
|
458 |
try:
|
459 |
with st.spinner('決定木を可視化中...'):
|
460 |
if selected_model == 'dt':
|
461 |
-
# 決定木モデルの場合、直接ツリーをプロット
|
462 |
-
# 図を描画
|
463 |
fig, ax = plt.subplots(figsize=(40, 20))
|
464 |
plot_tree(
|
465 |
model,
|
@@ -472,14 +468,10 @@ if uploaded_file is not None:
|
|
472 |
st.pyplot(fig)
|
473 |
st.caption("決定木の構造を表示しています。")
|
474 |
else:
|
475 |
-
# ランダムフォレストや勾配ブースティングなどの場合
|
476 |
from sklearn.metrics import mean_squared_error
|
477 |
-
|
478 |
-
# テストデータを取得
|
479 |
X_test_transformed = get_config('X_test_transformed')
|
480 |
y_test = get_config('y_test')
|
481 |
|
482 |
-
# 各決定木の性能を評価
|
483 |
if selected_model in ['rf', 'et']:
|
484 |
estimators = model.estimators_
|
485 |
elif selected_model == 'gbr':
|
@@ -511,10 +503,8 @@ if uploaded_file is not None:
|
|
511 |
best_score = mse
|
512 |
best_estimator_index = idx
|
513 |
|
514 |
-
# ベストなツリーを取得
|
515 |
if selected_model in ['rf', 'et', 'gbr']:
|
516 |
best_tree = estimators[best_estimator_index]
|
517 |
-
# 図を描画
|
518 |
fig, ax = plt.subplots(figsize=(40, 20))
|
519 |
plot_tree(
|
520 |
best_tree,
|
@@ -527,7 +517,6 @@ if uploaded_file is not None:
|
|
527 |
st.pyplot(fig)
|
528 |
st.caption(f"ベストな決定木(ツリー番号: {best_estimator_index})の構造を表示しています。")
|
529 |
elif selected_model == 'xgboost':
|
530 |
-
# xgboostの場合
|
531 |
import xgboost as xgb
|
532 |
booster = model.get_booster()
|
533 |
fig, ax = plt.subplots(figsize=(40, 20))
|
@@ -535,7 +524,6 @@ if uploaded_file is not None:
|
|
535 |
st.pyplot(fig)
|
536 |
st.caption(f"ベストな決定木(ツリー番号: {best_estimator_index})の構造を表示しています。")
|
537 |
elif selected_model == 'lightgbm':
|
538 |
-
# lightgbmの場合
|
539 |
import lightgbm as lgb
|
540 |
graph = lgb.create_tree_digraph(model, tree_index=best_estimator_index)
|
541 |
st.graphviz_chart(graph)
|
@@ -555,18 +543,15 @@ if uploaded_file is not None:
|
|
555 |
progress_bar = st.progress(0)
|
556 |
status_text = st.empty()
|
557 |
|
558 |
-
# モデルのファイナライズ
|
559 |
status_text.text("モデルをファイナライズ中...")
|
560 |
progress_bar.progress(30)
|
561 |
final_model = finalize_model(model)
|
562 |
|
563 |
-
# 最終評価
|
564 |
status_text.text("最終評価を実行中...")
|
565 |
progress_bar.progress(60)
|
566 |
predictions = predict_model(final_model)
|
567 |
final_scores = pull()
|
568 |
|
569 |
-
# 評価結果の表示
|
570 |
st.subheader("ファイナルモデルの評価結果")
|
571 |
col1, col2 = st.columns(2)
|
572 |
with col1:
|
@@ -576,19 +561,14 @@ if uploaded_file is not None:
|
|
576 |
st.write("ファイナライズ後の評価結果")
|
577 |
st.dataframe(final_scores, use_container_width=True)
|
578 |
|
579 |
-
|
580 |
-
# 目的変数の名前をモデルに保存
|
581 |
final_model.target_column = target_variable
|
582 |
|
583 |
-
# モデルの保存
|
584 |
status_text.text("モデルを保存中...")
|
585 |
progress_bar.progress(90)
|
586 |
model_name = f"{target_variable}_finalized_model"
|
587 |
|
588 |
-
# モデルの保存
|
589 |
save_model(final_model, model_name)
|
590 |
|
591 |
-
# モデルの読み込み
|
592 |
with open(f"{model_name}.pkl", 'rb') as f:
|
593 |
model_bytes = f.read()
|
594 |
|
@@ -611,5 +591,4 @@ if uploaded_file is not None:
|
|
611 |
st.error(f"予期せぬエラーが発生しました: {str(e)}")
|
612 |
|
613 |
# コピーライト情報
|
614 |
-
|
615 |
-
st.caption('© 2022-2024 Dit-Lab.(Daiki Ito). All Rights Reserved.')
|
|
|
11 |
from pycaret.regression import *
|
12 |
from sklearn.tree import plot_tree
|
13 |
from sklearn.inspection import permutation_importance
|
14 |
+
import common
|
15 |
+
|
16 |
import matplotlib.font_manager as fm
|
17 |
|
18 |
# フォントファイルのパスを指定
|
19 |
+
font_path = 'ipaexg.ttf'
|
20 |
|
21 |
# フォントプロパティを作成
|
22 |
font_prop = fm.FontProperties(fname=font_path)
|
|
|
51 |
|
52 |
# メインアプリケーション
|
53 |
st.title("easyAutoML(回帰)")
|
54 |
+
common.display_header()
|
55 |
|
56 |
with st.expander("このアプリケーションについて", expanded=False):
|
57 |
st.markdown("""
|
|
|
95 |
- トレーニング済みモデルのダウンロード
|
96 |
""")
|
97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
st.info("⚠️ 注意: データの前処理(欠損値の処理など)は自動的に行われますが、データの品質が結果に大きく影響します。")
|
99 |
|
100 |
# 1. データアップロード部分
|
|
|
189 |
st.session_state.model_configs['ignore_features'] = ignore_features
|
190 |
|
191 |
# データ処理オプション
|
192 |
+
col1, col2, col3 = st.columns(3)
|
193 |
with col1:
|
194 |
remove_outliers = st.checkbox('外れ値を除去する', value=False)
|
195 |
+
with col2:
|
196 |
+
pca_option = st.checkbox('PCAを適用する', value=False)
|
197 |
+
with col3:
|
198 |
+
if pca_option:
|
199 |
+
max_components = len(data.columns) - 1 # 目的変数を除く
|
200 |
+
pca_components = st.slider('主成分の数', min_value=1, max_value=max_components, value=min(10, max_components))
|
201 |
+
else:
|
202 |
+
pca_components = None
|
203 |
|
204 |
# モデル比較の実行
|
205 |
if st.button('モデルの比較を開始', use_container_width=True):
|
|
|
209 |
progress_bar = st.progress(0)
|
210 |
status_text = st.empty()
|
211 |
|
212 |
+
# データの前処理
|
213 |
status_text.text("データの前処理を実行中...")
|
214 |
progress_bar.progress(20)
|
215 |
|
216 |
+
# setup() に PCA 関連のパラメータを追加
|
217 |
+
setup_params = {
|
218 |
+
'data': data,
|
219 |
+
'target': target_variable,
|
220 |
+
'ignore_features': ignore_features,
|
221 |
+
'remove_outliers': remove_outliers,
|
222 |
+
'session_id': 123,
|
223 |
+
'verbose': False,
|
224 |
+
'pca': pca_option
|
225 |
+
}
|
226 |
+
if pca_option:
|
227 |
+
setup_params['pca_components'] = pca_components
|
228 |
+
setup_data = setup(**setup_params)
|
229 |
|
230 |
# 特徴量の保存
|
231 |
X_train = get_config('X_train')
|
|
|
390 |
fig, ax = plt.subplots(figsize=(10, 6))
|
391 |
sns.barplot(data=importance_df, x='重要度', y='特徴量', ax=ax)
|
392 |
st.pyplot(fig)
|
|
|
393 |
st.caption("**モデルが学習した結果、各特徴量が目的変数の予測にどれだけ寄与したかを示しています。重要度が高い特徴量ほど、モデルの予測に大きな影響を与えています。**")
|
|
|
394 |
with st.expander("特徴量重要度データ", expanded=False):
|
395 |
st.dataframe(importance_df, use_container_width=True)
|
396 |
else:
|
|
|
402 |
st.write("SHAP値による特徴量重要度")
|
403 |
with st.spinner('SHAP値を計算中...'):
|
404 |
try:
|
|
|
405 |
explainer = shap.Explainer(model, X_train_transformed)
|
406 |
shap_values = explainer(X_train_transformed)
|
|
|
407 |
shap.summary_plot(shap_values, X_train_transformed, plot_type="bar", show=False)
|
408 |
st.pyplot(plt.gcf())
|
|
|
409 |
st.caption("**SHAP値に基づく特徴量の重要度を示しています。各特徴量が予測結果に与える影響を定量的に評価できます。(青:正の影響 緑:負の影響)**")
|
410 |
plt.clf()
|
|
|
411 |
with st.expander("SHAP値データ", expanded=False):
|
412 |
shap_df = pd.DataFrame({
|
413 |
'特徴量': feature_names,
|
|
|
436 |
plot_model(model, plot='error', display_format="streamlit")
|
437 |
st.caption("予測値と実測値の差を示しています。誤差が小さいほど、モデルの予測精度が高いことを示します。")
|
438 |
|
|
|
439 |
col3, col4 = st.columns(2)
|
440 |
with col3:
|
441 |
st.write("学習曲線")
|
|
|
456 |
try:
|
457 |
with st.spinner('決定木を可視化中...'):
|
458 |
if selected_model == 'dt':
|
|
|
|
|
459 |
fig, ax = plt.subplots(figsize=(40, 20))
|
460 |
plot_tree(
|
461 |
model,
|
|
|
468 |
st.pyplot(fig)
|
469 |
st.caption("決定木の構造を表示しています。")
|
470 |
else:
|
|
|
471 |
from sklearn.metrics import mean_squared_error
|
|
|
|
|
472 |
X_test_transformed = get_config('X_test_transformed')
|
473 |
y_test = get_config('y_test')
|
474 |
|
|
|
475 |
if selected_model in ['rf', 'et']:
|
476 |
estimators = model.estimators_
|
477 |
elif selected_model == 'gbr':
|
|
|
503 |
best_score = mse
|
504 |
best_estimator_index = idx
|
505 |
|
|
|
506 |
if selected_model in ['rf', 'et', 'gbr']:
|
507 |
best_tree = estimators[best_estimator_index]
|
|
|
508 |
fig, ax = plt.subplots(figsize=(40, 20))
|
509 |
plot_tree(
|
510 |
best_tree,
|
|
|
517 |
st.pyplot(fig)
|
518 |
st.caption(f"ベストな決定木(ツリー番号: {best_estimator_index})の構造を表示しています。")
|
519 |
elif selected_model == 'xgboost':
|
|
|
520 |
import xgboost as xgb
|
521 |
booster = model.get_booster()
|
522 |
fig, ax = plt.subplots(figsize=(40, 20))
|
|
|
524 |
st.pyplot(fig)
|
525 |
st.caption(f"ベストな決定木(ツリー番号: {best_estimator_index})の構造を表示しています。")
|
526 |
elif selected_model == 'lightgbm':
|
|
|
527 |
import lightgbm as lgb
|
528 |
graph = lgb.create_tree_digraph(model, tree_index=best_estimator_index)
|
529 |
st.graphviz_chart(graph)
|
|
|
543 |
progress_bar = st.progress(0)
|
544 |
status_text = st.empty()
|
545 |
|
|
|
546 |
status_text.text("モデルをファイナライズ中...")
|
547 |
progress_bar.progress(30)
|
548 |
final_model = finalize_model(model)
|
549 |
|
|
|
550 |
status_text.text("最終評価を実行中...")
|
551 |
progress_bar.progress(60)
|
552 |
predictions = predict_model(final_model)
|
553 |
final_scores = pull()
|
554 |
|
|
|
555 |
st.subheader("ファイナルモデルの評価結果")
|
556 |
col1, col2 = st.columns(2)
|
557 |
with col1:
|
|
|
561 |
st.write("ファイナライズ後の評価結果")
|
562 |
st.dataframe(final_scores, use_container_width=True)
|
563 |
|
|
|
|
|
564 |
final_model.target_column = target_variable
|
565 |
|
|
|
566 |
status_text.text("モデルを保存中...")
|
567 |
progress_bar.progress(90)
|
568 |
model_name = f"{target_variable}_finalized_model"
|
569 |
|
|
|
570 |
save_model(final_model, model_name)
|
571 |
|
|
|
572 |
with open(f"{model_name}.pkl", 'rb') as f:
|
573 |
model_bytes = f.read()
|
574 |
|
|
|
591 |
st.error(f"予期せぬエラーが発生しました: {str(e)}")
|
592 |
|
593 |
# コピーライト情報
|
594 |
+
common.display_copyright()
|
|
common.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
|
3 |
+
|
4 |
+
def display_header():
|
5 |
+
st.caption("Created by Dit-Lab.(Daiki Ito)")
|
6 |
+
|
7 |
+
def set_font():
|
8 |
+
import matplotlib.pyplot as plt
|
9 |
+
import japanize_matplotlib
|
10 |
+
font_path = "ipaexg.ttf"
|
11 |
+
plt.rcParams['font.family'] = 'IPAexGothic'
|
12 |
+
|
13 |
+
def display_guide():
|
14 |
+
st.markdown("""
|
15 |
+
- [**情報探究ステップアップガイド**](https://dit-lab.notion.site/612d9665350544aa97a2a8514a03c77c?v=85ad37a3275b4717a0033516b9cfd9cc)
|
16 |
+
- [**中の人のページ(Dit-Lab.)**](https://dit-lab.notion.site/Dit-Lab-da906d09d3cf42a19a011cf4bf25a673?pvs=4)
|
17 |
+
""")
|
18 |
+
|
19 |
+
def display_link():
|
20 |
+
st.header("リンク")
|
21 |
+
st.markdown("""
|
22 |
+
- [**中の人のページ(Dit-Lab.)**](https://dit-lab.notion.site/Dit-Lab-da906d09d3cf42a19a011cf4bf25a673?pvs=4)
|
23 |
+
- [**進数変換学習アプリ**](https://easy-base-converter.streamlit.app)
|
24 |
+
- [**easyRSA**](https://easy-rsa.streamlit.app/)
|
25 |
+
- [**easyAutoML(回帰)**](https://huggingface.co/spaces/itou-daiki/pycaret_datascience_streamlit)
|
26 |
+
- [**pkl_predict_reg**](https://huggingface.co/spaces/itou-daiki/pkl_predict_reg)
|
27 |
+
- [**音のデータサイエンス**](https://audiovisualizationanalysis-bpeekdjwymuf6nkqcb4cqy.streamlit.app)
|
28 |
+
- [**3D RGB Cube Visualizer**](https://boxplot-4-mysteams.streamlit.app)
|
29 |
+
- [**上マーク角度計算補助ツール**](https://sailing-mark-angle.streamlit.app)
|
30 |
+
- [**Factor Score Calculator**](https://factor-score-calculator.streamlit.app/)
|
31 |
+
- [**easy Excel Merge**](https://easy-xl-merge.streamlit.app)
|
32 |
+
- [**フィードバックはこちらまで**](https://forms.gle/G5sMYm7dNpz2FQtU9)
|
33 |
+
- [**ソースコードはこちら(GitHub)**](https://github.com/itou-daiki/easy_stat)
|
34 |
+
""")
|
35 |
+
|
36 |
+
def display_copyright():
|
37 |
+
st.subheader("")
|
38 |
+
st.write('ご意見・ご要望は→', 'https://forms.gle/G5sMYm7dNpz2FQtU9', 'まで')
|
39 |
+
st.write("")
|
40 |
+
st.subheader('© 2022-2025 Dit-Lab.(Daiki Ito). All Rights Reserved.')
|
41 |
+
st.write("easyStat: Open Source for Ubiquitous Statistics")
|
42 |
+
st.write("Democratizing data, everywhere.")
|
43 |
+
st.write("")
|
44 |
+
|
45 |
+
def display_special_thanks():
|
46 |
+
st.subheader("In collaboration with our esteemed contributors:")
|
47 |
+
st.write("・Toshiyuki")
|
48 |
+
st.write("With heartfelt appreciation for their dedication and support.")
|