Gforce-ML commited on
Commit
3f651b1
1 Parent(s): 9f6ddfa

change app configure

Browse files
Files changed (1) hide show
  1. app.py +806 -0
app.py ADDED
@@ -0,0 +1,806 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # IMPORTS
2
+ # ====================================
3
+
4
+ import numpy as np
5
+ import pandas as pd
6
+ import streamlit as st
7
+ import streamlit.components.v1 as components
8
+ import seaborn as sns
9
+ import plotly.express as px
10
+ from random import randint
11
+ import matplotlib.pyplot as plt
12
+
13
+ from sklearn.linear_model import LogisticRegression
14
+ from sklearn.svm import SVC
15
+ from sklearn.neighbors import KNeighborsClassifier
16
+ from sklearn.tree import DecisionTreeClassifier
17
+ from sklearn.ensemble import RandomForestClassifier
18
+
19
+ from sklearn.model_selection import train_test_split
20
+ from sklearn.model_selection import StratifiedKFold
21
+ from imblearn.pipeline import make_pipeline as imbalanced_make_pipeline
22
+ from imblearn.over_sampling import SMOTE
23
+ from sklearn.model_selection import RandomizedSearchCV
24
+ from sklearn.metrics import classification_report, confusion_matrix, f1_score,accuracy_score, precision_score, recall_score, roc_auc_score
25
+
26
+ from sklearn.feature_selection import SelectKBest
27
+ from sklearn.feature_selection import f_classif
28
+
29
+ import time # для фичей отслеживания прогресса (не задеплоен)
30
+ import warnings
31
+ warnings.filterwarnings("ignore")
32
+
33
+ # MAIN PAGE
34
+ # ========================================
35
+
36
+ st.markdown("<h1 style='text-align: center;'>Применение методов машинного обучения в анализе банкротства</h1>", unsafe_allow_html=True)
37
+
38
+ components.html(
39
+ """
40
+ <a href="https://git.io/typing-svg"><img src="https://readme-typing-svg.herokuapp.com?font=Fira+Code&pause=1000&width=435&lines=Анализ+банкротства+компании" alt="Typing SVG" /></a>
41
+ <a href="https://git.io/typing-svg"><img src="https://readme-typing-svg.herokuapp.com?font=Fira+Code&pause=1000&width=435&lines=методами+искуственного+интеллекта" alt="Typing SVG" /></a>
42
+ """
43
+ )
44
+
45
+ with open("./img.png", "rb") as f:
46
+ st.image(f.read(), use_column_width=True)
47
+
48
+ st.write(
49
+ """
50
+ # Краткое описание задачи
51
+ Эффективное и заблаговременное прогнозирование банкротства компаний имеет важно значение для всех участников рынка. По мере развития информационного общества традиционные методы выявления банкротства становятся менее эффективными и более трудозатратными. Поэтому сочетание традиционных методов с современными моделями искусственного интеллекта может быть эффективно применено в современных экономических условиях.
52
+
53
+ Основная цель работы - оценить риск банкротства с помощью нескольких алгоритмов машинного обучения, сравнить результаты их работы, определить наилучшую модель и соответствующий набор признаков для прогнозирования банкротства компаний.
54
+ """
55
+ )
56
+
57
+ st.write("""# Этапы разработки""")
58
+
59
+ #image = Image.open("./stages.jpg")
60
+ #st.image(image, output_format="auto", use_column_width="auto")
61
+
62
+ with open("./stages.png", "rb") as f:
63
+ st.image(f.read(), use_column_width=True)
64
+
65
+
66
+ with st.expander("Описание пайплайна работы", expanded=True):
67
+
68
+ st.write(
69
+ """
70
+ ### Этапы разработки
71
+ <b><i>1. Поиск и сбор данных:</b></i>
72
+ Был использован датасет из Тайваньского экономического журнала за период с 1999 по 2009 год. Банкротство компании было определено на основании правил ведения бизнеса Тайваньской фондовой биржи. (<a href="https://www.kaggle.com/datasets/fedesoriano/company-bankruptcy-prediction">Ссылка на данные</a>)
73
+
74
+ <b><i>2. Обработка (препроцессинг):</b></i>
75
+ Удаление ненужных колонок, one hot encoding категориальных переменных, заполнение пропущенных значений. С использованием библиотек pandas, numpy, seaborn.
76
+
77
+ <b><i>3. Анализ статистических показателей и визуализация:</b></i>
78
+ Инструменты для этого - с использованием библиотек pandas, seaborn.
79
+
80
+ <b><i>4. Выбор моделей, обучение и валидация модели с ними (без фичей):</b></i>
81
+ С использованием библиотек scikit-learn, pandas, seaborn.
82
+
83
+ <b><i>5. Выбор моделей, обучение и валидация модели с ними (с фичами):</b></i>
84
+ С использованием библиотек scikit-learn, pandas, seaborn.
85
+ <
86
+ b><i>6. Сравнение результатов:</b></i>
87
+ Анализ и графическое представление работы алгоритмов. При некорректной работе или плохим результатом проводится п. 4 и п. 5.
88
+
89
+ <b><i>7. Оформление микросервиса Streamlit:</b></i>
90
+ С использованием библиотеки streamlit.
91
+ """,
92
+ unsafe_allow_html=True
93
+ )
94
+
95
+ with st.expander("Описание пайплайна работы", expanded=True):
96
+
97
+ st.write(
98
+ """
99
+ ### Информация о применении методов машинного обучения для бизнес-задач:
100
+ Прогнозирование финансовой неустойчивости – важный компонент управления компанией. Из-за банкротства акционеры теряют доходы, бизнес, нарушаются цепочки поставок, фискальные органы лишаются налоговых поступлений, госорганы фиксируют снижение экономического роста и повышение социальной напряженности, а работники вынуждены искать новую работу. Поэтому получение ясной картины финансового и имущественного состояния компаний уже много лет является целью специалистов самых разных областей знаний.
101
+ Компании активно внедряют современные технологии в основную деятельность, автоматизируя большое количество бизнес-процессов. Это позволяет выстраивать, например, электронную экспертизу, c помощью которой возможно оперативно объединять множество экспертов из разных предметных областей для полного охвата рассматриваемой проблемы и принятия коллективного решения. Электронная экспертиза также подразумевает взаимодействие людей с интеллектуальными системами, которые способны строить анализ и прогнозы на основе более широкого пространства переменных. Так, в частности, методы машинного обучения применяются уже в значительном количестве бизнес-задач, в том числе для интеллектуальной аналитики больших данных, которые компания аккумулирует для построения моделей прогнозирования.
102
+ Однако риски банкротства могут также возникнуть из-за некорректного стратегического менеджмента. Такой менеджмент подразумевает разработку долгосрочных целей и действий, которые позволят достичь более высоких результатов в будущем, например, стать лидирующей компанией в своей отрасли. Разрабатываемые при этом стратегии обычно носят амбициозный характер, поэтому цели компании в таком случае не направлены на пролонгацию сложившейся динамики. Правильный анализ стратегической ситуации также важен для прогнозирования банкротства. Существует множество методов для ее оценки, в том числе и на основе анализа больших данных.<a href="http://infosoc.iis.ru/article/view/509"> Источник<a>
103
+ """,
104
+ unsafe_allow_html=True
105
+ )
106
+
107
+ # INFO
108
+ # =====================================
109
+
110
+ st.write(
111
+ """
112
+ # 1. Информация о датасете
113
+ <b><i>Похожие наборы данных:</i></b>
114
+ - <a href="https://www.kaggle.com/datasets/fedesoriano/the-boston-houseprice-data">The Boston House-Price Data</a>
115
+ - <a href="https://www.kaggle.com/datasets/fedesoriano/gender-pay-gap-dataset">Gender Pay Gap Dataset</a>
116
+ - <a href="https://www.kaggle.com/datasets/fedesoriano/california-housing-prices-data-extra-features">Spanish Wine Quality Dataset</a>
117
+
118
+ <b><i>Про сами данные:</i></b>
119
+ Данные были получены из Тайваньского экономического журнала за период с 1999 по 2009 год. Банкротство компании было определено на основании правил ведения бизнеса Тайваньской фондовой биржи.
120
+
121
+ <i>P.S. Обновлены имена столбцов и описание, чтобы упростить понимание данных (Y = выходной объект, X = входной объект).</i>
122
+ """,
123
+ unsafe_allow_html=True
124
+ )
125
+
126
+ st.write(
127
+ """
128
+ <b><i>Источник:</i></b>
129
+ Deron Liang and Chih-Fong Tsai, deronliang '@' gmail.com; cftsai '@' mgt.ncu.edu.tw, National Central University, Taiwan.
130
+ <a href="https://archive.ics.uci.edu/ml/datasets/Taiwanese+Bankruptcy+Prediction">The data was obtained from UCI Machine Learning Repository.</a>
131
+
132
+ <b><i>Статья:</i></b>
133
+ <a href="https://www.sciencedirect.com/science/article/abs/pii/S0377221716000412">Тык</a>
134
+ """,
135
+ unsafe_allow_html=True
136
+ )
137
+
138
+ data = pd.read_csv("./dataset.csv", sep=",")
139
+
140
+ st.write(""" ### Таблица с данными: """, data)
141
+
142
+ st.write(
143
+ """
144
+ # 2. Обработка (препроцессинг)
145
+ """
146
+ )
147
+
148
+ # PREPROCESS
149
+ # ==================================
150
+
151
+ st.write(""" ### Статистика:""")
152
+ st.code(
153
+ """
154
+ data.describe()
155
+ """
156
+ )
157
+ st.text(data.describe())
158
+ st.code(
159
+ """
160
+ data.shape
161
+ """
162
+ )
163
+ st.write(""" #### Shape данных (номер строк и столбцов):""")
164
+ st.text(data.shape)
165
+
166
+ #st.table(data) - лучше не запускать :)
167
+
168
+ data.columns = [i.title().strip() for i in list(data.columns)]
169
+ row = data.shape[0]
170
+ col = data.shape[1]
171
+
172
+ null_values = data.isnull().sum().sort_values(ascending=False).head()
173
+ st.code(
174
+ """
175
+ null_values = data.isnull().sum().sort_values(ascending=False).head()
176
+ """
177
+ )
178
+ st.write(null_values)
179
+
180
+ st.code(
181
+ """
182
+ data.info()
183
+ """
184
+ )
185
+ st.text(data.info)
186
+ st.write("""Поскольку пропущенных значений нет, мы можем перейти к анализу данных.""")
187
+
188
+ # VISUALIZATIONS
189
+ # ==================================
190
+
191
+ #with open("./plot_1.png", "rb") as f:
192
+ #st.image(f.read(), use_column_width=True)
193
+
194
+ #values = st.sidebar.slider("Target", int(data["Bankrupt?"]))
195
+ #values = [0,1]
196
+ #values = list(data["Bankrupt?"].count())
197
+
198
+ colors = ['Accent', 'Accent_r', 'Blues', 'Blues_r', 'BrBG', 'BrBG_r', 'BuGn', 'BuGn_r', 'BuPu', 'BuPu_r', 'CMRmap',
199
+ 'CMRmap_r', 'Dark2', 'Dark2_r', 'GnBu', 'GnBu_r', 'Greens', 'Greens_r', 'Greys', 'Greys_r', 'OrRd', 'OrRd_r',
200
+ 'Oranges', 'Oranges_r', 'PRGn', 'PRGn_r', 'Paired', 'Paired_r', 'Pastel1', 'Pastel1_r', 'Pastel2', 'Pastel2_r',
201
+ 'PiYG', 'PiYG_r', 'PuBu', 'PuBuGn', 'PuBuGn_r', 'PuBu_r', 'PuOr', 'PuOr_r', 'PuRd', 'PuRd_r', 'Purples', 'Purples_r',
202
+ 'RdBu', 'RdBu_r', 'RdGy', 'RdGy_r', 'RdPu', 'RdPu_r', 'RdYlBu', 'RdYlBu_r', 'RdYlGn', 'RdYlGn_r', 'Reds', 'Reds_r',
203
+ 'Set1', 'Set1_r', 'Set2', 'Set2_r', 'Set3', 'Set3_r', 'Spectral', 'Spectral_r', 'Wistia', 'Wistia_r', 'YlGn', 'YlGnBu',
204
+ 'YlGnBu_r', 'YlGn_r', 'YlOrBr', 'YlOrBr_r', 'YlOrRd', 'YlOrRd_r', 'afmhot', 'afmhot_r', 'autumn', 'autumn_r', 'binary',
205
+ 'binary_r', 'bone', 'bone_r', 'brg', 'brg_r', 'bwr', 'bwr_r', 'cividis', 'cividis_r', 'cool', 'cool_r', 'coolwarm',
206
+ 'coolwarm_r', 'copper', 'copper_r', 'crest', 'crest_r', 'cubehelix', 'cubehelix_r', 'flag', 'flag_r', 'flare',
207
+ 'flare_r', 'gist_earth', 'gist_earth_r', 'gist_gray', 'gist_gray_r', 'gist_heat', 'gist_heat_r', 'gist_ncar',
208
+ 'gist_ncar_r', 'gist_rainbow', 'gist_rainbow_r', 'gist_stern', 'gist_stern_r', 'gist_yarg', 'gist_yarg_r', 'gnuplot',
209
+ 'gnuplot2', 'gnuplot2_r', 'gnuplot_r', 'gray', 'gray_r', 'hot', 'hot_r', 'hsv', 'hsv_r', 'icefire', 'icefire_r',
210
+ 'inferno', 'inferno_r', 'jet', 'jet_r', 'magma', 'magma_r', 'mako', 'mako_r', 'nipy_spectral', 'nipy_spectral_r',
211
+ 'ocean', 'ocean_r', 'pink', 'pink_r', 'plasma', 'plasma_r', 'prism', 'prism_r', 'rainbow', 'rainbow_r', 'rocket',
212
+ 'rocket_r', 'seismic', 'seismic_r', 'spring', 'spring_r', 'summer', 'summer_r', 'tab10', 'tab10_r', 'tab20',
213
+ 'tab20_r', 'tab20b', 'tab20b_r', 'tab20c', 'tab20c_r', 'terrain', 'terrain_r', 'turbo', 'turbo_r', 'twilight',
214
+ 'twilight_r', 'twilight_shifted', 'twilight_shifted_r', 'viridis', 'viridis_r', 'vlag', 'vlag_r', 'winter', 'winter_r']
215
+
216
+ value = randint(0, len(colors)-1)
217
+
218
+ # plot_1
219
+ counts = data['Bankrupt?'].value_counts()
220
+ f = px.bar(counts, title="Соотношение количества банкротов и не банкротов")
221
+ f.update_xaxes(title="Bankrupt?")
222
+ f.update_yaxes(title="Count")
223
+ st.plotly_chart(f)
224
+ #f.show() - для отображения в отдельной вкладке
225
+
226
+ st.write(
227
+ """
228
+ Записи кажутся сильно несбалансированными. Таким образом, необходимо рассмотреть возможность балансировки набора данных с помощью методов повышения или понижения дискретизации.
229
+ """
230
+ )
231
+ numeric_features = data.dtypes[data.dtypes != 'int64'].index
232
+ categorical_features = data.dtypes[data.dtypes == 'int64'].index
233
+
234
+ data[categorical_features].columns.tolist()
235
+
236
+ st.write(
237
+ """
238
+ С помощью data.info() мы заметили, что у нас есть большинство данных «float64». Категориальные данные различаются как двоичные 1 и 0, поэтому сохраняются как «int64». Мы разделяем числовые и категориальные данные для анализа нашего набора данных.
239
+ """
240
+ )
241
+ st.code(
242
+ """
243
+ numeric_features = data.dtypes[data.dtypes != 'int64'].index
244
+ categorical_features = data.dtypes[data.dtypes == 'int64'].index
245
+
246
+ data[categorical_features].columns.tolist()
247
+ """,
248
+ language="python"
249
+ )
250
+ st.write(
251
+ """
252
+ Вывод консоли:
253
+
254
+ ['Bankrupt?', 'Liability-Assets Flag', 'Net Income Flag']
255
+ """
256
+ )
257
+ st.write(
258
+ """
259
+ Есть только три столбца категорийных данных, сначала рассмотрим эти столбцы.
260
+ """
261
+ )
262
+
263
+ # plot_2
264
+ counts = data["Liability-Assets Flag"].value_counts()
265
+ f = px.bar(counts, title="Обязательства-активы")
266
+ f.update_xaxes(title="Liability-Assets Flag")
267
+ f.update_yaxes(title="Count")
268
+ st.plotly_chart(f)
269
+
270
+ st.write(
271
+ """
272
+ Поле «Обязательства-Активы» (Liability-Assets Flag) обозначает статус организации, где, если общая сумма обязательств превышает общую сумму активов, помеченное значение будет равно 1, в противном случае значение равно 0. В большинстве случаев активы организаций/компаний превышают их обязательства.
273
+ """
274
+ )
275
+
276
+ # plot_3
277
+
278
+ st.header("Распределение количества банкротов по активам и обязательствам")
279
+ counts = data[['Liability-Assets Flag','Bankrupt?']].value_counts()
280
+ plt.figure(figsize=(8,7))
281
+ fig, ax = plt.subplots()
282
+ ax = sns.countplot(x = 'Liability-Assets Flag',hue = 'Bankrupt?',data = data,palette = colors[value])
283
+ st.pyplot(fig)
284
+
285
+ st.write(
286
+ """
287
+ Небольшая часть организаций терпит банкротство, хотя у них активов больше, чем обязательств.
288
+ """
289
+ )
290
+
291
+ # plot_4
292
+ counts = data["Net Income Flag"].value_counts()
293
+ f = px.bar(counts, title="Чистый доход")
294
+ f.update_xaxes(title="Net Income Flag")
295
+ f.update_yaxes(title="Count")
296
+ st.plotly_chart(f)
297
+
298
+ st.write(
299
+ """
300
+ Поле «Чистый доход» (Net Income Flag) обозначает состояние дохода организации за последние два года, где, если чистый доход отрицателен за последние два года, отмеченное значение будет равно 1, в противном случае значение равно 0. Мы наблюдаем, что все отчеты демонстрируют убыток в течение последних двух лет.
301
+ """
302
+ )
303
+
304
+ # plot_5
305
+ st.header("Распределение количества банкротов по чистому доходу")
306
+ counts = data[['Net Income Flag','Bankrupt?']].value_counts()
307
+ plt.figure(figsize=(8,7))
308
+ fig, ax = plt.subplots()
309
+ ax = sns.countplot(x = 'Net Income Flag',hue = 'Bankrupt?',data = data,palette = colors[value])
310
+ st.pyplot(fig)
311
+
312
+ #counts = data[['Net Income Flag','Bankrupt?']].value_counts()
313
+ #f = sns.countplot(x = 'Net Income Flag',hue = 'Bankrupt?',data = data,palette = colors[value])
314
+ #st.plotly_chart(f)
315
+
316
+ st.write(
317
+ """
318
+ Многие организации, понесшие убытки за последние два года, стабилизировали свой бизнес, избежав таким образом банкротства.
319
+ """
320
+ )
321
+ positive_corr = data[numeric_features].corrwith(data["Bankrupt?"]).sort_values(ascending=False)[:6].index.tolist()
322
+ negative_corr = data[numeric_features].corrwith(data["Bankrupt?"]).sort_values()[:6].index.tolist()
323
+
324
+ positive_corr = data[positive_corr + ["Bankrupt?"]].copy()
325
+ negative_corr = data[negative_corr + ["Bankrupt?"]].copy()
326
+
327
+ #x_value = positive_corr.columns.tolist()[-1]
328
+ #y_value = positive_corr.columns.tolist()[:-1]
329
+
330
+ #x_value = negative_corr.columns.tolist()[-1]
331
+ #y_value = negative_corr.columns.tolist()[:-1]
332
+
333
+ st.write(
334
+ """
335
+ Для простоты мы анализируем шесть основных атрибутов с положительной и отрицательной корреляцией.
336
+ """
337
+ )
338
+
339
+ st.write("""Атрибуты с положительной корреляцией: """)
340
+ with open("./corr_1.png", "rb") as f:
341
+ st.image(f.read(), use_column_width=True)
342
+
343
+ with st.expander("i - Что значит корреляция", expanded=False):
344
+ st.write(
345
+ """
346
+ <b><i>Корреляция</i></b> – это взаимосвязь двух или нескольких случайных параметров. Когда одна величина растет или уменьшается, другая тоже изменяется.
347
+ """,
348
+ unsafe_allow_html=True
349
+ )
350
+
351
+ st.write(
352
+ """
353
+ Мы видим, что три атрибута — Отношение долга % (Debt Ratio %), Текущая ответственность к активам (Current Liability To Assets), Текущая ответственность к текущим активам (Current Liability To Current Assets) обычно высоки в организациях-банкротах.
354
+ """
355
+ )
356
+
357
+ st.write("""Атрибуты с отрицательной корреляцией: """)
358
+ with open("./corr_2.png", "rb") as f:
359
+ st.image(f.read(), use_column_width=True)
360
+
361
+ st.write(
362
+ """
363
+ Эти атрибуты показывают нам, что чем больше активы и доходы компании, тем меньше вероятность того, что организация обанкротится.
364
+ Давайте проверим соотношение шести верхних положительных и отрицательных атрибутов корреляции между собой.
365
+ """
366
+ )
367
+
368
+ with open("./positive.png", "rb") as f:
369
+ st.image(f.read(), use_column_width=True)
370
+
371
+ st.write(
372
+ """
373
+ Существует положительная связь между атрибутами, которые имеют высокую корреляцию с целевой переменной.
374
+ """
375
+ )
376
+
377
+ with open("./negative.png", "rb") as f:
378
+ st.image(f.read(), use_column_width=True)
379
+
380
+ st.write(
381
+ """
382
+ Существует положительная связь между атрибутами, которые имеют низкую корреляцию с целевой переменной.
383
+ """
384
+ )
385
+
386
+ st.write(""" ## Нажав на кнопку ниже - можно построить интерактивную корреляционную матрицу""")
387
+
388
+ if st.button("Построить корреляционную матрицу !!!"):
389
+ st.header("Корреляционная матрица")
390
+ relation = positive_corr.columns.tolist()[:-1] + negative_corr.columns.tolist()[:-1]
391
+ plt.figure(figsize=(8,7))
392
+ fig, ax = plt.subplots()
393
+ ax = sns.heatmap(data[relation].corr(),annot=True)
394
+ st.pyplot(fig)
395
+
396
+ st.write(
397
+ """
398
+ Общая корреляция 12 лучших атрибутов приведена выше.
399
+ """
400
+ )
401
+
402
+ st.write(
403
+ """
404
+ ### Резюме анализа
405
+ - Количество организаций, обанкротившихся за 10 лет с 1999 по 2000 год, невелико.
406
+ - Несколько компаний обладают большим количеством активов, что всегда является хорошим признаком для организации.
407
+ - Организация не может гарантировать, что не будет банкротом, хотя и владеет несколькими активами.
408
+ - Организации в наборе данных несут убытки за последние два года, поскольку их чистая прибыль представляется отрицательной.
409
+ - Очень немногие из организаций, имевших отрицательную прибыль за последние два года, терпят банкротство.
410
+ - Отмечено, что атрибуты «Отношение долга, %, текущие обязательства к активам, текущие обязательства к текущим активам» — это лишь некоторые из атрибутов, которые имеют высокую корреляцию с целевой переменной.
411
+ - Увеличение значений атрибутов «Отношение долга %, Текущие обязательства к активам, Текущие обязательства к оборотным средствам» приводит к большим убыткам организации, чт�� приводит к банкротству.
412
+ - Увеличение значений признаков, имеющих отрицательную корреляцию с целевой переменной, помогает организации избежать банкротства.
413
+ - По-видимому, существует связь между атрибутами, имеющими высокую и низкую корреляцию с целевой переменной.
414
+ - Мы наблюдали несколько корреляций между 12 основными атрибутами, одним из которых является «Чистая стоимость / Активы и соотношение долга%», которые отрицательно коррелируют друг с другом.
415
+ """
416
+ )
417
+
418
+ # ML
419
+ # ===========================================================
420
+
421
+ st.write("""# Машинное обучение""")
422
+ st.write("""### Нормализация данных""")
423
+
424
+ st.code(
425
+ """
426
+ numeric_features = data.dtypes[data.dtypes != 'int64'].index
427
+ data[numeric_features] = data[numeric_features].apply(lambda x: (x - x.mean()) / (x.std()))
428
+
429
+ data[numeric_features] = data[numeric_features].fillna(0)
430
+ """,
431
+ language="python"
432
+ )
433
+
434
+ with st.expander("i - Что значит нормализация", expanded=False):
435
+ st.write(
436
+ """
437
+ <b><i>Нормализация</i></b> – это процедура предобработки входной информации (обучающих, тестовых и валидационных выборок, а также реальных данных), при которой значения признаков во входном векторе приводятся к некоторому заданному диапазону, например, [0…1] или [-1…1] [1]
438
+ """,
439
+ unsafe_allow_html=True
440
+ )
441
+
442
+ st.write(
443
+ """
444
+ Наш набор данных сильно несбалансирован. Таким образом, перед обучением модели нам нужно как то преобразовать эти данные. Давайте обозначим несколько этапов, которым мы должны следовать, когда сталкиваемся с несбалансированным набором данных:
445
+
446
+ - Деление набора данных на части для обучения и тестирования (80–20%). Мы сохраняем 20% в тестовый набор для окончательной оценки.
447
+ - С помощью кросс-валидации по К блокам (stratified K-fold cross validation) мы распределим 80% тренировочного набора на дальнейшее обучение и тестирование.
448
+ - Поскольку мы имеем дело с более чем 50 функциями, будем использовать Randomized Search Cross-Validation, поскольку этот метод лучше работает со многими функциями.
449
+ """
450
+ )
451
+
452
+ # MODELS SCORES DISPLAY FUNC WITHOUT FEATURE SELECTION
453
+ # ============================================================================
454
+
455
+ Models = pd.DataFrame(columns=['Algorithm','Model Score','Precision','Recall','F1 score','ROC-AUC score'])
456
+
457
+ def taining_without_feature_selection(Parameters, Model, Dataframe, Modelname):
458
+
459
+ data = Dataframe.copy()
460
+
461
+ X = data.drop('Bankrupt?', axis=1)
462
+ y = data['Bankrupt?']
463
+
464
+ #Traditional split of the dataset 80% - 20%
465
+ x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
466
+
467
+ x_train, x_test, y_train, y_test = x_train.values, x_test.values, y_train.values, y_test.values
468
+
469
+ #Proportional split of 80% data with respect to the class of the target feature ie. [1,0]
470
+ sf = StratifiedKFold(n_splits=5, random_state=None, shuffle=False)
471
+
472
+ for train_index, test_index in sf.split(x_train, y_train):
473
+ sf_x_train, sf_x_test = X.iloc[train_index], X.iloc[test_index]
474
+ sf_y_train, sf_y_test = y.iloc[train_index], y.iloc[test_index]
475
+
476
+ sf_x_train, sf_x_test, sf_y_train, sf_y_test = sf_x_train.values, sf_x_test.values, sf_y_train.values, sf_y_test.values
477
+
478
+ model_parameter_sm = Parameters
479
+
480
+ rand_model = RandomizedSearchCV(Model, model_parameter_sm, n_iter=4)
481
+
482
+ #Identifying the best parameters through RandomizedSearchCV()
483
+ for train, test in sf.split(sf_x_train, sf_y_train):
484
+ pipeline = imbalanced_make_pipeline(SMOTE(sampling_strategy='minority'), rand_model)
485
+ fitting_model = pipeline.fit(sf_x_train[train], sf_y_train[train])
486
+ best_model = rand_model.best_estimator_
487
+
488
+ #Evaluation with against 20% unseen testing data
489
+ print()
490
+ print("Evaluation Of Models")
491
+
492
+ sm = SMOTE(sampling_strategy='minority', random_state=42)
493
+ Xsm_train, ysm_train = sm.fit_resample(sf_x_train, sf_y_train)
494
+
495
+ print()
496
+ print("Random Model Evaluation")
497
+
498
+ final_model_sm = rand_model.best_estimator_
499
+ final_model_sm.fit(Xsm_train, ysm_train)
500
+
501
+ prediction = final_model_sm.predict(x_test)
502
+
503
+ print(classification_report(y_test, prediction))
504
+
505
+ model = {}
506
+
507
+ model['Algorithm'] = Modelname
508
+ model['Model Score'] = str(round((accuracy_score(y_test, prediction)*100),2)) + "%"
509
+ model['Precision'] = round(precision_score(y_test, prediction),2)
510
+ model['Recall'] = round(recall_score(y_test, prediction),2)
511
+ model['F1 score'] = round(f1_score(y_test, prediction),2)
512
+ model['ROC-AUC score'] = round(roc_auc_score(y_test, prediction),2)
513
+
514
+ return model
515
+
516
+ # SELECT OPTIONS
517
+ # ==========================================================================
518
+ st.write("""### Машинное обучение без отбора признаков""")
519
+
520
+ option = st.selectbox(
521
+ "Какой алгоритм для обучения выберем?",
522
+ ("K Nearest Neighbour", "Logistic Regression", "DecisionTree Classifier", "Random Forest Classifier", "Support Vector Classifier")
523
+ )
524
+
525
+ st.write('Выбрано:', option)
526
+ st.write(
527
+ """
528
+ После выбора нужно подождать, пока пройдет обучение - у некоторых алгоритмов процесс может растянуться на продолжительное время...
529
+ Для быстрой проверки можно использовать K Nearest Neighbour и Logistic Regression
530
+ """
531
+ )
532
+
533
+ with st.expander("О алгоритмах", expanded=False):
534
+ st.write(
535
+ """
536
+ сюда описание про алгоритмы
537
+ """,
538
+ unsafe_allow_html=True
539
+ )
540
+
541
+ @st.cache
542
+ def convert_df(df):
543
+ # IMPORTANT: Cache the conversion to prevent computation on every rerun
544
+ return df.to_csv().encode('utf-8')
545
+
546
+ @st.cache
547
+ def save_results(Models):
548
+ Models = Models.append(TrainedModel,ignore_index=True)
549
+ return Models
550
+
551
+ if option == "K Nearest Neighbour":
552
+ #print("K Nearest Neighbour")
553
+ TrainedModel = taining_without_feature_selection({"n_neighbors": list(range(2,5,1)), 'algorithm': ['auto', 'ball_tree', 'kd_tree', 'brute']}, KNeighborsClassifier(), data,"K Nearest Neighbour")
554
+ save_results(Models)
555
+ st.write(""" ### Результаты работы алгоритма: """, Models)
556
+ csv = convert_df(Models)
557
+ st.download_button(
558
+ label="Скачать CSV",
559
+ data=csv,
560
+ file_name='score_nneighbors.csv',
561
+ mime='text/csv',
562
+ )
563
+
564
+ if option == "Logistic Regression":
565
+ #print("Logistic Regression")
566
+ TrainedModel = taining_without_feature_selection({"penalty": ['l2'], 'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000]}, LogisticRegression(solver='liblinear'), data, "Logistic Regression")
567
+ save_results(Models)
568
+ st.write(""" ### Результаты работы алгоритма: """, Models)
569
+ csv = convert_df(Models)
570
+ st.download_button(
571
+ label="Скачать CSV",
572
+ data=csv,
573
+ file_name='score_logisticregression.csv',
574
+ mime='text/csv',
575
+ )
576
+
577
+ if option == "DecisionTree Classifier":
578
+ #print("DecisionTree Classifier")
579
+ TrainedModel = taining_without_feature_selection({"criterion": ["gini", "entropy"], "max_depth": list(range(2,4,1)),"min_samples_leaf": list(range(5,7,1))}, DecisionTreeClassifier(), data, "DecisionTree Classifier")
580
+ save_results(Models)
581
+ st.write(""" ### Результаты работы алгоритма: """, Models)
582
+ csv = convert_df(Models)
583
+ st.download_button(
584
+ label="Скачать CSV",
585
+ data=csv,
586
+ file_name='score_decisiontree.csv',
587
+ mime='text/csv',
588
+ )
589
+
590
+ if option == "Random Forest Classifier":
591
+ #print("Random Forest Classifier")
592
+ TrainedModel = taining_without_feature_selection({"max_depth": [3, 5, 10, None],"n_estimators": [100, 200, 300, 400, 500]}, RandomForestClassifier(), data, "Random Forest Classifier")
593
+ save_results(Models)
594
+ st.write(""" ### Результаты работы алгоритма: """, Models)
595
+ csv = convert_df(Models)
596
+ st.download_button(
597
+ label="Скачать CSV",
598
+ data=csv,
599
+ file_name='score_randomforest.csv',
600
+ mime='text/csv',
601
+ )
602
+
603
+ if option == "Support Vector Classifier":
604
+ print("Support Vector Classifier")
605
+ TrainedModel = taining_without_feature_selection({'C': [1,10,20],'kernel': ['rbf','linear']}, SVC(), data, "Support Vector Classifier")
606
+ save_results(Models)
607
+ st.write(""" ### Результаты работы алгоритма: """, Models)
608
+ csv = convert_df(Models)
609
+ st.download_button(
610
+ label="Скачать CSV",
611
+ data=csv,
612
+ file_name='score_supportvector.csv',
613
+ mime='text/csv',
614
+ )
615
+
616
+ st.write("### Общая таблица работы моделей: ")
617
+ if st.button("Отобразить (тыкать после обучения интересующих алгоритмов)"):
618
+ # st.write(Models.sort_values('F1 score',ascending=False))
619
+ st.write(Models)
620
+
621
+
622
+ # MODELS SCORES DISPLAY FUNC WITH FEATURE SELECTION
623
+ # ================================================================================
624
+
625
+ Models_2 = pd.DataFrame(columns=['Algorithm','Model Score','Precision','Recall','F1 score','ROC-AUC score'])
626
+
627
+ @st.cache
628
+ def taining_with_feature_selection(Parameters, Model, Dataframe, Modelname):
629
+
630
+ data = Dataframe.copy()
631
+
632
+ X = data.drop('Bankrupt?', axis=1)
633
+ y = data['Bankrupt?']
634
+
635
+ '''
636
+ Feature Selection Process:
637
+ class sklearn.feature_selection.SelectKBest(score_func=<function>, k=<number of features>
638
+ score_func - Scoring measure
639
+ k - Total features to be returned
640
+ '''
641
+
642
+ fs = SelectKBest(score_func=f_classif, k=int((data.shape[1]*85)/100))
643
+
644
+ X = fs.fit_transform(X, y)
645
+
646
+ X = pd.DataFrame(X)
647
+ y = pd.DataFrame(y)
648
+
649
+ x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
650
+
651
+ x_train, x_test, y_train, y_test = x_train.values, x_test.values, y_train.values, y_test.values
652
+
653
+ sf = StratifiedKFold(n_splits=5, random_state=None, shuffle=False)
654
+
655
+ for train_index, test_index in sf.split(x_train, y_train):
656
+ sf_x_train, sf_x_test = X.iloc[train_index], X.iloc[test_index]
657
+ sf_y_train, sf_y_test = y.iloc[train_index], y.iloc[test_index]
658
+
659
+ sf_x_train, sf_x_test, sf_y_train, sf_y_test = sf_x_train.values, sf_x_test.values, sf_y_train.values, sf_y_test.values
660
+
661
+ model_parameter_sm = Parameters
662
+
663
+ rand_model = RandomizedSearchCV(Model, model_parameter_sm, n_iter=4)
664
+
665
+ for train, test in sf.split(sf_x_train, sf_y_train):
666
+ pipeline = imbalanced_make_pipeline(SMOTE(sampling_strategy='minority'), rand_model)
667
+ fitting_model = pipeline.fit(sf_x_train[train], sf_y_train[train])
668
+ best_model = rand_model.best_estimator_
669
+
670
+ print()
671
+ print("Evaluation Of Models")
672
+
673
+ sm = SMOTE(sampling_strategy='minority', random_state=42)
674
+ Xsm_train, ysm_train = sm.fit_resample(sf_x_train, sf_y_train)
675
+
676
+ print()
677
+ print("Random Model Evaluation")
678
+
679
+ final_model_sm = rand_model.best_estimator_
680
+ final_model_sm.fit(Xsm_train, ysm_train)
681
+
682
+ prediction = final_model_sm.predict(x_test)
683
+
684
+ print(classification_report(y_test, prediction))
685
+
686
+ model = {}
687
+
688
+ model['Algorithm'] = Modelname
689
+ model['Model Score'] = str(round((accuracy_score(y_test, prediction)*100),2)) + "%"
690
+ model['Precision'] = round(precision_score(y_test, prediction),2)
691
+ model['Recall'] = round(recall_score(y_test, prediction),2)
692
+ model['F1 score'] = round(f1_score(y_test, prediction),2)
693
+ model['ROC-AUC score'] = round(roc_auc_score(y_test, prediction),2)
694
+
695
+ return model
696
+
697
+
698
+ # SELECT OPTIONS
699
+ # ==========================================================================
700
+ with open("./polosca.jpg", "rb") as f:
701
+ st.image(f.read(), use_column_width=True)
702
+
703
+ st.write("""### Машинное обучение с отбором признаков""")
704
+
705
+ option = st.selectbox(
706
+ "Какой алгоритм для обучения с отбором признаков выберем?",
707
+ ("K Nearest Neighbour", "Logistic Regression", "DecisionTree Classifier", "Random Forest Classifier", "Support Vector Classifier")
708
+ )
709
+
710
+ st.write('Выбрано:', option)
711
+ st.write(
712
+ """
713
+ После выбора нужно подождать, пока пройдет обучение - у некоторых алгоритмов процесс может растянуться на продолжительное время...
714
+ Для быстрой проверки можно использовать K Nearest Neighbour и Logistic Regression
715
+ """
716
+ )
717
+
718
+ @st.cache
719
+ def save_results(Models_2):
720
+ Models_2 = Models_2.append(TrainedModel,ignore_index=True)
721
+ return Models_2
722
+
723
+ if option == "K Nearest Neighbour":
724
+ #print("K Nearest Neighbour")
725
+ TrainedModel = taining_without_feature_selection({"n_neighbors": list(range(2,5,1)), 'algorithm': ['auto', 'ball_tree', 'kd_tree', 'brute']}, KNeighborsClassifier(), data,"K Nearest Neighbour")
726
+ save_results(Models_2)
727
+ st.write(""" ### Результаты работы алгоритма: """, Models_2)
728
+ csv = convert_df(Models_2)
729
+ st.download_button(
730
+ label="Скачать CSV",
731
+ data=csv,
732
+ file_name='score_nneighbors_fs.csv',
733
+ mime='text/csv',
734
+ )
735
+
736
+ if option == "Logistic Regression":
737
+ #print("Logistic Regression")
738
+ TrainedModel = taining_without_feature_selection({"penalty": ['l2'], 'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000]}, LogisticRegression(solver='liblinear'), data, "Logistic Regression")
739
+ save_results(Models_2)
740
+ st.write(""" ### Результаты работы алгоритма: """, Models_2)
741
+ csv = convert_df(Models_2)
742
+ st.download_button(
743
+ label="Скачать CSV",
744
+ data=csv,
745
+ file_name='score_logisticregression_fs.csv',
746
+ mime='text/csv',
747
+ )
748
+
749
+ if option == "DecisionTree Classifier":
750
+ #print("DecisionTree Classifier")
751
+ TrainedModel = taining_without_feature_selection({"criterion": ["gini", "entropy"], "max_depth": list(range(2,4,1)),"min_samples_leaf": list(range(5,7,1))}, DecisionTreeClassifier(), data, "DecisionTree Classifier")
752
+ save_results(Models_2)
753
+ st.write(""" ### Результаты работы алгоритма: """, Models_2)
754
+ csv = convert_df(Models_2)
755
+ st.download_button(
756
+ label="Скачать CSV",
757
+ data=csv,
758
+ file_name='score_decisiontree_fs.csv',
759
+ mime='text/csv',
760
+ )
761
+
762
+ if option == "Random Forest Classifier":
763
+ #print("Random Forest Classifier")
764
+ TrainedModel = taining_without_feature_selection({"max_depth": [3, 5, 10, None],"n_estimators": [100, 200, 300, 400, 500]}, RandomForestClassifier(), data, "Random Forest Classifier")
765
+ save_results(Models_2)
766
+ st.write(""" ### Результаты работы алгоритма: """, Models_2)
767
+ csv = convert_df(Models_2)
768
+ st.download_button(
769
+ label="Скачать CSV",
770
+ data=csv,
771
+ file_name='score_randomforest_fs.csv',
772
+ mime='text/csv',
773
+ )
774
+
775
+ if option == "Support Vector Classifier":
776
+ print("Support Vector Classifier")
777
+ TrainedModel = taining_without_feature_selection({'C': [1,10,20],'kernel': ['rbf','linear']}, SVC(), data, "Support Vector Classifier")
778
+ save_results(Models_2)
779
+ st.write(""" ### Результаты работы алгоритма: """, Models_2)
780
+ csv = convert_df(Models_2)
781
+ st.download_button(
782
+ label="Скачать CSV",
783
+ data=csv,
784
+ file_name='score_supportvector_fs.csv',
785
+ mime='text/csv',
786
+ )
787
+
788
+ st.write("### Общая таблица работы моделей: ")
789
+ if st.button("Отобразить (тыкать после обучения интересующих алгоритмов с отбором признаков)"):
790
+ # st.write(Models.sort_values('F1 score',ascending=False))
791
+ st.write(Models_2)
792
+
793
+ st.markdown(" ")
794
+ st.markdown(" ")
795
+ st.markdown(" ")
796
+
797
+ if st.button("✨Получи приз, если дошел до самого конца!!"):
798
+ st.balloons()
799
+
800
+ st.markdown(" ")
801
+
802
+ components.html(
803
+ """
804
+ <p align="center">Powered by <a href="https://github.com/Lyutikk">Gforce</a></p>
805
+ """
806
+ )