File size: 15,183 Bytes
10831b3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
import streamlit as st
import pandas as pd
import numpy as np
from pycaret.classification import *
from pycaret.regression import *
from sklearn.tree import *
import plotly.figure_factory as ff
import graphviz
import matplotlib.pyplot as plt
import japanize_matplotlib
import joblib
import base64
import io

# Streamlitのページ設定
st.set_page_config(page_title="AIデータサイエンス")

# タイトルの表示
st.title("AIデータサイエンス")
st.caption("Created by Dit-Lab.(Daiki Ito)")
st.write("アップロードされたデータセットに基づいて、機械学習モデルの作成と評価を行います。")
st.write("データの読み込み → モデル比較 → チューニング → 可視化 を行うことができます")

# データファイルのアップロード
st.header("1. データファイルのアップロード")
st.caption("こちらからデータをアップロードしてください。アップロードしたデータは次のステップで前処理され、モデルの訓練に使用されます。")
uploaded_file = st.file_uploader("CSVまたはExcelファイルをアップロードしてください。", type=['csv', 'xlsx'])

# 新しいデータがアップロードされたときにセッションをリセット
if uploaded_file is not None and ('last_uploaded_file' not in st.session_state or uploaded_file.name != st.session_state.last_uploaded_file):
    st.session_state.clear()  # セッションステートをクリア
    st.session_state.last_uploaded_file = uploaded_file.name  # 最後にアップロードされたファイル名を保存

if uploaded_file:
    if uploaded_file.name.endswith('.csv'):
        train_data = pd.read_csv(uploaded_file)
    elif uploaded_file.name.endswith('.xlsx'):
        train_data = pd.read_excel(uploaded_file)
    else:
        st.error("無効なファイルタイプです。CSVまたはExcelファイルをアップロードしてください.")

    st.session_state.uploaded_data = train_data
    st.dataframe(train_data.head())

# ターゲット変数の選択
if 'uploaded_data' in st.session_state:
    st.header("2. ターゲット変数の選択")
    st.caption("モデルの予測対象となるターゲット変数を選択してください。この変数がモデルの予測ターゲットとなります。")
    target_variable = st.selectbox('ターゲット変数を選択してください。', st.session_state.uploaded_data.columns)
    st.session_state.target_variable = target_variable

# 分析から除外する変数の選択
    st.header("3. 分析から除外する変数の選択")
    st.caption("モデルの訓練から除外したい変数を選択してください。これらの変数はモデルの訓練には使用されません。")
    ignore_variable = st.multiselect('分析から除外する変数を選択してください。', st.session_state.uploaded_data.columns)
    st.session_state.ignore_variable = ignore_variable

    # フィルタリングされたデータフレームの表示
    filtered_data = st.session_state.uploaded_data.drop(columns=ignore_variable)
    st.write("フィルタリングされたデータフレームの表示")
    st.write(filtered_data)

    # Excelファイルダウンロード機能
    towrite = io.BytesIO()
    downloaded_file = filtered_data.to_excel(towrite, encoding='utf-8', index=False, header=True)
    towrite.seek(0)
    b64 = base64.b64encode(towrite.read()).decode()
    original_filename = uploaded_file.name.split('.')[0]  # 元のファイル名を取得
    download_filename = f"{original_filename}_filtered.xlsx"  # フィルタリングされたファイル名を作成
    link = f'<a href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}" download="{download_filename}">フィルタリングされたデータフレームをExcelファイルとしてダウンロード</a>'
    st.markdown(link, unsafe_allow_html=True)

# 前処理の実行及びモデルの比較
    st.header("4. 前処理の実行とモデルの比較")
    st.caption("データの前処理を行い、利用可能な複数のモデルを比較します。最も適したモデルを選択するための基準としてください。")

    # 外れ値の処理
    remove_outliers_option = st.checkbox('外れ値を削除する', value=False) 

    if st.button('前処理とモデルの比較の実行'):  # この条件を追加
        # データの検証
        if st.session_state.uploaded_data[target_variable].isnull().any():
            st.warning("ターゲット変数に欠損値が含まれているレコードを削除します。")
            st.session_state.uploaded_data = st.session_state.uploaded_data.dropna(subset=[target_variable])
        
        
        # 前処理(モデル作成の準備)
        if 'exp_clf101_setup_done' not in st.session_state:  # このセッションで既にセットアップが完了していない場合のみ実行
            with st.spinner('データの前処理中...'):
                exp_clf101 = setup(data=st.session_state.uploaded_data, 
                                   target=target_variable, 
                                   session_id=123, 
                                   remove_outliers=remove_outliers_option,
                                   ignore_features=ignore_variable)
                st.session_state.exp_clf101 = exp_clf101
                st.session_state.exp_clf101_setup_done = True  # セットアップ完了フラグをセッションに保存
    
        st.info("前処理が完了しました")
        setup_list_df = pull()
        st.write("前処理の結果")
        st.caption("以下は、前処理のステップとそれに伴うデータのパラメータを示す表です。")
        st.write(setup_list_df)
    
        # モデルの比較
        with st.spinner('モデルを比較中...'):
            models_comparison = compare_models(exclude=['dummy','catboost'])
            st.session_state.models_comparison = models_comparison  # セッション状態にモデル比較を保存
            models_comparison_df = pull()
            st.session_state.models_comparison_df = models_comparison_df

# モデルの選択とチューニング
    if 'models_comparison' in st.session_state:
        st.success("モデルの比較が完了しました!")
        # モデル比較の表示
        models_comparison_df = pull()
        st.session_state.models_comparison_df = models_comparison_df
        st.write("モデル比較結果")
        st.caption("以下は、利用可能な各モデルの性能を示す表です。")
        st.dataframe(st.session_state.models_comparison_df)

        st.header("5. モデルの選択とチューニング")
        st.caption("最も性能の良いモデルを選択し、さらにそのモデルのパラメータをチューニングします。")
        selected_model_name = st.selectbox('使用するモデルを選択してください。', st.session_state.models_comparison_df.index)
        
        # 決定木プロットは可能なモデルのリストを表示
        tree_models = ['ada', 'et', 'rf', 'dt', 'gbr', 'catboost', 'lightgbm', 'xgboost']
        st.write("決定木プロットが可能なモデル: " + ", ".join(tree_models))

        # max_depth のオプションを表示
        if selected_model_name in tree_models:
            max_depth = st.slider("決定木の最大の深さを選択", 1, 10, 3)  # 例として最小1、最大10、デフォルト3


        if st.button('チューニングの実行'):
            with st.spinner('チューニング中...'):
                if selected_model_name in tree_models:
                    model = create_model(selected_model_name, max_depth=max_depth)
                else:
                    # モデルの作成とチューニング
                    model = create_model(selected_model_name)
                        
                pre_tuned_scores_df = pull()
                tuned_model = tune_model(model)
                st.session_state.tuned_model = tuned_model  # tuned_modelをセッションステートに保存
                st.success("モデルのチューニングが完了しました!")
                setup_tuned_model_df = pull()
                col1, col2 = st.columns(2) 
                with col1:
                    st.write("<チューニング前の交差検証の結果>")
                    st.write(pre_tuned_scores_df)
                with col2:
                    st.write("<チューニング後の交差検証の結果>")
                    st.write(setup_tuned_model_df)
                st.caption("上記表は、チューニング前後のモデルの交差検証結果を示す表です。")
                
                # チューニング後のモデルを保存
                if 'tuned_model' in st.session_state:
                    # モデルをバイナリ形式で保存
                    with open("tuned_model.pkl", "wb") as f:
                        joblib.dump(st.session_state.tuned_model, f)
                        
                    # ファイルをbase64エンコードしてダウンロードリンクを作成
                    with open("tuned_model.pkl", "rb") as f:
                        model_file = f.read()
                        model_b64 = base64.b64encode(model_file).decode()
                        href = f'<a href="data:application/octet-stream;base64,{model_b64}" download="tuned_model.pkl">チューニングされたモデルをダウンロード</a>'
                        st.markdown(href, unsafe_allow_html=True)
                        
                st.header("6. モデルの可視化及び評価")
                st.caption("以下は、チューニング後のモデルのさまざまな可視化を示しています。これらの可視化は、モデルの性能や特性を理解するのに役立ちます。")
                plot_types = [
                    ('pipeline', '<前処理パイプライン>', '前処理の流れ(フロー)を表しています'),
                    ('residuals', '<残差プロット>', '実際の値と予測値との差(残差)を示しています'),
                    ('error', '<予測誤差プロット>', 'モデルの予測誤差を示しています'),
                    ('feature', '<特徴量の重要度>', '各特徴量のモデルにおける重要度を示しています'),
                    ('cooks', '<クックの距離プロット>', 'データポイントがモデルに与える影響を示しています'),
                    ('learning', '<学習曲線>', '訓練データのサイズに対するモデルの性能を示しています'),
                    ('vc', '<検証曲線>', 'パラメータの異なる値に対するモデルの性能を示しています'),
                    ('manifold', '<マニホールド学習>', '高次元データを2次元にマッピングしたものを示しています')
                ]
                
                for plot_type, plot_name, plot_description in plot_types:
                    with st.spinner('プロット中...'):
                        try:
                            st.write(plot_name) 
                            img = plot_model(tuned_model, plot=plot_type, display_format="streamlit", save=True)
                            st.image(img)
                            st.caption(plot_description)  # グラフの説明を追加
                        except Exception as e:
                            st.warning(f"{plot_name}の表示中にエラーが発生しました: {str(e)}")
                        
                # 決定木のプロット
                if selected_model_name in tree_models:
                    st.write("<決定木のプロット>")
                    st.caption("決定木は、モデルがどのように予測を行っているかを理解するのに役立ちます。")
                    
                    with st.spinner('プロット中...'):
                                
                        if selected_model_name in ['dt']:
                            from sklearn.tree import plot_tree
                            fig, ax = plt.subplots(figsize=(20,10))
                            plot_tree(tuned_model, proportion=True, filled=True, rounded=True, ax=ax, max_depth=3)
                            st.pyplot(fig)

                        elif selected_model_name in ['rf', 'et']:
                            from sklearn.tree import plot_tree
                            fig, ax = plt.subplots(figsize=(20,10))
                            plot_tree(tuned_model.estimators_[0], feature_names=train_data.columns, proportion=True, filled=True, rounded=True, ax=ax, max_depth=3)
                            st.pyplot(fig)
                    
                        elif selected_model_name == 'ada':
                            from sklearn.tree import plot_tree
                            base_estimator = tuned_model.get_model().estimators_[0]
                            fig, ax = plt.subplots(figsize=(20,10))
                            plot_tree(base_estimator, filled=True, rounded=True, ax=ax, max_depth=3)
                            st.pyplot(fig)
                    
                        elif selected_model_name == 'gbr':
                            from sklearn.tree import plot_tree
                            base_estimator = tuned_model.get_model().estimators_[0][0]
                            fig, ax = plt.subplots(figsize=(20,10))
                            plot_tree(base_estimator, filled=True, rounded=True, ax=ax, max_depth=3)
                            st.pyplot(fig)
                    
                        elif selected_model_name == 'catboost':
                            from catboost import CatBoostClassifier, plot_tree
                            catboost_model = tuned_model.get_model()
                            fig, ax = plt.subplots(figsize=(20,10))
                            plot_tree(catboost_model, tree_idx=0, ax=ax, max_depth=3)
                            st.pyplot(fig)
                        
                        elif selected_model_name == 'lightgbm':
                            import lightgbm as lgb
                            booster = tuned_model._Booster  # LightGBM Booster object
                            fig, ax = plt.subplots(figsize=(20,10))
                            lgb.plot_tree(booster, tree_index=0, ax=ax, max_depth=3)
                            st.pyplot(fig)
                        
                        elif selected_model_name == 'xgboost':
                            import xgboost as xgb
                            booster = tuned_model.get_booster()  # XGBoost Booster object
                            fig, ax = plt.subplots(figsize=(20,10))
                            xgb.plot_tree(booster, num_trees=0, ax=ax, max_depth=3)
                            st.pyplot(fig)