机器学习算法——SVM简单易懂应用实战
SVM(Support Vector Machine)学习资料总结
实战应用
导入工具
import pandas as pd
import numpy as np
from sklearn import svm
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import confusion_matrix
from pylab import mpl
import plotly.graph_objects as go
#设置风格、尺度
sns.set_style('whitegrid')
sns.set_context('paper')
数据展示
# 一个挑西瓜的简单分类例子
data = pd.read_csv('data.csv')
data
# 数据是这样的
编号 色泽 根蒂 敲声 纹理 脐部 触感 密度 含糖率 好瓜?
0 1 青绿 蜷缩 浊响 清晰 凹陷 硬滑 0.697 0.460 是
1 2 乌黑 蜷缩 沉闷 清晰 凹陷 硬滑 0.774 0.376 是
2 3 乌黑 蜷缩 浊响 清晰 凹陷 硬滑 0.634 0.264 是
3 4 青绿 蜷缩 沉闷 清晰 凹陷 硬滑 0.608 0.318 是
4 5 浅白 蜷缩 浊响 清晰 凹陷 硬滑 0.556 0.215 是
5 6 青绿 稍蜷 浊响 清晰 稍凹 软粘 0.403 0.237 是
6 7 乌黑 稍蜷 浊响 稍糊 稍凹 软粘 0.481 0.149 是
7 8 乌黑 稍蜷 浊响 清晰 稍凹 硬滑 0.437 0.211 是
8 9 乌黑 稍蜷 沉闷 稍糊 稍凹 硬滑 0.666 0.091 否
9 10 青绿 硬挺 清脆 清晰 平坦 软粘 0.243 0.267 否
10 11 浅白 硬挺 清脆 模糊 平坦 硬滑 0.245 0.057 否
11 12 浅白 蜷缩 浊响 模糊 平坦 软粘 0.343 0.099 否
12 13 青绿 稍蜷 浊响 稍糊 凹陷 硬滑 0.639 0.161 否
13 14 浅白 稍蜷 沉闷 稍糊 凹陷 硬滑 0.657 0.198 否
14 15 乌黑 稍蜷 浊响 清晰 稍凹 软粘 0.360 0.370 否
15 16 浅白 蜷缩 浊响 模糊 平坦 硬滑 0.593 0.042 否
16 17 青绿 蜷缩 沉闷 稍糊 稍凹 硬滑 0.719 0.103 否
将数据转化为数值型
# 定义一个函数将数据集转化为可处理的数值
def str_column_to_int(dataset, columns):
"""
将类别转化为int型
@dataset: 数据
@column: 需要转化的列
"""
for column in columns:
class_values = [row[column] for row in dataset]
unique = set(class_values)
lookup = dict()
for i, value in enumerate(unique):
lookup[value] = i
for row in dataset:
row[column] = lookup[row[column]]
return dataset
使用Sklearn的API
# 读取西瓜数据集
data = pd.read_csv('data.csv')
# 删除编号行
data.drop(columns=['编号'], inplace=True)
# 将数据转化为数值型
data = str_column_to_int(data.values, [0, 1, 2, 3, 4, 5, 8])
# 创建一个线性svm分类器,随便设置一个惩罚参数和内核系数
svm_classifer = svm.SVC(kernel = 'linear', C = 1, gamma = 1)
# 使用这个分类器来分类实验数据
svm_classifer.fit(data[:, :-1].astype(float), data[:, -1].astype(int))
# 查看分类器得分
svm_classifer.score(data[:, :-1].astype(float), data[:, -1].astype(int))
输出的分类准确率结果显示为
0.7058823529411765
绘制结果的混淆矩阵
# 对结果进行可视化
predict = svm_classifer.predict(data[:, :-1].astype(float))
# 设置字体
mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.sans-serif'] = 'NSimSun,Times New Roman'
font = {'family': 'sans-serif',
'color': 'k',
'weight': 'normal',
'size': 20,}
# 将结果整理成混淆矩阵
con_mat = confusion_matrix(data[:, -1].astype(int), predict, labels=[0, 1])
# 使用seaborn绘制
fig = plt.figure(figsize=(10, 8), dpi = 100)
heatmap = sns.heatmap(con_mat, annot=True, fmt='.1f', annot_kws={'size':15,'weight':'bold'})
heatmap.tick_params(labelsize=15)
plt.xlabel('Prediction',fontsize=20, color='k')
plt.ylabel('True',fontsize=20, color='k')
# 设置label内标签大小
cax = plt.gcf().axes[-1]
cax.tick_params(labelsize=15)
plt.title('Confusion Matrix', fontsize=20)
plt.show()
测试在不同的C下的准确率变化
# 测试在不同的C下的准确率变化
accuracy_rate = []
for c in range(1, 50):
svm_classifer = svm.SVC(kernel = 'linear', C = c, gamma = 1)
svm_classifer.fit(data[:, :-1].astype(float), data[:, -1].astype(int))
accuracy_rate.append(svm_classifer.score(data[:, :-1].astype(float), data[:, -1].astype(int)))
fig = go.Figure()
fig.add_trace(go.Scatter(x=[i for i in range(1, 50)], y = accuracy_rate,
line_shape='spline'))
fig.update_layout(template='none', title="Accuracy change over C",
xaxis_title = 'C',
yaxis_title = 'Accuracy',
font=dict(
family="Times New Roman",
size=15,
color="rgb(82, 82, 82)"
)
)
fig.show()
测试在不同的Gamma下的准确率变化
我们先将核保持为线性试一下
# 测试在不同的gamma下的准确率变化
accuracy_rate = []
for g in range(1, 50):
svm_classifer = svm.SVC(kernel = 'linear', C = 1, gamma = g)
svm_classifer.fit(data[:, :-1].astype(float), data[:, -1].astype(int))
accuracy_rate.append(svm_classifer.score(data[:, :-1].astype(float), data[:, -1].astype(int)))
fig = go.Figure()
fig.add_trace(go.Scatter(x=[i for i in range(1, 50)], y = accuracy_rate,
line_shape='spline'))
fig.update_layout(template='none', title="Accuracy change over Gamma",
xaxis_title = 'Gamma',
yaxis_title = 'Accuracy',
font=dict(
family="Times New Roman",
size=15,
color="rgb(82, 82, 82)"
)
)
fig.show()
准确率随着Gamma的变化并没有改变。在Sklearn提供的svmAPI中还存在其他几种类型的核
核类型 | 核函数 |
---|---|
线性核 | |
多项式核 | |
高斯核 | |
拉普拉斯核 | |
Sigmoid核 |
我们试一下高斯核下的准确率会不会随着gamma的取值不同而发生变化,
# 测试在不同的gamma下的准确率变化
accuracy_rate = []
for g in range(1, 50):
svm_classifer = svm.SVC(kernel = 'rbf', C = 1, gamma = g)
svm_classifer.fit(data[:, :-1].astype(float), data[:, -1].astype(int))
accuracy_rate.append(svm_classifer.score(data[:, :-1].astype(float), data[:, -1].astype(int)))
fig = go.Figure()
fig.add_trace(go.Scatter(x=[i for i in range(1, 50)], y = accuracy_rate,
line_shape='spline'))
fig.update_layout(template='none', title="Accuracy change over Gamma",
xaxis_title = 'Gamma',
yaxis_title = 'Accuracy',
font=dict(
family="Times New Roman",
size=15,
color="rgb(82, 82, 82)"
)
)
fig.show()
在使用高斯核之后,无论Gamma为任何值,拟合的非线性超平面都完美的将样本给区分开(准确率为100%)。这是因为我们所使用的样本太少,分类任务太简单,理论上讲在使用高斯核或拉普拉斯核时,分类效果会随着Gamma而发生变化()。理解C和Gamma可以参考SVM的两个参数 C 和 gamma的解析。