От начала до конца, от начала

Мы слышали модные слова: наука о данных, машинное обучение, прогнозное моделирование, но что они означают? Как мы можем использовать эту технологию в реальном мире для принятия эффективных решений?

Этот сквозной проект был создан, чтобы продемонстрировать именно это.

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

А как мы узнаем, какая информация полезна? Здесь на помощь приходит машинное обучение. Машинное обучение дает системам и пользователям (таким как мы) возможность выявлять скрытые идеи на основе наших данных с помощью алгоритмов . Алгоритмы используют статистическое моделирование для прогнозирования выходного значения на основе входных данных.

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

Мы можем дополнительно разделить контролируемое обучение на основе типа результата: классификация, где наш прогнозируемый результат является двоичным (0/1), или регрессионным, где наш прогнозируемый результат является непрерывным. При работе над проблемой машинного обучения важно понимать тип результата - мыслительный процесс и методологии различаются для обоих типов задач.

Эта статья предоставит подробное описание шагов для сквозного проекта с использованием набора данных Framingham Heart Study. Данные взяты из продолжающегося исследования сердечно-сосудистой системы с участием людей из Фрамингема, штат Массачусетс, где участников исследования отслеживают на предмет риска ишемической болезни сердца (ИБС) на основе 15 различных переменных. С помощью этого набора данных мы определим наиболее релевантные переменные для результата и спрогнозируем общий риск диагностирования ИБС.

Давайте начнем.

Примечание. В этой статье предполагается, что вы знакомы с Python IDE. Весь код и визуализации из этой статьи были созданы в Jupyter Notebook и их можно найти на моем GitHub.

Шаг 1. Определение проблемы

Поскольку метка вывода предоставлена ​​нам (TenYearCHD), мы знаем, что это контролируемая проблема. Мы стремимся разделить людей на две (бинарные) категории: тех, у кого развивается ВПС (1), и тех, у кого нет ВПС (0), поэтому это проблема классификации.

Шаг 2. Загрузка данных

Мы будем использовать библиотеки Python NumPy, Pandas и Seaborn для загрузки, исследования и визуализации данных. Библиотека Seaborn основана на Matplotlib и создает чистые и удобные для чтения визуализации.

#Data loading and visualization 
import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

После считывания данных (набор данных можно загрузить из Kaggle в виде файла CSV) следующим шагом является проверка данных перед переходом к очистке данных - мы хотим понять форму набора данных, различные типы данных, включены переменные и целевая переменная.

#Reading in data
fhs = pd.read_csv('/Users/harikapanuganty/Desktop/framingham.csv')
fhs.head()
#Shape of data
fhs.shape
#Information about a DataFrame
fhs.info()

Шаг 3. Очистка данных

В реальных наборах данных и проектах нам не предоставляется аккуратный и чистый CSV-файл - будут несовместимые типы данных, отсутствующие / нулевые значения и дубликаты. Как говорится, «мусор на входе, мусор на выходе»: модель машинного обучения может быть настолько хороша, насколько хороши исходные данные, которые она предоставляет.

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

#Looking for null values
fhs.isnull().sum() 

Мы замечаем, что в нескольких столбцах пропущено одно или несколько значений. Два самых популярных способа справиться с отсутствующими данными - это либо удаление затронутых строк (или столбца вместе), либо подстановка пропущенных значений. Основываясь на столбце и количестве пропущенных значений, я решил чередовать отбрасывание строк, заполнение нулевых значений средними и интерполяционными значениями.

fhs = fhs.dropna(subset = ['heartRate'])
fhs['cigsPerDay'].fillna(int(fhs['cigsPerDay'].mean()), inplace=True)
fhs['totChol'].fillna(int(fhs['totChol'].mean()), inplace=True)
fhs['BPMeds'].fillna(int(fhs['BPMeds'].mean()), inplace=True)
fhs['BMI'].interpolate(method='pad', direction = 'forward', inplace=True)
fhs['glucose'].interpolate(method='pad', direction = 'forward', inplace=True)
fhs.dropna(subset = ['education'], inplace=True)

Шаг 4. Исследовательский анализ данных

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

  • Коробчатые диаграммы

Мы можем идентифицировать выбросы, построив коробчатую диаграмму. Любые точки данных, которые находятся за пределами верхней и нижней линий поля, являются явными выбросами (например, крайние точки данных в столбцах totChol и sysBP) и должны быть удалены.

plt.figure(figsize=(20,35))
sns.boxplot(data=fhs)
plt.show()

  • Корреляционные тепловые карты

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

fhs_corr = fhs.corr()
plt.figure(figsize=(20,10))
sns.heatmap(fhs_corr)
plt.title("Correlation between features", size=20)
fhs_corr

Когда значение на боковой панели:
ближе к 0, нет линейной корреляции между двумя переменными
ближе к +1, есть положительная корреляция между двумя переменными
ближе к - 1, между двумя переменными существует отрицательная корреляция

Например, цвет sysBP square на оси y по сравнению с квадратом TenYearCHD на оси x, является светло-розовато-пурпурным и соответствует ~ 0,3 на боковой панели. Это указывает на то, что sysBP положительно коррелирует с переменной TenYearCHD.

  • Графики

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

numeric_vars_fhs = ['cigsPerDay', 'totChol', 'sysBP', 'diaBP', 'BMI', 'heartRate', 'glucose']
for var in numeric_vars_fhs:
    plt.figure(figsize=(8,8))
    sns.distplot(fhs[var])
    plt.title('{} Distribution'.format(var))
    plt.show()

Примером нормально распределенной переменной может быть sysBP, тогда как cigsPerDay сильно перекошен и наклонен вправо.

  • Графики

Столбчатые диаграммы обычно используются для построения взаимосвязи между двумя категориальными переменными. Возьмем, к примеру, переменные gender и TenYearCHD, мы ясно видим, что у мужчин риск развития ИБС немного выше, чем у женщин.

plt.figure(figsize=(8,6))
sns.barplot(x=gender_graph["male"], y=gender_graph["TenYearCHD"])
plt.title("Graph showing which gender has more risk of coronary heart disease CHD", size=15)
plt.xlabel("Gender\n0 is female and 1 is male",size=15)
plt.ylabel("TenYearCHD cases", size=15)

  • Графики

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

plt.figure(figsize=(30,12), facecolor='w')
sns.countplot(x='TenYearCHD', data=fhs, hue='cigsPerDay')
plt.legend(title = 'cigsPerDay', fontsize='large')
plt.title("Graph showing the relationship between cigsPerDay and risk of developing CHD", size=28)
plt.xlabel("Risk of developing, TenYearCHD", size=25)
plt.ylabel("Count, TenYearCHD", size=25)
plt.show()

Из этого графика мы видим, что cigsPerDay (числовой) положительно коррелирует с TenYearCHD (категориальным), то есть чем больше сигарет выкуривает человек в день, тем больше у него вероятность развития ИБС.

  • Графики

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

plt.figure(figsize=(8,8))
sns.regplot(x=sysbp_graph["TenYearCHD"], y=sysbp_graph["sysBP"])
plt.title("Distribution of sysBP in relation to developing CHD", size=15)

Глядя на sysBP (числовой) и TenYearCHD (категориальный), мы можем увидеть линейно возрастающую линию, которая указывает на положительную взаимосвязь между обеими переменными. Риск развития TenYearCHD увеличивается по мере sysBP увеличения.

Шаг 5. Выбор функции

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

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

  • SelectKBest: вычисляет статистику chi² между каждой характеристикой меток классов X и y и возвращает первые k функций с наивысшими баллами.
from sklearn.feature_selection import SelectKBest, chi2
bestfeatures_skb = SelectKBest(score_func=chi2, k=8)
fit_skb = bestfeatures_skb.fit(X,y) 
dfscores = pd.DataFrame(fit_skb.scores_)
dfcolumns = pd.DataFrame(X.columns)
featureScores = pd.concat([dfcolumns,dfscores],axis=1)
featureScores.columns = ['Specs','Score']  
print(featureScores.nlargest(10,'Score'))  

  • Общая классификация информации: измеряет зависимость характеристик от целевой переменной, более высокий балл указывает на большую зависимость переменной.
from sklearn.feature_selection import mutual_info_classif
threshold = 10  
high_score_features = []
feature_scores = mutual_info_classif(X, y, random_state=1)
for score, f_name in sorted(zip(feature_scores, X.columns), reverse=True)[:threshold]:
        print(f_name, score)
        high_score_features.append(f_name)
feature_scores_mic = X[high_score_features]

Последними функциями в нашей модели будут сочетания основных функций из результатов SelectKBest и Mutual Information Classification: sysBP, age, totChol, diaBP, prevalentHyp, diabetes, BPMeds и male.

fhs = fhs[['sysBP', 'age', 'totChol', 'diaBP', 'prevalentHyp', 'diabetes', 'BPMeds', 'male','TenYearCHD' ]]
fhs.head()

Шаг 6. Предварительная обработка данных

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

  • Разделение на обучение и тест. Мы разделяем наш один набор данных на два подмножества: первое подмножество (обучающий набор данных) соответствует модели, а второе подмножество (тестовый набор данных) используется для оценки прогнозов на основе обучающих данных. тестовые данные. Если мы не разделим наш набор данных, модель «увидит» все данные и не сможет точно предсказать эффективность новых данных.
from sklearn.model_selection import train_test_split
X = fhs.drop(['TenYearCHD'], axis=1) 
y = fhs['TenYearCHD'] 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=25)
  • Масштабирование функций. Мы хотим, чтобы каждая точка данных в наших функциях имела одинаковый вес. Метод масштабирования функций зависит от распределения наших данных, в нашем случае распределение нормальное, поэтому мы будем использовать Min Max Scaler.
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
  • Повторная выборка несбалансированной переменной. Взглянув на форму набора данных перед повторной выборкой, мы видим, что наша целевая переменная TenYearCHD сильно несбалансирована. Если мы будем использовать эту переменную для прогнозирования, наши модели будут отдавать предпочтение классу большинства и игнорировать класс меньшинства, в результате чего модели будут иметь высокую точность, но низкую отзывчивость. Есть несколько способов решить эту проблему, но мы воспользуемся методом SMOTE, который передискретизирует класс меньшинства путем создания новых выборок из существующих.
from imblearn.over_sampling import SMOTE
sm = SMOTE(random_state=1)
X_sm, y_sm = sm.fit_resample(X,y)
print(f'''Shape of X before SMOTE: {X.shape}
Shape of X after SMOTE: {X_sm.shape}''')
print('\nNumber of positive and negative instances in both classes (%):')
y_sm.value_counts(normalize=True) * 100

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

Теперь мы готовы к алгоритмам машинного обучения.

Шаг 7. Прогностическое моделирование

Есть несколько алгоритмов, которые хорошо подходят для задач классификации. В этом проекте будут реализованы четыре из этих алгоритмов (и их гипертонастроенные аналоги): логистическая регрессия, случайный лес, K-ближайших соседей и машины опорных векторов.

  • Логистическая регрессия: широко используемый алгоритм классификации, когда ожидаемый результат является двоичным (да / нет или 0/1). Этот алгоритм оказывается полезным при понимании влияния одной или нескольких независимых переменных на одну конечную переменную.
from sklearn.linear_model import Logistic Regression
from sklearn.metrics import confusion_matrix, accuracy_score, roc_curve, classification_report
lr = LogisticRegression(random_state=25, max_iter=100)
lr_model = fhs_lr.fit(X_train, y_train) 
lr_predict = fhs_lr.predict(X_test)
lr_accuracy = accuracy_score(y_test, lr_predict) 
lr_cm = confusion_matrix(y_test, lr_predict)
print("Accuracy of Logistic Regression:", lr_accuracy)
print("Logistic Regression Confusion Matrix:", lr_cm)
print(classification_report(y_test, lr_predict))

  • Случайный лес. Случайный лес - это несколько соединенных вместе деревьев решений, которые эффективны как для классификации, так и для задач регрессии. Что такое дерево решений? Подобно блок-схеме, дерево решений разбивает данные на более мелкие подмножества, пока алгоритм не найдет наименьшее дерево, которое соответствует данным. Хотя отдельные деревья легко интерпретировать и хорошо обрабатывать данные, они подвержены переобучению и дают результаты с низкой точностью. Объединение нескольких деревьев в модель, то есть случайный лес, повышает производительность каждой отдельной модели дерева в одну сильную модель дерева.
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import confusion_matrix, accuracy_score, roc_curve, classification_report
rf = RandomForestClassifier(n_estimators=100, random_state=25, max_depth=12)
rf.fit(X_train, y_train)
rf_predict = rf.predict(X_test)
rf_accuracy = accuracy_score(y_test, rf_predict)
rf_cm = confusion_matrix(y_test, rf_predict)
print("Accuracy of Random Forest:", rf_accuracy)
print("Random Forest Confusion Matrix:", rf_cm)
print(classification_report(y_test, rf_predict))

  • K-ближайшие соседи: этот алгоритм работает в предположении, что похожие точки данных существуют рядом друг с другом. KNN объединяет эту идею «близости» для расчета расстояния между точками данных. Взяв конкретное значение для K, например K = 5, мы рассмотрим 5 точек данных, ближайших к неизвестной точке данных, и основная метка между этими точками будет назначена неизвестной точке данных.
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix, accuracy_score, roc_curve, classification_report
knn = KNeighborsClassifier(n_neighbors=5)
knn_model = knn.fit(X_train, y_train)
knn_predict = knn.predict(X_test)
knn_cm = confusion_matrix(y_test, knn_predict)
knn_accuracy = accuracy_score(y_test, knn_predict)
print("Accuracy of KNN Classification:", knn_accuracy)
print("KNN Classification Confusion Matrix:", knn_cm)
print(classification_report(y_test, knn_predict))

  • Машина опорных векторов. Этот алгоритм создает линейный разделитель, который делит группу точек данных на два класса (для классификации), классифицируя каждую точку данных в один из двух классов.
from sklearn.svm import SVC
from sklearn.metrics import confusion_matrix, accuracy_score, roc_curve, classification_report
svm = SVC()
svm_model = svm.fit(X_train, y_train)
svm_predict = svm.predict(X_test)
svm_cm = confusion_matrix(y_test, svm_predict)
svm_accuracy = accuracy_score(y_test, svm_predict)
print("Accuracy of SVM Classification:", svm_accuracy)
print("SVM Classification Confusion Matrix:", svm_cm)
print(classification_report(y_test, svm_predict))

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

С большинством моделей мы также можем настраивать гиперпараметры (воспринимать это как настройки алгоритма) для оптимизации производительности модели. Scikit-learn включает набор гиперпараметров по умолчанию для всех моделей, но эти значения не гарантируют лучших результатов. GridSearch и RandomizedSearch - общие методы настройки, используемые для поиска оптимальных значений; все гипертонастроенные модели в этом проекте использовали RandomizedSearch (с помощью этого метода мы выбираем комбинации гиперпараметров случайным образом на основе диапазона значений)

Гипертонастроенный случайный лес:

Скорректированные гиперпараметры:

  • n_estimators: количество деревьев в лесу.
  • max_features: максимальное количество функций, необходимых перед каждым разделением.
  • max_depth: максимальное количество уровней в каждом дереве.
  • min_samples_split: минимальное количество выборок, необходимое для разделения узла.
  • min_samples_leaf: минимальное количество образцов, необходимое для каждого узла.
  • bootstrap: метод выбора образцов для обучения каждого дерева
from sklearn.model_selection import RandomizedSearchCV
from sklearn.metrics import confusion_matrix, accuracy_score, roc_curve, classification_report
# Number of trees in forest 
n_estimators = [int(x) for x in np.linspace(start= 100, stop = 1000, num = 10)]
# Max number of features needed before each split
max_features = ["auto", "sqrt"]
# Max no. of levels in each tree
max_depth = [int(x) for x in np.linspace(start=10, stop=100, num = 10)] 
max_depth.append(None)
# Min no. of samples needed to split a node  
min_samples_split = [2, 5, 10]
# Min no. of samples needed at each node 
min_samples_leaf = [1, 2, 4]
# Method of choosing samples for training each tree
bootstrap = [True, False]
# Create the random grid to sample from during fitting
rf_grid = {'n_estimators': n_estimators,
               'max_features': max_features,
               'max_depth': max_depth,
               'min_samples_split': min_samples_split,
               'min_samples_leaf': min_samples_leaf,
               'bootstrap': bootstrap}
print(rf_grid)

После того, как мы создали сетку, мы можем создать экземпляр объекта и подогнать его под другие модели scikit-learn.

#instantiating object 
rf_hyp = RandomForestClassifier()
#Random search of parameters through 3-Fold cross-validation 
rf_hyp_rs = RandomizedSearchCV(estimator=rf_hyp, param_distributions = rf_grid, n_iter=100, cv=3, verbose=2, random_state=25, n_jobs=-1)
#Fit model
rf_hyp_rs.fit(X_train, y_train)
rf_hyp_model = rf_hyp_rs.best_estimator_
rf_hyp_model.fit(X_train, y_train)
rf_hyp_predict = rf_hyp_model.predict(X_test)
rf_hyp_cm = confusion_matrix(y_test, rf_hyp_predict)
rf_hyp_accuracy = accuracy_score(y_test, rf_hyp_predict)
print("Accuracy of Hypertuned Random Forest:", rf_hyp_accuracy)
print("Hypertuned Random Forest:", rf_hyp_cm)
print(classification_report(y_test, rf_hyp_predict))

Hypertuned K-Nearest Neighbours

Скорректированные гиперпараметры:

  • leaf_size: влияет на скорость и память запроса, передаваемого алгоритму (в данном случае Balltree)
  • n_neighbors: количество соседей
  • p: метрический параметр мощности Минковского
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix, accuracy_score, roc_curve, classification_report
# affects speed and memory of query, passed on to algorithm (balltree or kdtree)
leaf_size= list(range(1,50))
# Number of neighbors 
n_neighbors= list(range(1,30))
# minkowski metric power parameter 
p= [1,2]
#creating the dict 'grid'
knn_hyperparameters = dict(leaf_size=leaf_size, n_neighbors=n_neighbors, p=p)

После того, как мы создали сетку, мы можем создать экземпляр объекта и подогнать его под другие модели scikit-learn.

#Create base model to tune and use grid to find best hyperparameters 
knn_hyp_obj = KNeighborsClassifier()
#Random search of parameters through 3-Fold cross-validation 
knn_hyp_grid = RandomizedSearchCV(knn_hyp_obj, knn_hyperparameters, random_state = 25, cv=3, n_jobs=-1)
#Fit random search model
knn_hyp_model = knn_hyp_grid.fit(X_train, y_train)
knn_hyp = KNeighborsClassifier(n_neighbors=28, leaf_size=20, p=1)
knn_model_hyp = knn_hyp.fit(X_train, y_train)
knn_predict_hyp = knn_hyp.predict(X_test)
knn_cm_hyp = confusion_matrix(y_test, knn_predict_hyp)
knn_hyp_accuracy = accuracy_score(y_test, knn_predict_hyp)
print("Accuracy of Hypertuned KNN Classification:", knn_hyp_accuracy)
print("Hypertuned KNN Classification Confusion Matrix:", knn_cm_hyp)
print(classification_report(y_test, knn_predict_hyp))

Гипертонастроенная машина опорных векторов

Скорректированные гиперпараметры:

  • C: параметр регуляризации
  • Ядро: тип ядра (может быть линейным, поли, rbf, сигмоидным, предварительно вычисляемым или вызываемым)
  • Гамма: коэффициент ядра (rbf, poly, sigmoid)
from sklearn.svm import SVC
from sklearn.metrics import confusion_matrix, accuracy_score, roc_curve, classification_report
svm_param_grid = {'C': [0.1, 1, 10, 100], 
                 'gamma': [1, 0.1, 0.01, 0.001, 0.0001],
                 'kernel': ['rbf']}
svm_hyp_rs = RandomizedSearchCV(SVC(), svm_param_grid, refit=True, verbose=1, n_jobs=-1)
svm_hyp_rs.fit(X_train, y_train)
svm_hyp_model = svm_hyp_rs.best_estimator_
svm_hyp_model.fit(X_train, y_train)
svm_hyp_predict = svm_hyp_model.predict(X_test)
svm_hyp_cm = confusion_matrix(y_test, svm_hyp_predict)
svm_hyp_accuracy = accuracy_score(y_test, svm_hyp_predict)
print("Accuracy of Hypertuned Support Vector Machine:", svm_hyp_accuracy)
print("Hypertuned Support Vector Machine:", svm_hyp_cm)
print(classification_report(y_test, svm_hyp_predict))

Шаг 9. Оценка модели

Чтобы оценить наши модели, мы будем использовать точность и матрицу неточностей. Точность классификации - это отношение количества правильных прогнозов к общему количеству входных выборок. Лучше всего он работает, когда каждый класс имеет равное количество выборок (у обоих наших классов это так, поскольку на предыдущем шаге мы выполняли повторную выборку для баланса). Конечная цель - получить максимально возможную точность, редкую 100% - точность для всех наших моделей составляет от 83 до 84%. На первый взгляд это выглядит неплохо.

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

  • Тип 1 / ложноположительный результат: модель указывает на то, что у человека разовьется ИБС, хотя на самом деле этого не произойдет. Мы отвергаем нулевую гипотезу, когда она действительно верна.
  • Тип 2 / Ложноотрицательный: модель указывает на то, что у человека не разовьется ИБС, хотя на самом деле он будет. Мы не можем отвергнуть нулевую гипотезу, когда она на самом деле ложна.

Возвращаясь к нашему случаю, какая ошибка хуже? Они оба плохие, но, вероятно, Тип 2. Мы не хотим говорить участникам исследования, что у них нет ИБС, только для того, чтобы они вернулись через пару лет с ИБС на поздней стадии.

Матрица путаницы - это измерение производительности для задач классификации машинного обучения, которое (в отличие от точности) учитывает истинно положительный результат (TP), ложный результат (ошибка FP / типа 1), ложно отрицательный результат (FN / тип 2). ошибка) и истинно отрицательные (TN) значения.

Взглянув на приведенную выше матрицу путаницы через призму нашего набора данных, мы хотим, чтобы наша модель выдавала большое количество истинно положительных (TP) и истинно отрицательных (TN) и небольшое количество ложноотрицательных (FN) и ложных положительных результатов (FP ).

Вот наши результаты с точностью каждой модели и матрицей недоразумений [[TP, FP] [FN, TN]]. Хотя все модели дали схожие результаты с точки зрения общей точности и количества ложноотрицательных результатов, я бы рассмотрел Hypertuned Random Forest как модель, представляющую наш набор данных и результат. самый лучший.

Последние мысли

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

Есть способы повысить точность модели. Поскольку Framingham Heart Study все еще продолжается, мы можем передавать моделям машинного обучения больше данных по мере их получения - модели, как известно, делают более точные прогнозы с увеличением объема данных. С технической точки зрения мы могли бы попробовать использовать более совершенные методы и алгоритмы машинного обучения, такие как ансамбль и глубокое обучение. Это то, что мне больше всего нравится в машинном обучении, возможности безграничны :)

Спасибо за чтение!