Аннотация
В этом учебном пособии шаг за шагом подробно описано, как создать модель прогнозирования на основе flask API на основе линейной регрессии, которая прогнозирует общую стоимость выписки из стационара на основе исторических данных и факторов, влияющих на эту стоимость. Этот проект разработан с учетом потребностей конечного пользователя и обеспечивает интуитивно понятный и простой пользовательский интерфейс.
Введение
По данным statista.com, расходы на здравоохранение на душу населения в Соединенных Штатах являются самыми высокими в мире. Это почти в два раза больше, чем в Германии со вторым по величине капитальным вложением. Это является причиной для беспокойства населения, относящегося к группе с низким доходом, и населения, которое не имеет или не может позволить себе медицинскую страховку. Какую пользу получат такие люди, если смогут узнать, сколько они должны заплатить в конце лечения, и будут ли расчетные расходы низкими/высокими в зависимости от местоположения.
Этот проект пытается решить эту проблему и фокусируется на создании удобного веб-приложения, которое может прогнозировать общую стоимость выписки из стационара на основе различных факторов. Приложение основано на модели машинного обучения, которая обучается на исторических данных за 2015 год для общих расходов на выписку из стационара.
О наборе данных
Мы получили эти данные от Общегосударственной системы планирования и исследований (SPARCS). SPARCS — это комплексная система отчетности по всем плательщикам, созданная в 1979 году в результате сотрудничества между отраслью здравоохранения и правительством Соединенных Штатов Америки.
Набор данных содержит обезличенные данные о выписке пациентов из больниц в штате Нью-Йорк. Набор данных содержит сведения об уровне выписки о характеристиках пациентов, диагнозах, лечении, услугах и расходах за каждое пребывание в стационаре и амбулаторное посещение (амбулаторная хирургия, отделение неотложной помощи и амбулаторные услуги). Этот набор данных содержит 34 столбца и 1 миллион строк, подробно описывающих каждый аспект выписки пациента.
Код
Этот проект разделен на две части:
· Часть A. Модель прогнозирования в Python.
· Часть B: Веб-приложение на основе Flask API.
Сначала мы рассмотрим Часть А: как построить модель.
Библиотеки, которые вам понадобятся для этой модели, перечислены ниже.
#importing libraries import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from pandas.api.types import is_string_dtype, is_object_dtype from pandas.api.types import is_categorical_dtype import matplotlib.pyplot as plt import seaborn as sns from joblib import dump,load from sklearn.metrics import mean_absolute_error, r2_score
Вы можете узнать больше об этих библиотеках на следующих страницах документации. Numpy, Pandas, sklearn, matplotlib, seaborn, joblib
Структура модели
Это проблема регрессии, поэтому мы будем использовать RandomForestRegressor в качестве алгоритма нашей модели.
1. Загрузка данных
2. Очистка данных
3. Исследовательский анализ данных
4. Подготовка данных для модели
5. Создание и обучение модели
6. Оценка модели< br /> 7. Окончательное извлечение модели для веб-приложения.
Давайте посмотрим на них один за другим.
- Загрузка данных. Здесь мы загружаем необработанные данные с помощью функции pandas
.read_csv()
.
#loading the dataset into a pandas dataframe data = pd.read_csv('data_2015.csv', low_memory=False) #as we have over a million rows we have turned off the low memory flag #printing the shape of the orignal dataset print("Shape of orignal data", data.shape) print("\n") #printing the dataframe columns in transpose to get an idea about the data print(data.head(5).T)
2.Очистка данных. Общие шаги по очистке данных включают удаление ненужных столбцов, удаление строк с нулевыми значениями, удаление дубликатов и правильное форматирование строк/целых чисел.
#during the initial testing phase we have identified the following columns that have very little effect on the accuracy. #hence removing such columns data1 = data.drop(['Operating Certificate Number','Facility Name', 'CCS Diagnosis Description','CCS Procedure Description', 'APR DRG Description','APR MDC Description', 'Discharge Year', 'APR Severity of Illness Description','Abortion Edit Indicator','Zip Code - 3 digits', 'Emergency Department Indicator','Payment Typology 2','Payment Typology 3'], axis=1) #checking for null values print(data1.isnull().sum()) #dropping all the rows that contain null values data1 = data1.dropna() print("\n") print("Shape of data after dropping NA rows", data1.shape) #printing the unique values from the dataframe columns print(data1.apply(lambda col: col.unique())) #changing the data type of column length of stay data1['Length of Stay'].replace({"120 +": "120"}, inplace=True) data1['Length of Stay'] = data1['Length of Stay'].astype(str).astype(int)
3. Исследовательский анализ данных (EDA):EDA — это следующий шаг после очистки данных, чтобы увидеть, какие интересные вещи мы можем сделать из наших данных. Это также показывает, как наши данные могут быть обработаны и какая информация актуальна.
#checking the distribution of Length of stay a4_dims = (11.7, 8.27) fig, ax = plt.subplots(figsize=a4_dims) sns.displot(data1, x="Length of Stay", kind="kde") #checking the distribution of Birth weight sns.displot(data1, x="Birth Weight", kind="kde")
График распределения по возрастным группам.
#plotting the distribution of age group a4_dims = (11.7, 8.27) fig, ax = plt.subplots(figsize=a4_dims) sns.countplot(ax=ax, x="Age Group", palette="ch:.25", data=data1)
Дальнейшее EDA: здесь мы видим, что при проверке мы обнаружили, что столбцы, упомянутые в коде, оказывают значительное влияние на точность модели. Такие результаты могут быть получены путем повторных проб и ошибок.
#upon futher inspection it was found that only the following columns have significant inpact on the model accuracy. #storing these columns in a new dataframe data_new = data1[['Hospital County','Age Group','Gender','Length of Stay','Type of Admission','Payment Typology 1','Total Charges','Total Costs']] #our final dataset looks like this data_new.head()
4. Предварительная обработка данных для модели. Поскольку это регрессионная модель, большинство моделей машинного обучения принимают данные только в числовой форме. В наших данных есть как числовые, так и категориальные столбцы. Чтобы преобразовать нечисловые данные в числовые данные, мы используем форму категориального кодирования. Эта функция кодирует различные категории в каждом столбце и присваивает им определенный номер.
После кодирования мы разделяем целевой столбец из набора обучающих данных и далее разделяем данные на обучающие и тестируемые для обучения модели с помощью функции traintestsplit()
.
import warnings warnings.filterwarnings("ignore") # Functions to convert non-numeric to numeric - 1 def wkng_data1_string_to_cat(wkng_data1): for col in wkng_data1.columns: if is_string_dtype(wkng_data1[col]) or is_object_dtype(wkng_data1[col]): wkng_data1[col] = wkng_data1[col].astype('category').cat.as_ordered() # Functions to convert non-numeric to numeric - 2 def wkng_data1_cat_to_catcode(wkng_data1): for col in wkng_data1.columns: if is_categorical_dtype(wkng_data1[col]): wkng_data1[col] = wkng_data1[col].cat.codes + 1 #applying functions on the dataset wkng_data1_string_to_cat(data_new) wkng_data1_cat_to_catcode(data_new) #data1 = data1.head(40000) #renaming columns for simplicity data_new = data_new.rename(columns={"Hospital County": "hospitalcounty", "Age Group": "agegroup", "Gender": "gender", "Length of Stay": "lengthofstay", "Type of Admission": "admissiontype", "Payment Typology 1": "paymentmethod", "Total Charges": "totalcharges", "Total Costs": "totalcosts"}, errors="raise") #verifying that the rename worked sucessfully print(data_new.info()) print("\n") #labels are the values that we want to predict labels = np.array(data_new['totalcharges']) #removing labels from features inputs = data_new.drop('totalcharges', axis = 1) #saving cols name for future use cols_list = list(data_new.columns) #converting to numpy array inputs = np.array(inputs) #splitting the data into train and test sets for model training with test size 30% of the total data. train_x, test_x, train_y, test_y = train_test_split(inputs, labels, test_size = 0.30, random_state = 9) print("Shape of training inputs", train_x.shape) print("Shape of training labels",train_y.shape) print("Shape of testing data",test_x.shape) print("Shape of testing labels",test_y.shape)
Вы можете сохранить тестовые файлы для дальнейшего использования.
#saving the test files for further use np.savetxt("test_x.csv", test_x, delimiter=",") np.savetxt("test_y.csv", test_y, delimiter=",")
5. Создание и обучение модели. Мы инициализируем алгоритм модели RandomForestRegressor()
с 200 оценщиками. Это указывает количество деревьев, которые должны быть использованы, прежде чем принимать максимальное голосование или средние значения прогнозов. Мы также указываем метрику n_jobs (этот флаг указывает системе использовать для обработки все доступные ядра процессора). Мы подгоняем модель к данным поезда и получаем значение oob_score, которое мы получили как 0,926660.
#initializing the model model = RandomForestRegressor(n_estimators = 200, #using RandomForestRegressor with n_estimator 200 and metric=oob_score oob_score=True, n_jobs = -1, random_state = 9) model.fit(train_x, train_y) #fitting the model on training data oob_score = model.oob_score_ #obtaining the oob score print(f" {oob_score:f}", end='') #printing the oob score
Проверка прогноза. Мы используем функцию model.predict()
для применения к тестовым данным для получения прогнозов.
#using the .predict method on the model to get predictions from the test data pred = model.predict(test_x) #comparing predicted and actual values print("Printing top 4 values from the predictions:", pred[0:4]) print("\n") print("Printing top 5 values fromt the test labels", test_y[0:4])
6. Оценка модели.Оценка модели важна, поскольку она помогает найти наилучшую модель, которая представляет наши данные и насколько хорошо выбранная модель будет работать в будущем.
#creating emptly list for storing final metrics train_r2 = [] train_mae = [] test_r2 = [] test_mae = [] oob_scores = [] #applying predict function on the train data train_preds = model.predict(train_x) #getting the r2 score train_r2.append(round(r2_score(train_y, train_preds), 4)) test_r2.append(round(r2_score(test_y, pred), 4)) #getting the Mean absolute error train_mae.append(round(mean_absolute_error(train_y, train_preds), 0)) test_mae.append(round(mean_absolute_error(test_y, pred), 0)) #getting the oob score oob_scores.append(round(model.oob_score_, 4)) #printing everything print("Train r2 scores: \n", train_r2) print("") print("Test r2 scores: \n", test_r2) print("") print("Train MAE scores: \n", train_mae) print("") print("Test MAE scores: \n", test_mae) print("") print("oob_scores: \n", oob_scores)
7. Извлечение модели в файл .joblib. Затем этот файл используется в качестве движка для нашего приложения.
#using dump from the joblib library, saving the model in .joblib format for further use dump(model,'modelpredictorengine.joblib')
Часть Б. Создание приложения Flask
Вы можете найти весь код этого проекта в моем репозитории на Github.
Структура каталогов для этого приложения.
Эта структура называется структурой шаблона представления модели, и, хотя она может не соответствовать отраслевому стандарту, она очень тесно связана с ним.
Файл app.py содержит основную логику приложения, которая загружает файл joblib, загружает используемые входные данные, преобразует их в фрейм данных и применяет к нему функцию model.predict для получения прогноза. Затем этот прогноз сохраняется в переменной и отображается во внешнем интерфейсе с использованием шаблона html.
Некоторые фрагменты кода из app.py, чтобы лучше понять процесс.
Требуемые библиотеки:
from os import readlink import flask import pandas as pd import numpy as np from joblib import dump, load import csv
Загрузка модели и инициализация файла app.py
#loading the model in read mode with open(f'modelpredictorengine.joblib', 'rb') as f: model = load(f) #initializing the app.py file app = flask.Flask(__name__, template_folder='templates')
Корневая страница (или домашняя страница вашего приложения)
@app.route('/', methods=['GET', 'POST']) def main(): if flask.request.method == 'GET': return (flask.render_template('main.html'))
Основная логика ввода и прогнозирования
input_variables = pd.DataFrame([[hospitalcounty, agegroup, gender, lengthofstay, admissiontype, paymentmethod, totalcosts]], columns=['hospitalcounty', 'agegroup', 'gender', 'lengthofstay', 'admissiontype', 'paymentmethod', 'totalcosts'], dtype='float', index=['input']) predictions = np.round(model.predict(input_variables)[0]) print(predictions) return flask.render_template('main.html', original_input={'hospitalcounty': hospitalcounty, 'agegroup': agegroup, 'gender': gender, 'lengthofstay': lengthofstay, 'admissiontype': admissiontype, 'paymentmethod': paymentmethod, 'totalcosts': totalcosts}, result=predictions)
Для запуска этого приложения в вашей системе должен быть установлен Flask. Flask — это среда веб-разработки для Python, которую можно установить как модуль Python. Он имеет много интересных функций, таких как маршрутизация URL-адресов и механизм шаблонов. Вы можете установить Flask, следуя этому руководству.
Действия для запуска этого приложения:
Предположим, что вы запустили код создания модели и был создан файл model.joblib. Следующим шагом будет запуск файла app.py. Мой предпочтительный способ выполнить это — использовать IDE, например VS Code. Использование такой IDE полезно, так как большинство из них имеют встроенную интеграцию с терминалом, отладчик и окно вывода, а также подсветку синтаксиса.
После того, как вы запустите файл app.py, вы увидите что-то подобное в окне терминала.
Если вы видите это поздравление, вы успешно запустили веб-сервер flask и нажимаете ссылку, отображаемую в терминале, чтобы увидеть, как работает ваше приложение. Это должно выглядеть так.
Это приложение имеет семь полей ввода, которые имеют различные параметры, указанные в соответствующем раскрывающемся меню. После выбора параметров нажмите «Отправить», чтобы просмотреть прогнозируемую цену. Вы также можете увидеть необработанный ввод, который поступает в механизм прогнозирования.
Заключение
Этот проект создан, чтобы помочь пользователям принимать обоснованные решения при выборе различных факторов, влияющих на стоимость здравоохранения, и достигает цели, предоставляя удобный и интуитивно понятный интерфейс для ввода переменных и получения прогноза расходов, которые могут иметь место. платить. Проект использует машинное обучение для изучения исторических данных, основанных на больницах в штате Нью-Йорк. Однако этот проект можно масштабировать, включив в него множество местоположений и данных. Это можно сделать с помощью механизма обработки больших данных в реальном времени, такого как Cassandra. Будущий объем этого проекта включает в себя добавление механизма рекомендаций, чтобы показать, какие места предлагают низкие цены на медицинские услуги для тех же факторов. Кроме того, с более мощной системой можно повысить точность модели.
Пожалуйста, обращайтесь с любыми вопросами, разъяснениями или вопросами авторского права по адресу [email protected]. В качестве альтернативы вы можете написать мне на моей странице Linkedin.