调用sklearn实现支持向量机

线性支持向量机
一、需要使用的模块

import pandas as pd
from scipy.io import loadmat
import matplotlib.pyplot as plt
import numpy as np

这里pandas主要用于将数据处理成DataFrame格式,调用loadmat用于读取mat格式的数据,matplotlib.pyplot用于画图查看数据。

二、处理并查看数据
1、读取并处理数据

data=loadmat('F:\\MachineLearning\data\ex6data1.mat')
print(data['X'])

这里先读取数据data,并查看data训练集数据data['X'],得到:

[[1.9643   4.5957  ]
 [2.2753   3.8589  ]
 [2.9781   4.5651  ]
 [2.932    3.5519  ]
 [3.5772   2.856   ]
 [4.015    3.1937  ]
 [3.3814   3.4291  ]
 [3.9113   4.1761  ]
 [2.7822   4.0431  ]
 [2.5518   4.6162  ]
 [3.3698   3.9101  ]
 [3.1048   3.0709  ]
 [1.9182   4.0534  ]
 [2.2638   4.3706  ]
 [2.6555   3.5008  ]
 [3.1855   4.2888  ]
 [3.6579   3.8692  ]
 [3.9113   3.4291  ]
 [3.6002   3.1221  ]
 [3.0357   3.3165  ]
 [1.5841   3.3575  ]
 [2.0103   3.2039  ]
 [1.9527   2.7843  ]
 [2.2753   2.7127  ]
 [2.3099   2.9584  ]
 [2.8283   2.6309  ]
 [3.0473   2.2931  ]
 [2.4827   2.0373  ]
 [2.5057   2.3853  ]
 [1.8721   2.0577  ]
 [2.0103   2.3546  ]
 [1.2269   2.3239  ]
 [1.8951   2.9174  ]
 [1.561    3.0709  ]
 [1.5495   2.6923  ]
 [1.6878   2.4057  ]
 [1.4919   2.0271  ]
 [0.962    2.682   ]
 [1.1693   2.9276  ]
 [0.8122   2.9992  ]
 [0.9735   3.3881  ]
 [1.25     3.1937  ]
 [1.3191   3.5109  ]
 [2.2292   2.201   ]
 [2.4482   2.6411  ]
 [2.7938   1.9656  ]
 [2.091    1.6177  ]
 [2.5403   2.8867  ]
 [0.9044   3.0198  ]
 [0.76615  2.5899  ]
 [0.086405 4.1045  ]]

即我们的数据具有两个特征。接着,将data['x']转化为pd.DataFrame格式的数据,并将两个特征所在列命名为x1x2,并加上一列y,用于存储训练集样本的标记:

pd1 = pd.DataFrame(data['X'],columns=['x1','x2'])
pd1['y'] = data['y']
print(pd1)

可以看到我们处理后的数据打印为:

          x1      x2  y
0   1.964300  4.5957  1
1   2.275300  3.8589  1
2   2.978100  4.5651  1
3   2.932000  3.5519  1
4   3.577200  2.8560  1
5   4.015000  3.1937  1
6   3.381400  3.4291  1
7   3.911300  4.1761  1
8   2.782200  4.0431  1
9   2.551800  4.6162  1
10  3.369800  3.9101  1
11  3.104800  3.0709  1
12  1.918200  4.0534  1
13  2.263800  4.3706  1
14  2.655500  3.5008  1
15  3.185500  4.2888  1
16  3.657900  3.8692  1
17  3.911300  3.4291  1
18  3.600200  3.1221  1
19  3.035700  3.3165  1
20  1.584100  3.3575  0
21  2.010300  3.2039  0
22  1.952700  2.7843  0
23  2.275300  2.7127  0
24  2.309900  2.9584  0
25  2.828300  2.6309  0
26  3.047300  2.2931  0
27  2.482700  2.0373  0
28  2.505700  2.3853  0
29  1.872100  2.0577  0
30  2.010300  2.3546  0
31  1.226900  2.3239  0
32  1.895100  2.9174  0
33  1.561000  3.0709  0
34  1.549500  2.6923  0
35  1.687800  2.4057  0
36  1.491900  2.0271  0
37  0.962000  2.6820  0
38  1.169300  2.9276  0
39  0.812200  2.9992  0
40  0.973500  3.3881  0
41  1.250000  3.1937  0
42  1.319100  3.5109  0
43  2.229200  2.2010  0
44  2.448200  2.6411  0
45  2.793800  1.9656  0
46  2.091000  1.6177  0
47  2.540300  2.8867  0
48  0.904400  3.0198  0
49  0.766150  2.5899  0
50  0.086405  4.1045  1

接着我们将标记为1的正例和标记为0的反例分开,分别存储在positivenegative中,并查看:

positive = pd1[pd1['y']==1]
print('\n')
negative = pd1[pd1['y']==0]
print(positive)

得到:

          x1      x2  y
0   1.964300  4.5957  1
1   2.275300  3.8589  1
2   2.978100  4.5651  1
3   2.932000  3.5519  1
4   3.577200  2.8560  1
5   4.015000  3.1937  1
6   3.381400  3.4291  1
7   3.911300  4.1761  1
8   2.782200  4.0431  1
9   2.551800  4.6162  1
10  3.369800  3.9101  1
11  3.104800  3.0709  1
12  1.918200  4.0534  1
13  2.263800  4.3706  1
14  2.655500  3.5008  1
15  3.185500  4.2888  1
16  3.657900  3.8692  1
17  3.911300  3.4291  1
18  3.600200  3.1221  1
19  3.035700  3.3165  1
50  0.086405  4.1045  1

positive中存储的全为正例。下面画图查看正例和反例的分布,决定使用线性支持向量机还是非线性支持向量机:

plt.scatter(positive['x1'],positive['x2'],marker='o',label='positive',color='blue')
plt.scatter(negative['x1'],negative['x2'],marker='x',label='negative',color='red')
plt.legend()
plt.show()

查看图:

调用sklearn实现支持向量机_第1张图片
显然我们只需使用线性支持向量机即可解决这一问题。

3、调用sklearn中svm解决问题

from sklearn import svm
svc = svm.LinearSVC(C=1,loss='hinge',max_iter=1000)
#给定训练数据拟合SVM模型
svc.fit(pd1[['x1','x2']],pd1['y'])
#返回训练数据和标签的平均精度
score = svc.score(pd1[['x1','x2']],pd1['y'])
print(score)
#改变系数C
svc2 = svm.LinearSVC(C=100,loss='hinge',max_iter=1000)
fit2 = svc2.fit(pd1[['x1','x2']],pd1['y'])
score2 = svc2.score(pd1[['x1','x2']],pd1['y'])
print(score2)

首先在第一行调用了sklearn中的svm模块,第二行设置线性支持向量机svm.LinearSVC的参数:用于调和结构风险和经验风险的惩戒参数C我们设定为1,损失函数设定为hinge形,最大迭代次数设定为1000。第四行用我们现有的数据取拟合一个给定参数的支持向量机。第六行我们查看拟合模型在训练集上的平均精度。后面类似,只是改变了惩戒参数C,查看情况,得到结果:

0.9803921568627451
1.0

即C=1时为精度为0.9803921568627451,C=100时的精度为1.0,可以知道C=100时很可能发生了过拟合。
接下来,用svc.decision_function计算样本到决策边界的距离,并将每一个样本在C=1和C=100时的距离分别存储在pd1'SVM Confidence'SVM2 Confidence,并将每个样本点打印出来,用点的颜色深浅表示样本到决策边界的距离:

#decision_function为样本到决策边界的距离
fig,ax=plt.subplots(figsize=(12,8))
pd1['SVM Confidence'] = svc.decision_function(pd1[['x1','x2']])
ax.scatter(pd1['x1'],pd1['x2'],marker='o',c=pd1['SVM Confidence'],cmap='seismic')
ax.set_title('SVM Confidence(C=1)')
plt.show()

fig,ax = plt.subplots(figsize=(12,8))
pd1['SVM2 Confidence'] = svc2.decision_function(pd1[['x1','x2']])
ax.scatter(pd1['x1'],pd1['x2'],marker='o',c=pd1['SVM2 Confidence'],cmap='seismic')
ax.set_title('SVM Confidence(C=100)')
plt.show()

得到:
调用sklearn实现支持向量机_第2张图片
调用sklearn实现支持向量机_第3张图片
从图上我们可以进一步感受到C=100时的过拟合,在左上角一点我们可以清楚感受到他一定为反例,但是C=100时将这个样本划分为和决策边界距离很近,以至于颜色太浅我们看不到这一点。

非线性支持向量机
一、处理并查看数据
这与前面的线性支持向量机情况一样:

data2 = loadmat('F:\\MachineLearning\data\ex6data2.mat')
pd2 = pd.DataFrame(data2['X'],columns=['x1','x2'])
pd2['y'] = data2['y']

positive1 = pd2[pd2['y']==1]
negative1 = pd2[pd2['y']==0]

fig,ax = plt.subplots(figsize=(12,8))
ax.scatter(positive1['x1'],positive1['x2'],c='blue',marker='o',label='positive')
ax.scatter(negative1['x1'],negative1['x2'],c='red',marker='x',label='negative')
plt.show()

得到数据分布图:
调用sklearn实现支持向量机_第4张图片
很显然,不能在使用线性支持向量机去解决这一问题,必须使用带有核函数的支持向量机,即非线性支持向量机。
下面用非线性支持向量机svm.SVC去拟合,并查看拟合模型在训练集上的精度:

svc_nonlinear = svm.SVC(C=100,gamma=10,probability=True)
svc_nonlinear.fit(pd2[['x1','x2']],pd2['y'])
score_nonlinear=svc_nonlinear.score(pd2[['x1','x2']],pd2['y'])
print(score_nonlinear)

第一行,我们默认使用高斯函数作为核函数,所以我们需要定义 σ 2 σ^2 σ2参数,代码中用gamma表示,这里我们定为10,这个 σ 2 σ^2 σ2参数会影响我们的拟合情况,具体地说:太大的 σ 2 σ^2 σ2会使高斯函数过于平坦,而导致高偏差、低方差:反之,还会导致高方差,低偏差。所以惩戒参数数C和参数 σ 2 σ^2 σ2的选取都极为重要。probability表示是否用概率估计,此参数定义一定要在调用fit之后,设置为False之后会使训练过程的计算过程变慢。
接下来调用.predict_proba(),这个方法返回一个矩阵,矩阵第i行第j列表示第i个样本属于第j个类的概率:

probability_nonlinear = svc_nonlinear.predict_proba(pd2[['x1','x2']])
print(probability_nonlinear)

得到:

[[3.0000009e-14 1.0000000e+00]
 [3.0000009e-14 1.0000000e+00]
 [3.0000009e-14 1.0000000e+00]
 ...
 [3.0000009e-14 1.0000000e+00]
 [3.0000009e-14 1.0000000e+00]
 [3.0000009e-14 1.0000000e+00]]

然后取这个矩阵的第一列,即每个样本属于第0类(反例)的概率,用这一列的大小去定义颜色的深浅,颜色越深,越有可能属于第0类:

probability_nonlinear = svc_nonlinear.predict_proba(pd2[['x1','x2']])
print(probability_nonlinear)

pd2['probability'] = probability_nonlinear[:,0]
fig,ax = plt.subplots(figsize=(12,8))
ax.scatter(pd2['x1'],pd2['x2'],c=pd2['probability'],cmap='Reds',marker='o')
ax.set_title('SVM Probability')
plt.show()

得到图:
调用sklearn实现支持向量机_第5张图片
和原始的数据图相比基本一致。

参数选择问题
这里的分类问题涉及到参数 σ 2 σ^2 σ2 C C C的选取问题,若参数选取不当可能导致过拟合或欠拟合,所以参数选择影响到我们训练的好坏。这里我们主要是不同的参数对应着不同的模型,利用此模型取训练,然后选取在交叉验证集上表现最好的模型。
一、处理并查看数据

data3 = loadmat('F:\\MachineLearning\data\ex6data3.mat')
print(data3['X'])

pd3 = pd.DataFrame(data3['X'],columns=['x1','x2'])
pd3['y'] = data3['y']
pd4 = pd.DataFrame(data3['Xval'],columns=['x1','x2'])
pd4['y'] = data3['yval']

fig,ax = plt.subplots(figsize=(12,8))
positive3=pd3[pd3['y']==1]
negative3=pd3[pd3['y']==0]
ax.scatter(positive3['x1'],positive3['x2'],color='blue',marker='o',label='Positive')
ax.scatter(negative3['x1'],negative3['x2'],color='red',marker='x',label='Negative')
ax.set_title('Training_Set')
ax.legend()
plt.show()

fig,ax = plt.subplots(figsize=(12,8))
positive4=pd4[pd4['y']==1]
negative4=pd4[pd4['y']==0]
ax.scatter(positive4['x1'],positive4['x2'],color='blue',marker='o',label='Positive')
ax.scatter(negative4['x1'],negative4['x2'],color='red',marker='x',label='Negative')
ax.set_title('Val')
ax.legend()
plt.show()

这里我们将训练集数据和交叉验证集数据分别存在pd3pd4中,分别查看,得到:
调用sklearn实现支持向量机_第6张图片
调用sklearn实现支持向量机_第7张图片
我们选择非线性支持向量机去将数据分类。

二、选择合适参数
这里我们将所有 C C C存在C_list列表中,所有 σ 2 σ^2 σ2存于gamma_list列表中,遍历列表中所有元素,选取在交叉验证集上表现最好的参数,并打印此参数及此参数在交叉验证集上的精度:

best_score=0
gamma_list=[0.01,0.03,0.1,0.3,1,3,10,30,100]
C_list=[0.01,0.03,0.1,0.3,1,3,10,30,100]
for C_value in C_list:
    for gamma_value in gamma_list:
        svc = svm.SVC(C=C_value,gamma=gamma_value,probability=True)
        svc.fit(pd3[['x1','x2']],pd3['y'])
        score=svc.score(pd4[['x1','x2']],pd4['y'])
        if score>best_score:
            best_score=score
            best_C=C_value
            best_gamma=gamma_value
print(best_gamma,best_C,best_score)

得到:

100 0.3 0.965

即惩罚参数C选取为0.3, σ 2 σ^2 σ2选为100,在交叉验证集上的精度为0。965。

利用支持向量机对邮件分类

下面我们用支持向量机对邮件进行分类,分为垃圾邮件和有用的邮件。
首先读取数据:

spam_data = loadmat('F:\\MachineLearning\data\spamTrain.mat')
X = spam_data['X']
y = spam_data['y']
spam_test = loadmat('F:\\MachineLearning\data\spamTest.mat')
Xtest = spam_test['Xtest']
ytest = spam_test['ytest']

查看训练集维度:

(4000, 1899)

即我们有4000条数据,每条数据有1899个特征。

我们如何将每个邮件处理为数字化的样本?
1、所有文字母转化为小写
2、所有HTML标记都从电子邮件中删除。
3、所有URL都替换为文本’httpaddr’。
4、所有电子邮件地址都替换为文本’emailaddr’。
5、所有数字都用文本’number’替换。
6、所有美元符号($)都替换为文本’dollars’。
7、所有单词处理为其原始形式。(如:discounting、discounted转化为discount)
8、删除非文本和标点符号。

然后创建一个word list,上面一共1899个单词,每个单词对应这一个数字,如:
调用sklearn实现支持向量机_第8张图片
将样本处理为维度为1899的数组形式,数组对应位置代表着对应单词的频数。这样我们就可以将数字化。

下面我们拟合训练集数据,并输出在训练集和验证集上的精度:

svc_spam = svm.SVC()
svc_spam.fit(X,y)
print('The  traininig accuracy is'+str(svc_spam.score(X,y))+'.')
print('The test accusracy is'+str(svc_spam.score(Xtest,ytest))+'.' )

得到:

The  traininig accuracy is 0.944.
The test accusracy is 0.953.

即训练集上精度为0.944,测试集上的精度为0.953。

你可能感兴趣的:(调用sklearn实现支持向量机)