Аннотация

В этом учебном пособии шаг за шагом подробно описано, как создать модель прогнозирования на основе 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. Окончательное извлечение модели для веб-приложения.

Давайте посмотрим на них один за другим.

  1. Загрузка данных. Здесь мы загружаем необработанные данные с помощью функции 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.