机器学习算法——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.4601	2	乌黑	蜷缩	沉闷	清晰	凹陷	硬滑	0.774	0.3762	3	乌黑	蜷缩	浊响	清晰	凹陷	硬滑	0.634	0.2643	4	青绿	蜷缩	沉闷	清晰	凹陷	硬滑	0.608	0.3184	5	浅白	蜷缩	浊响	清晰	凹陷	硬滑	0.556	0.2155	6	青绿	稍蜷	浊响	清晰	稍凹	软粘	0.403	0.2376	7	乌黑	稍蜷	浊响	稍糊	稍凹	软粘	0.481	0.1497	8	乌黑	稍蜷	浊响	清晰	稍凹	硬滑	0.437	0.2118	9	乌黑	稍蜷	沉闷	稍糊	稍凹	硬滑	0.666	0.0919	10	青绿	硬挺	清脆	清晰	平坦	软粘	0.243	0.26710	11	浅白	硬挺	清脆	模糊	平坦	硬滑	0.245	0.05711	12	浅白	蜷缩	浊响	模糊	平坦	软粘	0.343	0.09912	13	青绿	稍蜷	浊响	稍糊	凹陷	硬滑	0.639	0.16113	14	浅白	稍蜷	沉闷	稍糊	凹陷	硬滑	0.657	0.19814	15	乌黑	稍蜷	浊响	清晰	稍凹	软粘	0.360	0.37015	16	浅白	蜷缩	浊响	模糊	平坦	硬滑	0.593	0.04216	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中还存在其他几种类型的核

核类型 核函数
线性核 kij=k(xi,xj)=xiTxjk_{ij}=k\left( x_{i},x_{j}\right) =x^{T}_{i}x_{j}
多项式核 kij=k(xi,xj)=(xiTxj)dk_{ij}=k\left( x_{i},x_{j}\right) =(x^{T}_{i}x_{j})^{d}
高斯核 kij=k(xi,xj)=exp(xixj22σ2)k_{ij}=k\left( x_{i},x_{j}\right) =\exp (-\frac{\| x_{i}-x_{j}\|^{2} }{2\sigma^{2} } )
拉普拉斯核 kij=k(xi,xj)=exp(xixj2σ2)k_{ij}=k\left( x_{i},x_{j}\right) =\exp (-\frac{\| x_{i}-x_{j}\| }{2\sigma^{2} } )
Sigmoid核 kij=k(xi,xj)=tanh(βxiTxj+θ)k_{ij}=k\left( x_{i},x_{j}\right) =\tanh \left( \beta x^{T}_{i}x_{j}+\theta \right)

我们试一下高斯核下的准确率会不会随着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而发生变化(gamma=12σ2gamma=\frac{1}{2\sigma^{2} })。理解C和Gamma可以参考SVM的两个参数 C 和 gamma的解析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章