如何使用Sci-kit Learn的四个SVM核来建立机器学习模型

476 阅读9分钟

使用支持向量机对糖尿病进行诊断

在本指南中,我们将学习如何使用机器学习来诊断病人是否患有糖尿病。我们可以通过使用他们的医疗记录来做到这一点。我们将使用支持向量机算法(来自Sci-kit Learn)来建立我们的模型。

前提条件

  • 一台装有Jupyter笔记本的电脑。
  • 基本的Python知识。
  • [支持向量机]的基本知识
  • 来自[Kaggle]的糖尿病数据集

概要

  • 使用Pandas的探索性数据分析 - 剖析
  • 特征提取
  • 将数据集分成训练集和测试集
  • 创建SVM模型
  • 诊断一个新病人
  • 评估模型性能

用pandas-profiling进行探索性数据分析

pandas-profiling库可以帮助我们以最小的努力完成快速的探索性数据分析。

要安装pandas-profiling,请运行下面的代码。

pip install pandas-profiling

如果你使用的是Anaconda,那么你可以在Anaconda Prompt中运行以下代码。

conda install -c conda-forge pandas-profiling

现在我们可以导入pandas-profiling并为我们的数据集生成一份报告。在加载我们的数据集之前,让我们导入我们将要使用的库。

# importing libraries
import numpy as np
import pandas as pd
import pandas_profiling
from sklearn import svm
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report

我们使用pandas的read_csv函数导入我们的数据集。我们把数据集的文件名作为一个参数传递。

# Getting Data
dataset = pd.read_csv("diabetes.csv")
# generate report with panda-profiling
profile = dataset.profile_report(title='Diabetes Profiling Report')
profile

Pandas-profiling会给我们提供数据集的统计数据。

Overview of the Dataset

数据集的概述

从上面的报告来看,我们有九个变量和768行。数据集中没有缺失的数据。没有重复的数据。

Pandas-profiling还查看了这九个变量中的每一个。对于每个变量,它都会给我们描述性的统计数字。它生成了一个直方图,显示每个变量的数据分布。

Histogram - Pregnancy

直方图 - 怀孕

Histogram - Glucose & Blood Pressure

直方图--葡萄糖和血压

Histogram - Skin Thickness & Insulin

直方图--皮肤厚度和胰岛素

Histogram - BMI & Pedigree

直方图--BMI与血统

Histogram - Age & Outcome

直方图--年龄与结果

我们可以看到每个变量的平均值、最小值和最大值。我们可以观察每个变量之间的相关图。

Features Interaction

特征的相互作用

我们可以看到Pearson, Spearman, Kendall, 和Phik相关矩阵热图。

Feature Correlations

特征的相关关系

我们可以直观地看到缺失值,并确切地知道我们在数据集中哪里有缺失值。没有一个变量包含任何缺失值,所以我们可以继续建立我们的模型。

Visualization of Missing Values

缺失值的可视化

最后,我们可以查看数据集的前十行和最后十行。

First Rows of the dataset

数据集的第一行

Last Rows of the dataset

数据集的最后几行

特征提取

我们把特征和目标变量分开。我们有八个特征。

# Extract Features
X = dataset.iloc[:, :8]
X.head()

Dataset Features

数据集特征

我们的目标变量是结果栏。值1代表糖尿病患者,而0代表无糖尿病患者。

# Extract Class Labels
y = dataset["Outcome"]
y.head()

Class Labels of the Dataset

类标签

将数据集分成训练集和测试集

我们把我们的数据集分成训练集和测试集。我们用75%的数据集来训练模型,训练后用剩下的25%来测试模型。

# Split Dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.75, random_state=0)
    
print(X_train.shape)

Shape of X_train

print(y_train.shape)

Shape of y_train

print(X_test.shape)

Shape of X_test

print(y_test.shape)

Shape of y_test

我们可以看到我们将用于训练和测试的数据量。

X_train.head()

Training Set

训练集

我们需要将训练集中的特征归一化。归一化将我们数据集中的每一列调整为平均值为0,标准差为1,这将使训练过程更快。

# Normalize Features
scaler = StandardScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)

让我们来看看规范化后的训练集的前五行。

# View first 5 rows
X_train[:5, :]

Normalized Training Set

正常化的训练集

创建SVM模型

Sci-kit Learn库有四个SVM内核。我们有线性、Poly、Rbf和sigmoid核。我们不知道哪个核会给我们一个更好的决策边界。

因此,我们在这些核中进行迭代,看看哪一个能给我们的数据集提供最好的决策边界。决策边界是分隔正类和负类的超平面或曲线。它可以是线性或非线性的。

Decision Boundary

当类别不可线性分离时,多项式和RBF核是合适的。

我们将每个核的SVM模型适合于我们的训练集。我们对训练集进行预测,看看哪个核能给我们带来最高的准确率。

我们把这称为超参数优化(Hyper-Parameter Optimization)。

# SVM Kernels
for k in ('linear', 'poly', 'rbf', 'sigmoid'):
    model = svm.SVC(kernel=k)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_train)
    print(k)
    print(accuracy_score(y_train, y_pred))

Accuracy of SVM Kernels

SVM核的准确度

RBF(径向基函数)核给了我们最高的准确率分数。所以对于这个数据集,它提供了最好的决策边界。RBF核找到了一个能正确分离82.4%的病人的决策边界。现在让我们用RBF核创建我们的模型。

# Using the best model
model = svm.SVC(kernel='rbf')
model.fit(X_train, y_train)

诊断一个新的病人

我们用我们的模型对一个新病人进行预测。

# Making a Single Prediction
# 'pregnancies', 'glucose', 'bpressure', 'skinThickness'
# 'insulin', 'bml', 'pedigree', 'age'
    
patient = np.array([[ 1., 150., 70., 45., 0., 40., 1.5, 25]])
    
# Normalize the data with the values used in the training set
patient = scaler.transform(patient)
    
model.predict(patient)

Result of Single Prediction

让我们创建一个包含新病人记录的numpy数组。在将数据传递给模型进行预测之前,我们对数据进行标准化处理。这次我们使用转化方法,而不是fit_transform方法。

这将使用与归一化训练集相同的平均值和标准差。结果是1,所以该病人患有糖尿病。让我们看看如果我们把葡萄糖水平从150改为50,我们的模型会预测什么。

patient = np.array([[ 1., 50., 70., 45., 0., 40., 1.5, 25]])
    
# Normalize the data
patient = scaler.transform(patient)
    
model.predict(patient)

Result of Single Prediction

我们得到0,这意味着这个病人没有糖尿病。让我们来看看我们的测试集。

# Viewing Test Set
X_test

Test Set

现在让我们试着诊断测试集中的第三个病人(ID为113)。记住,第三个病人的指数是2,因为我们从0开始计算。

# Checking the third patient in the test set with index 2
X_test.iloc[2]

Details of the Third Patient

# Convert dataframe to a numpy array
t_patient = np.array([ X_test.iloc[2]])

# Predicting on third patient in Test Set
t_patient = scaler.transform(t_patient)
    
print("Model's Prediction:", model.predict(t_patient))
print("Actual Prediction:", y_test.iloc[2])

Prediction of the Third Patient

我们可以看到,我们的模型预测值是0,实际预测值也是0。这意味着我们的模型对这个病人的预测是正确的。第三个病人没有糖尿病。

评估模型性能

让我们看看整个测试集的准确性。

# Accuracy on Testing Set
X_test = scaler.transform(X_test)
y_pred = model.predict(X_test)
print("Accuracy Score:", accuracy_score(y_test, y_pred))

Accuracy Score of the Test Set

在进行预测之前,我们对测试集进行标准化处理。我们的准确率为77.60,低于我们在训练集上的结果。这是因为测试集包含我们的模型以前没有见过的数据。

如果我们的模型预测到没有人患有糖尿病呢?在这种情况下,我们的准确率会是多少?让我们来看看,如果我们的模型预测所有的病人都是0(没有糖尿病),准确率会是多少。

为了做到这一点,我们创建一个零数组,其形状与我们的测试集类相同。

# Comparison to All-Zero Prediction
y_zero = np.zeros(y_test.shape)
print(accuracy_score(y_test, y_zero))

Accuracy Score of All-Zero Prediction

当我们将测试集与全零数组进行比较时,我们得到的准确率为67.7%。我们的模型准确率是67.7%,即使它预测测试集中没有人患有糖尿病。

这意味着我们的数据集是不平衡的。在我们的数据集中有更多没有糖尿病的样本。所以准确率分数不能帮助我们评估我们的模型。我们可以用精确度和召回率来衡量我们模型的性能。

精确率告诉我们,在我们的模型预测的所有病人中,有多少人患有糖尿病。召回率告诉我们,在所有的糖尿病患者中,我们的模型正确检测到的患有糖尿病的比例。

一个高精确度的模型可以帮助我们避免治疗没有糖尿病的人。但我们可能最终没有治疗一些糖尿病患者。一个高召回率的模型允许我们治疗所有糖尿病患者。但我们最终可能会治疗那些没有糖尿病的病人。

我们需要的是在精确度和召回率之间进行权衡。这就是f1-score的作用。f1-score在精确度和召回率之间找到一个良好的平衡。

精确度是指。真阳性/(真阳性+假阳性)

召回率是指。真阳性/(真阳性+假阴性)

  • 真阳性是指患有糖尿病的病人,而我们的模型预测其患有糖尿病。
  • 假阳性是指没有糖尿病的病人,但我们的模型预测为有糖尿病。
  • 真阴性是指没有糖尿病的病人,而我们的模型预测为没有糖尿病。
  • 假阴性是指有糖尿病的病人,但我们的模型预测为没有糖尿病。

让我们计算一下精度、召回率和f1得分。我们还可以生成一份分类报告。

# Compute precision, recall and f1 score
from sklearn.metrics import recall_score, precision_score, f1_score
    
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
    
print("Precision is", precision)
print("Recall is", recall)
print("F1 score is", f1)

Precision Recall & F1 Score

精度、召回率和F1分数

我们也可以生成一个分类报告。

# Generate classification report
print(classification_report(y_test, y_pred))

Classification Report

分类报告

我们的精度、召回率和f1分数分别约为0.71、0.52和0.60。这个模型不是太好。对于一个医疗问题,我们最终可能会误诊为患有糖尿病的病人。这就是为什么我们更关注召回分数。我们可以通过收集更多的数据来改善我们的结果。

总结

在本指南中,我们学习了如何使用Sci-kit Learn的四个SVM核来建立机器学习模型。不同的内核在不同的数据集上效果更好。你可以使用pandas-profiling来做快速的探索性数据分析。

准确率得分对于评估一个有倾斜类的数据集来说不是一个好的指标。这是一个具有不平衡类的数据集,其中一个类的样本比另一个多。

我们可以使用精度、召回率和f1-score来检查我们的模型。我们可以通过收集更多的数据来提高我们的模型性能。