機器學習算法——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的解析

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