Python机器学习的练习六:支持向量机

2018年06月01日 由 xiaoshan.xiang 发表 183012 0
Python机器学习的练习系列共有八个部分:

Python机器学习的练习一:简单线性回归

Python机器学习的练习二:多元线性回归

Python机器学习的练习三:逻辑回归

Python机器学习的练习四:多元逻辑回归

Python机器学习的练习五:神经网络

Python机器学习的练习六:支持向量机

Python机器学习的练习七:K-Means聚类和主成分分析

Python机器学习的练习八:异常检测和推荐系统

在Python机器学习的练习六中,我们将使用支持向量机(SVMs)创建一个垃圾邮件分类器。在一些简单的2D数据集上使用SVMs去观察他们如何工作,接下来我们查看一组邮件数据集,并且在处理过的邮件上使用SVMs创建一个分类器,用于判断他们是否是垃圾邮件。

尽管在多类场景中有使用SVMs的方法,但它是一种默认的二进制分类工具。SVMs还可以使用 kernel trick 来处理非线性分类,在尝试找到超平面之前,将数据投射到高维空间中。SVMs是一种强大的算法类,经常用于实际的机器学习应用程序。

首先要做的就是研究简单的二维数据集,看看线性的SVM是如何在不同C值(类似于线性/逻辑回归中的正则化项)的数据集上工作的。

加载数据。
import numpy as np  
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
from scipy.io import loadmat
%matplotlib inline

raw_data = loadmat('data/ex6data1.mat')
raw_data

{'X': array([[ 1.9643  ,  4.5957  ],
[ 2.2753 , 3.8589 ],
[ 2.9781 , 4.5651 ],
...,
[ 0.9044 , 3.0198 ],
[ 0.76615 , 2.5899 ],
[ 0.086405, 4.1045 ]]),
'__globals__': [],
'__header__': 'MATLAB 5.0 MAT-file, Platform: GLNXA64, Created on: Sun Nov 13 14:28:43 2011',
'__version__': '1.0',
'y': array([[1],
[1],
[1],
...,
[0],
[0],
[1]], dtype=uint8)}

我们将它可视化为散点图,类标签由符号表示(' + '为 positive,' o '为negative)。
data = pd.DataFrame(raw_data['X'], columns=['X1', 'X2'])  
data['y'] = raw_data['y']

positive = data[data['y'].isin([1])]
negative = data[data['y'].isin([0])]

fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(positive['X1'], positive['X2'], s=50, marker='x', label='Positive')
ax.scatter(negative['X1'], negative['X2'], s=50, marker='o', label='Negative')
ax.legend()

Python机器学习练习

注意,有一个比其他值更positive的离群值的例子。这些类仍然是线性可分的,但它是一个非常紧密的组合。我们将训练一个线性支持向量机来学习类边界。在这个练习中,我们不需要从头开始执行SVM,所以我将使用scikit- learn的内置工具。
from sklearn import svm  
svc = svm.LinearSVC(C=1, loss='hinge', max_iter=1000)
svc

LinearSVC(C=1, class_weight=None, dual=True, fit_intercept=True,
intercept_scaling=1, loss='hinge', max_iter=1000, multi_class='ovr',
penalty='l2', random_state=None, tol=0.0001, verbose=0)

第一次试验取值C=1,观察它怎样运行
svc.fit(data[['X1', 'X2']], data['y'])  
svc.score(data[['X1', 'X2']], data['y'])

0.98039215686274506

看来它错误的分类了离散值。让我们看看当C值更大时会怎样。
svc2 = svm.LinearSVC(C=100, loss='hinge', max_iter=1000)  
svc2.fit(data[['X1', 'X2']], data['y'])
svc2.score(data[['X1', 'X2']], data['y'])

1.0

这次我们得到了更好的训练集的分类。然而随着C值的增加,我们创建了一个不再适合该数据的决策边界。我们可以通过每个等级预测的置信度来可视化它,这是点与超平面的距离的函数。
data['SVM 1 Confidence'] = svc.decision_function(data[['X1', 'X2']])

fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(data['X1'], data['X2'], s=50, c=data['SVM 1 Confidence'], cmap='seismic')
ax.set_title('SVM (C=1) Decision Confidence')

Python机器学习练习
data['SVM 2 Confidence'] = svc2.decision_function(data[['X1', 'X2']])

fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(data['X1'], data['X2'], s=50, c=data['SVM 2 Confidence'], cmap='seismic')
ax.set_title('SVM (C=100) Decision Confidence')

Python机器学习练习

边界附近点的颜色差别有点微妙。在第一个图像中,边界附近的点是强烈的红色或蓝色,表明它们在超平面的可靠范围内。在第二个图像中不是的,这样其中一些点几乎是白色的,表明它们与超平面直接相邻。

现在我们将从线性SVM转移到能够使用内核进行非线性分类的SVM。首先,我们需要实现一个高斯核函数。为了完全透明,尽管scikit- learn有一个高斯内核,我们仍然从头开始实现高斯核函数 。
def gaussian_kernel(x1, x2, sigma):  
return np.exp(-(np.sum((x1 - x2) ** 2) / (2 * (sigma ** 2))))

x1 = np.array([1.0, 2.0, 1.0])
x2 = np.array([0.0, 4.0, -1.0])
sigma = 2
gaussian_kernel(x1, x2, sigma)

0.32465246735834974

这个结果与预期值相匹配。接下来,我们将检查另一个非线性决策边界的数据集。
raw_data = loadmat('data/ex6data2.mat')

data = pd.DataFrame(raw_data['X'], columns=['X1', 'X2'])
data['y'] = raw_data['y']

positive = data[data['y'].isin([1])]
negative = data[data['y'].isin([0])]

fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(positive['X1'], positive['X2'], s=30, marker='x', label='Positive')
ax.scatter(negative['X1'], negative['X2'], s=30, marker='o', label='Negative')
ax.legend()

Python机器学习练习

对于这个数据集,我们将使用内置的RBF内核构建一个支持向量机分类器,并检查它在训练数据上的准确性。为了使决策边界可视化,这次我们将基于具有负类标签的实例预测概率来遮蔽点。我们从结果中看到大部分都是正确的。
svc = svm.SVC(C=100, gamma=10, probability=True)  
svc.fit(data[['X1', 'X2']], data['y'])
data['Probability'] = svc.predict_proba(data[['X1', 'X2']])[:,0]

fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(data['X1'], data['X2'], s=30, c=data['Probability'], cmap='Reds')

Python机器学习练习

对于第三个数据集,我们得到了训练和验证集,并基于验证集性能为SVM模型寻找最优超参数。尽管我们可以很容易地使用scikit- learn的内置网格搜索来实现这一点,但为了更多的练习,我们将从头开始实现一个简单的网格搜索。
raw_data = loadmat('data/ex6data3.mat')

X = raw_data['X']
Xval = raw_data['Xval']
y = raw_data['y'].ravel()
yval = raw_data['yval'].ravel()

C_values = [0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30, 100]
gamma_values = [0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30, 100]

best_score = 0
best_params = {'C': None, 'gamma': None}

for C in C_values:
for gamma in gamma_values:
svc = svm.SVC(C=C, gamma=gamma)
svc.fit(X, y)
score = svc.score(Xval, yval)

if score > best_score:
best_score = score
best_params['C'] = C
best_params['gamma'] = gamma

best_score, best_params

(0.96499999999999997, {'C': 0.3, 'gamma': 100})

现在我们继续练习的最后一部分。在这个部分,我们的目标是使用SVMs构建一个垃圾邮件过滤器。在练习文本中,有一个任务需要对一些文本进行预处理,以使获得适合SVM的数据格式,这个任务非常简单,而其他预处理步骤(例如HTML删除、词干、规范化等)都已经完成了。我不会重复这些步骤,而是跳过机器学习任务,其中包括从预处理的训练中创建分类器,以及由垃圾邮件和非垃圾邮件转换为单词发生向量的测试数据集。
spam_train = loadmat('data/spamTrain.mat')  
spam_test = loadmat('data/spamTest.mat')

spam_train

{'X': array([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 1, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]], dtype=uint8),
'__globals__': [],
'__header__': 'MATLAB 5.0 MAT-file, Platform: GLNXA64, Created on: Sun Nov 13 14:27:25 2011',
'__version__': '1.0',
'y': array([[1],
[1],
[0],
...,
[1],
[0],
[0]], dtype=uint8)}

X = spam_train['X']  
Xtest = spam_test['Xtest']
y = spam_train['y'].ravel()
ytest = spam_test['ytest'].ravel()

X.shape, y.shape, Xtest.shape, ytest.shape

((4000L, 1899L), (4000L,), (1000L, 1899L), (1000L,))

每个文档都被转换成一个向量,其中1,899个维度对应于词汇表中的1,899个字。二进制的值用来表示文档中的单词是否存在。训练和评估只是考验分类器的一个问题。
svc = svm.SVC()  
svc.fit(X, y)
print('Test accuracy = {0}%'.format(np.round(svc.score(Xtest, ytest) * 100, 2)))

Test accuracy = 95.3%

这个结果与默认参数有关。我们可能会使用一些参数调优来提高它的精度,但是95%的精度仍然不差。

 
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消