С набором данных heart создаются и оцениваются 3 модели машинного обучения для прогнозирования наличия сердечных заболеваний.

В этом посте я собираюсь объяснить, как читать данные и строить 3 модели машинного обучения для обнаружения патологии пациента. Это будут модели бинарной классификации. Мы оценим каждую модель и определим, какая из них лучше. Это модели дерева решений, случайного леса и наивного байесовского алгоритма. Кроме того, я буду сравнивать модели, играя с данными. В конце поста я постараюсь объяснить, как повысить точность моделей. Это сердечная болезнь UCI от Kaggle [1]. Лицензия данных — Условия Reddit API.

Чтобы просмотреть код для лучшей визуализации и понимания, нажмите здесь.

Начиная

Нам нужно загрузить данные. В этой записной книжке мы будем использовать набор данных о сердечных заболеваниях с открытым исходным кодом, опубликованный здесь.

!pip install opendatasets
import opendatasets as od
od.download("https://www.kaggle.com/ronitf/heart-disease-uci")

Подготовка данных

Этот набор данных имеет следующие столбцы:

Непрерывные числовые столбцы

  • age: возраст в годах
  • trestbps: артериальное давление в покое
  • chol: холестерин сыворотки в мг/дл
  • thalach: достигнута максимальная частота сердечных сокращений
  • oldpeak: Депрессия ST, вызванная физической нагрузкой, по сравнению с состоянием покоя

Категорийные столбцы

  • sex: 1 = мужчина; 0 = женщина
  • cp: тип боли в груди (4 значения)
  • fbs: уровень сахара в крови натощак > 120 мг/дл. 1 = правда; 0 = ложь
  • restecg: результаты электрокардиографии в покое (значения 0,1,2)
  • exang: стенокардия, вызванная физической нагрузкой, 1 = да; 0 = нет
  • slope: наклон пикового сегмента ST при нагрузке (3 значения)
  • ca: количество крупных сосудов (0-3), окрашенных при флюороскопии
  • thal: талассемия, 1 = норма; 2 = фиксированный дефект; 3 = обратимый дефект
  • target: наличие порока сердца. 0 = положительный, 1 = отрицательный

Этот набор данных содержит столбец target, который является двоичным флагом, указывающим на наличие болезни сердца. Это целевой столбец, который мы хотим предсказать.

Чтобы увидеть первые и последние пять индексов данных в таблице:

# Reading Data:
df=pd.read_csv("/Users/esmasert/Desktop/CODES/Jupyter/DataAssessment/heart-disease-uci/heart.csv")
df.head()  # Showing the First Five Rows:

Чтобы увидеть имена столбцов и информацию о данных:

df.columns # Column Names
df.info() # Data Information

Мы можем увидеть, есть ли пропущенное значение в строках, перебирая все столбцы. И если есть, то какой процент?

for clmn in df.columns:
    any_missing = df[clmn].isnull().sum()
    print(f'{clmn} - {any_missing :.1%}')

Здорово! Нет пропущенного значения.

Теперь нам нужно проверить данные, чтобы увидеть, есть ли повторяющиеся строки. Чтобы увидеть это:

df.duplicated().sum() # Counting the duplicated rows

В данных есть повторяющаяся строка. Теперь мы должны справиться с этим, чтобы предотвратить любые негативные побочные эффекты для тренировочной части. Потому что избыточность может отрицательно сказаться на анализе данных, поскольку это значения, которые точно не нужны. Чтобы преодолеть это:

Мы можем транспонировать столбец и индексы для лучшей визуализации.

Теперь, чтобы лучше понять данные, мы можем перечислить уникальные значения каждой функции.

Мы закончили с числовой визуализацией, теперь давайте воспользуемся графиками!

print(f'Number of people identified as sex 0 are {df.sex.value_counts()[0]} and Number of people identified as sex 1 are {df.sex.value_counts()[1]}')
plt.figure(figsize=(7,7))
p = sns.set_theme(style="darkgrid")
p = sns.countplot(data=df, x="sex", palette='Set3')

Также попробуйте этот код! И вы будете удивлены результатами :)

g = sns.PairGrid(df, hue="target")
g.map_diag(sns.histplot)
g.map_offdiag(sns.scatterplot)
g.add_legend()

Теперь давайте посмотрим, сколько там людей того же возраста и пола.

import seaborn as sns
import matplotlib.pyplot as plt
 
plt.figure(figsize=(12,6))
 
# count plot on two categorical variable
sns.countplot(x ='age', hue = "sex", data = df)
 
# Show the plot
plt.show()

Как мы видим, у нас гораздо больше информации от самцов в данных. (1 = мужчина; 0 = женщина)

Из графиков видно, что сердечные заболевания чаще встречаются у мужчин. (Цель; 0 = положительный, 1 = отрицательный) (Пол; 1 = мужской; 0 = женский)

В возрасте от 55 до 63 лет риск сердечного приступа гораздо выше. (Цель; наличие болезни сердца. 0 = положительный, 1 = отрицательный)

Еще немного графиков:

Построение моделей

Подготовка данных

Выбор функций

Сначала нам нужно разделить заданные столбцы на два типа переменных; независимые (характеристические переменные) и зависимые (целевая переменные) переменные.

Разделение данных

Затем мы разделим набор данных на обучающий набор и тестовый набор, разделив наши данные на 80% для обучения и 20% для тестирования.

from sklearn.model_selection import train_test_split # to split the data

X_train, X_test, y_train, y_test = train_test_split(df.drop('target', 1), df['target'], 
                                                    test_size = .2, random_state=10) #split the data

Классификация дерева решений

Теперь давайте создадим модель дерева решений с помощью Scikit-learn.

import pandas as pd
from sklearn.tree import DecisionTreeClassifier # importing Decision Tree Classifier
from sklearn import metrics # metrics module for accuracy calculation
# Create Decision Tree Classifer object
clfDT = DecisionTreeClassifier()

# Train Decision Tree Classifer
clfDT = clfDT.fit(X_train,y_train)

#Predict the response for test dataset
y_pred = clfDT.predict(X_test)

Оценка модели

И рисуем дерево решений

Матрица путаницы

# Print Accuracy
print("Accuracy:",metrics.accuracy_score(y_test, y_pred))
print('\n')

from sklearn.metrics import plot_confusion_matrix

fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(15,7))

titles_options = [("Confusion matrix for Decision Tree, without normalization", None, axes.flatten()[0]),
                  ("Normalized confusion matrix for Decision Tree", 'true', axes.flatten()[1])]

for title, normalize, ax in titles_options:
    
    disp = plot_confusion_matrix(clfDT, X_test, y_test, cmap=plt.cm.Blues, ax=ax, normalize = normalize)
    
    disp.ax_.set_title(title)
    
    plt.rcParams['axes.grid'] = False

    print(title)
    print(disp.confusion_matrix)

plt.show()

Давайте нормализуем данные:

b = df.target.values
a_data = df.drop(['target'], axis = 1)

# Normalize
a = (a_data - np.min(a_data)) / (np.max(a_data) - np.min(a_data)).values
a_train, a_test, b_train, b_test = train_test_split(a, b, test_size = 0.2, random_state=0)
# Create Decision Tree classifer object
clfNorm = DecisionTreeClassifier()

# Train Decision Tree Classifer
clfNorm = clfNorm.fit(a_train,b_train)

#Predict the response for test dataset
b_pred = clfNorm.predict(a_test)

Здорово! Как вы видите здесь, мы можем повысить точность, нормализовав данные перед обучением.

Случайная классификация леса

Алгоритм случайного леса представляет собой алгоритм усреднения по ансамблю, основанный на рандомизированных деревьях решений.

#Import Random Forest Model
from sklearn.ensemble import RandomForestClassifier
#Create a Gaussian Classifier
clfRF=RandomForestClassifier(n_estimators=100)

#Train the model using the training sets y_pred=clf.predict(X_test)
clfRF.fit(X_train,y_train)

y_pred=clfRF.predict(X_test)

Оценка модели:

Матрица путаницы этой модели.

Если мы обучаем модель с нормализованными данными,

#Create a Gaussian Classifier
clfRFNorm=RandomForestClassifier(n_estimators=100)

#Train the model using the training sets y_pred=clf.predict(X_test)
clfRFNorm.fit(a_train,b_train)

b_predNorm=clfRFNorm.predict(a_test)

Здорово! Как вы видите здесь, мы повысили точность, нормализовав данные перед обучением с 0,770 до 0,868.

Поиск важных функций

Мы используем переменную важности функции, чтобы увидеть оценки важности функции. Затем мы визуализируем эти партитуры с помощью библиотеки seaborn.

feature_imp = pd.Series(clfRF.feature_importances_, index=X_train.columns.values.tolist()).sort_values(ascending=False)
feature_imp
from matplotlib import pyplot

# Creating a bar plot
fig, ax = pyplot.subplots(figsize=(14, 7))
sns.barplot(x=feature_imp, y=feature_imp.index)

# Add labels to your graph
plt.xlabel('Feature Importance Score',fontsize=15)
plt.ylabel('Features',fontsize=15)
plt.title("Visualizing Important Features",fontsize=18)
plt.legend()
plt.show()

Создание модели на основе выбранных объектов

Здесь мы можем удалить последние 4 признака (fbs,restecg,sex,exang), так как они имеют очень низкую важность, по мнению других, и выбрать остальные оставшиеся признаки.

# Split dataset into features and labels
RmX= df[['age','cp','trestbps','chol','thalach','oldpeak','slope','ca','thal']]  # Removed feature "sepal length"
Rmy= df['target']                         

# Split dataset into training set and test set
RmX_train, RmX_test, Rmy_train, Rmy_test = train_test_split(RmX, Rmy, test_size=0.20, random_state=5) # 80% training and 20% test
#Create a Gaussian Classifier
Rmclf=RandomForestClassifier(n_estimators=100)

#Train the model using the training sets y_pred=clf.predict(X_test)
Rmclf.fit(RmX_train,Rmy_train)

# prediction on test set
Rmy_pred=Rmclf.predict(RmX_test)

Оцените модель:

Отлично!! Точность увеличилась до 0,836 с 0,770.

Вы можете видеть, что после удаления наименее важных функций точность увеличилась. Это потому, что мы удалили вводящие в заблуждение данные и шум. Меньшее количество функций также сокращает время обучения. Поскольку мы удалили функции, которые имеют меньшее влияние, мы уже избавились от ненужных функций. Таким образом, нормализация данных может не работать с этим методом.

Наивная байесовская классификация

#Import Gaussian Naive Bayes model
from sklearn.naive_bayes import GaussianNB
#Create a Gaussian Classifier
NBclf = GaussianNB()

# Train the model using the training sets
NBclf.fit(X_train,y_train)

#Predict Output
NBy_pred = NBclf.predict(X_test) # 0:Overcast, 2:Mild

Оценить модель

Матрица путаницы:

Подходя к концу, я создал таблицу, в которой показаны все шаги, чтобы увидеть, как влияет точность модели.

Вывод

Сравнение моделей

Мы можем сравнить модели, просмотрев график,

colors = ['red','plum','slateblue','lavender','mediumaquamarine','silver','khaki','yellowgreen','lightskyblue']
plt.figure(figsize=(14,7))
plt.title("Accuracies of different models")
plt.xlabel("Algorithms")
plt.ylabel("Accuracy %")
plt.bar(results_df['Model'],results_df['Testing Accuracy %'], color = colors)
plt.xticks(rotation='vertical')

plt.show()

Как мы видим здесь, наиболее эффективным алгоритмом для достижения наивысшей точности является наивный байесовский алгоритм с нормализованными данными для набора данных UCI по сердечно-сосудистым заболеваниям. Даже точность обучения в алгоритме Наивного Байеса ниже, чем у других, результат точности теста, что интересно, является самым высоким.

Опять же, у меня была меньшая точность от наивного байесовского классификатора с FIF и результатом нормализованных данных. Кроме того, поскольку у меня не было более высокого результата для случайного леса с нормализованными данными и FIF, чтобы не усложнять внешний вид, я исключил наивный байесовский классификатор с FIF и результатом нормализованных данных из таблицы.

Как повысить точность

Нормализация данных

Нормализация данных — это тип процесса, при котором данные реорганизуются таким образом, чтобы пользователи могли правильно использовать их для дальнейших запросов и анализа. Цель нормализации — привести значения числовых столбцов в наборе данных к общему масштабу, не искажая различий в диапазонах значений.

Как видите, почти во всех методах метод нормализации оказал огромное влияние на точность. Поэтому использование этого метода будет полезным в большинстве случаев.

Ассемблирование

Для повышения точности модели можно использовать метод ансамбля. Цель методов ансамбля состоит в том, чтобы объединить прогнозы нескольких базовых оценок, построенных с помощью заданного алгоритма обучения, чтобы улучшить обобщаемость/надежность по сравнению с одной оценкой.

Существует два типа методов сборки:

  • Методы усреднения. Основной принцип заключается в независимом построении нескольких оценщиков, а затем в усреднении их прогнозов. В среднем комбинированная оценка обычно лучше, чем любая из оценок с одной базой, потому что ее дисперсия уменьшается.
  • Методы повышения: базовые оценки строятся последовательно, и каждый пытается уменьшить смещение комбинированной оценки. Мотивация состоит в том, чтобы объединить несколько слабых моделей для создания мощного ансамбля.

Мы уже использовали один метод усреднения по ансамблю, случайный лес. Поэтому продолжим с другими. Но, чтобы доказать положительные эффекты метода ансамбля, мы можем просто проверить результаты алгоритма случайного леса.

Поиск важных функций и удаление наименее важных

Важность признаков относится к классу методов присвоения оценок входным признакам в прогностической модели, которая указывает относительную важность каждого признака при прогнозировании.

Оценки полезны и могут использоваться в ряде ситуаций в задаче прогнозного моделирования, например:

  • Лучшее понимание данных.
  • Лучшее понимание модели.
  • Уменьшение количества входных признаков.
  • Сокращение времени обучения, меньшее количество точек данных снижает сложность алгоритма, и алгоритмы обучаются быстрее.
  • Сокращение переобучения, меньше избыточных данных означает меньше возможностей принимать решения на основе шума.
  • Повышение точности, меньше вводящих в заблуждение данных означает повышение точности моделирования.

Настройка гиперпараметров

Чтобы увидеть эффекты настройки гиперпараметров, мы настроим гиперпараметры модели случайного леса. Гиперпараметры, которые мы будем настраивать, включают max_features и n_estimators.

from sklearn.model_selection import GridSearchCV

max_features_range = np.arange(1,6,1)
n_estimators_range = np.arange(10,210,10)
param_grid = dict(max_features=max_features_range, n_estimators=n_estimators_range)

RanFrstCls = RandomForestClassifier()

gridSCV = GridSearchCV(estimator=RanFrstCls, param_grid=param_grid, cv=5)
gridSCV.fit(X_train, y_train)

Функция GridSearchCV() из scikit-learn используется для настройки гиперпараметров. В частности, функция GridSearchCV() может выполнять типичные функции классификатора, такие как соответствие, оценка и прогнозирование, а также прогнозирование_проблемы, решение_функции, преобразование и обратное_преобразование.

После настройки гиперпараметра для алгоритма случайного леса точность увеличилась до 85,9439 с 80,327869.

Это самая высокая точность среди всех опробованных нами методов классификации случайного леса!

Результаты

Когда мы обучили 3 алгоритма с набором данных UCI по сердечно-сосудистым заболеваниям, мы добились очень разной точности.

Пока мы искали, наилучшей точностью на данный момент является алгоритм наивного байесовского классификатора с нормализованными данными (90,1634).

Второй по точности алгоритм случайного леса с настроенными гиперпараметрами (85,9354).

И третье место по точности — это алгоритм повышения дерева градиентов из методов ансамбля. (85,2459)

Наконец, четвертое место по точности занимает классификатор случайного леса с методом поиска важных признаков. (83,6065)

В этом посте я попытался; поиск важных функций, объединение, настройка гиперпараметров и нормализация данных, чтобы увидеть, как они влияют на точность. Существует множество других методов, с помощью которых мы можем вносить изменения в данные перед обучением или моделями.

Из приведенной выше информации мы можем сделать вывод, что все алгоритмы, которые мы пробовали, достигли более высокой точности с дополнительными алгоритмами и методами. Все эффективности методов и алгоритмов меняются в зависимости от данных и того, на каком классификаторе они построены.

Большое спасибо за чтение!

использованная литература

[1] https://www.kaggle.com/ronitf/heart-disease-uci

[2] https://scikit-learn.org/stable/modules/ensemble.html

[3] https://medium.com/@urvashilluniya/why-data-normalization-is-necessary-for-machine-learning-models-681b65a05029

[4] https://machinelearningmastery.com/calculate-feature-importance-with-python/

[5] https://github.com/dataprofessor/code/blob/master/python

[6] https://www.datacamp.com/community/tutorials/