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