Emil25 commited on
Commit
61f924c
1 Parent(s): 013cf90

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +23 -0
  2. main.py +151 -0
  3. scripts/download_data.py +17 -0
  4. scripts/model_training.py +56 -0
Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10
2
+
3
+ USER root
4
+
5
+ WORKDIR /app
6
+
7
+ COPY scripts /app/
8
+
9
+ COPY main.py /app/
10
+
11
+ COPY requirements.txt /app/
12
+
13
+ RUN apt-get update && \
14
+ apt-get install -y python3-pip python3-venv
15
+
16
+ RUN python3 -m venv /app/venv
17
+
18
+ ENV PATH="/app/venv/bin:$PATH"
19
+
20
+ RUN pip install --upgrade pip && \
21
+ pip install --no-cache-dir --upgrade -r /app/requirements.txt
22
+
23
+ CMD streamlit run main.py
main.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from scripts.model_training import model_training
3
+ import pandas as pd
4
+ import streamlit as st
5
+
6
+ st.set_page_config(
7
+ page_title="Cardiovascular-Disease App",
8
+ page_icon="🧊",
9
+ layout="wide",
10
+ initial_sidebar_state="expanded"
11
+ )
12
+
13
+
14
+ def user_input_features():
15
+ age = st.sidebar.slider('Возраст',
16
+ min_value=10,
17
+ max_value=100,
18
+ step=1,
19
+ )
20
+ gender= st.sidebar.selectbox('Пол',
21
+ options=('Мужской', 'Женский'),
22
+ )
23
+ height = st.sidebar.slider('Рост (см)',
24
+ min_value=100,
25
+ max_value=200,
26
+ value=150,
27
+ step=1,
28
+ )
29
+ weight = st.sidebar.slider('Вес (кг)',
30
+ min_value=30,
31
+ max_value=200,
32
+ value=70,
33
+ step=1,
34
+ )
35
+ ap_hi = st.sidebar.slider('Систолическое артериальное давление',
36
+ min_value=50,
37
+ max_value=200,
38
+ value=120,
39
+ step=1,
40
+ )
41
+ ap_lo = st.sidebar.slider('Диастолическое артериальное давление',
42
+ min_value=50,
43
+ max_value=200,
44
+ value=80,
45
+ step=1,
46
+ )
47
+ cholesterol = st.sidebar.selectbox('Общий холестерин (ммоль/л.)',
48
+ options=('<5','5-63', '>6.3'),
49
+ )
50
+ gluc = st.sidebar.selectbox('Глюкоза (ммоль/л.)',
51
+ options=('3.5—5.5','5.6-9', '>9'),
52
+ )
53
+ smoke = st.sidebar.selectbox('Курение',
54
+ options=('Да','Нет'),
55
+ )
56
+ alco = st.sidebar.selectbox('Употребление алкоголя',
57
+ options=('Да','Нет'),
58
+ )
59
+ active = st.sidebar.selectbox('Физическая активность',
60
+ options=('Да','Нет'),
61
+ )
62
+
63
+
64
+ def map_gluc(gluc):
65
+ if gluc == '3.5—5.5':
66
+ return '1'
67
+ elif gluc == '5.6-9':
68
+ return '2'
69
+ else:
70
+ return '3'
71
+
72
+
73
+ def map_cholesterol(cholesterol):
74
+ if cholesterol == '<5':
75
+ return '1'
76
+ elif cholesterol == '5-63':
77
+ return '2'
78
+ else:
79
+ return '3'
80
+
81
+
82
+ age = age * 365
83
+ data = {'age': age,
84
+ 'gender': '1' if gender == 'Женский' else '0',
85
+ 'height': height,
86
+ 'weight': weight,
87
+ 'ap_hi': ap_hi,
88
+ 'ap_lo': ap_lo,
89
+ 'cholesterol': map_cholesterol(cholesterol),
90
+ 'gluc': map_gluc(gluc),
91
+ 'smoke': '1' if smoke == 'Да' else '0',
92
+ 'alco': '1' if alco == 'Да' else '0',
93
+ 'active': '1' if active == 'Да' else '0',
94
+ }
95
+ features = pd.DataFrame(data, index=[0])
96
+ return features
97
+
98
+
99
+ @st.cache_data()
100
+ def get_model():
101
+ model, metric = model_training()
102
+ model_json = {'model': model,
103
+ 'metric': metric}
104
+ return model_json
105
+
106
+
107
+ def main():
108
+
109
+ st.write(""" # Приложение для определения наличия сердечно-сосудистого заболевания (ССЗ) :heartpulse: """)
110
+ st.sidebar.header("Параметры ввода")
111
+ st.divider()
112
+ user_data = user_input_features()
113
+ st.write(" # Ваши данные")
114
+ new_column_names = {'age': 'Возраст (дней)',
115
+ 'gender': 'Пол',
116
+ 'height': 'Рост (см)' ,
117
+ 'weight': 'Вес (кг)',
118
+ 'ap_hi': 'Систолическое давление',
119
+ 'ap_lo': 'Диастолическое давление',
120
+ 'cholesterol': 'Общий холестерин',
121
+ 'gluc': 'Глюкоза',
122
+ 'smoke': 'Курение',
123
+ 'alco': 'Алкоголь',
124
+ 'active': 'Физическая активность',
125
+ 'cardio': 'x',
126
+ }
127
+ user_data_rus = user_data.rename(columns=new_column_names)
128
+ st.dataframe(user_data_rus)
129
+
130
+ with st.spinner('Загрузка модели ...'):
131
+ model = get_model()
132
+ st.success('Модель загружена!')
133
+
134
+ st.divider()
135
+
136
+ diag_btn = st.button("Диагностика", type="primary")
137
+ if diag_btn == True:
138
+ result = ' '.join(map(str, model['model'].predict(user_data)))
139
+ result = "Положительный" if "result" == "positive" else "Отрицательный"
140
+ metric = model['metric']
141
+ col1, col2 = st.columns(2)
142
+ col1.metric(label=" # :heartpulse: Результат",
143
+ value=result,
144
+ )
145
+ col2.metric(label=" # Метрика",
146
+ value=str(metric),
147
+ )
148
+
149
+
150
+ if __name__ == "__main__":
151
+ main()
scripts/download_data.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Загрузка необходимых библиотек
2
+ from sklearn.datasets import fetch_openml
3
+ from sklearn.model_selection import train_test_split
4
+
5
+
6
+ def download_data():
7
+ # Загрузка датасета diabetes с помощью fetch_openml
8
+ cardio_data = fetch_openml("Cardiovascular-Disease-dataset", version=1, parser="auto")
9
+ cardio_data_df = cardio_data.frame
10
+ cardio_data_df['cardio'] = cardio_data_df['cardio'].apply(lambda x: 'positive' if x=='1' else 'negative')
11
+
12
+ # Разделение данных на обучающую и тестовую выборки
13
+ train_set, test_set = train_test_split(cardio_data_df, test_size=0.1, random_state=42)
14
+
15
+ return train_set, test_set
16
+
17
+
scripts/model_training.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sklearn.ensemble import RandomForestClassifier
2
+ from sklearn.pipeline import Pipeline
3
+ from scripts.download_data import download_data
4
+ from sklearn.metrics import f1_score
5
+ from sklearn.preprocessing import StandardScaler
6
+ from sklearn.preprocessing import PowerTransformer
7
+ from sklearn.preprocessing import OneHotEncoder
8
+ from sklearn.pipeline import Pipeline
9
+ from sklearn.compose import ColumnTransformer
10
+ from sklearn.preprocessing import QuantileTransformer
11
+ import pandas as pd
12
+
13
+ def calculate_metric(model):
14
+ _, test_set = download_data()
15
+ X_test, y_test = test_set.drop(columns=['cardio']), test_set['cardio']
16
+ y_pred = model.predict(X_test)
17
+ f1 = f1_score(y_test, y_pred, pos_label='positive')
18
+ return f1
19
+
20
+
21
+ def model_training():
22
+ train_set, _ = download_data()
23
+ X_train, y_train = train_set.drop(columns=['cardio']), train_set['cardio']
24
+
25
+ num_columns = ['age', 'height', 'weight', 'ap_hi', 'ap_lo',]
26
+ cat_columns = ['gender', 'cholesterol', 'gluc', 'smoke', 'alco', 'active']
27
+
28
+ num_pipe = Pipeline([
29
+ ('qt', QuantileTransformer(output_distribution="normal")),
30
+ ('scaler', StandardScaler()),
31
+ ('power', PowerTransformer()),
32
+ ])
33
+
34
+ cat_pipe = Pipeline([
35
+ ('encoder', OneHotEncoder(handle_unknown='ignore'))
36
+ ])
37
+
38
+ preprocessors_all = ColumnTransformer(transformers=[
39
+ ('num_p', num_pipe, num_columns),
40
+ ('cat_p', cat_pipe, cat_columns),
41
+ ])
42
+
43
+ pipe_all = Pipeline([
44
+ ('preprocessors', preprocessors_all),
45
+ ('model', RandomForestClassifier(n_estimators=200,
46
+ criterion = "gini",
47
+ min_samples_split=15,
48
+ max_depth=15,
49
+ oob_score=True)
50
+ )
51
+ ])
52
+
53
+ pipe_all.fit(X_train, y_train)
54
+
55
+ return pipe_all, calculate_metric(pipe_all)
56
+