机器学习基础-机器学习练习 6 - 支持向量机

目录

前言:

第一部分练习-绘图分析

线性可分的

用非线性决策边界。

第二部分的练习:

小结


前言:

在本练习中,我们将使用支持向量机(SVM)来构建垃圾邮件分类器。 我们将从一些简单的2D数据集开始使用SVM来查看它们的工作原理。 然后,我们将对一组原始电子邮件进行一些预处理工作,并使用SVM在处理的电子邮件上构建分类器,以确定它们是否为垃圾邮件。

第一部分练习-绘图分析

线性可分的

看看线性SVM如何对数据集进行不同的C值(类似于线性/逻辑回归中的正则化项)。

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

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

 

我们将其用散点图表示,其中类标签由符号表示(+表示正类,o表示负类)。 

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()
plt.show()

请注意,还有一个异常的正例在其他样本之外。
这些类仍然是线性分离的,但它非常紧凑。 我们要训练线性支持向量机来学习类边界。

在这个练习中,我们没有从头开始执行SVM的任务,所以我要用scikit-learn。

svc = svm.LinearSVC(C=1,loss='hinge',max_iter=1000)
print(svc)

svc.fit(data[['X1', 'X2']], data['y'])
print(svc.score(data[['X1', 'X2']], data['y']))

svc2 = svm.LinearSVC(C=100, loss='hinge', max_iter=1000)
svc2.fit(data[['X1', 'X2']], data['y'])
print(svc2.score(data[['X1', 'X2']], data['y']))

这次我们得到了训练数据的完美分类,但是通过增加C的值(选择需要适中),我们创建了一个不再适合数据的决策边界。 我们可以通过查看每个类别预测的置信水平来看出这一点,这是该点与超平面距离的函数。

 

 

可以看看靠近边界的点的颜色,区别是有点微妙。 如果您在练习文本中,则会出现绘图,其中决策边界在图上显示为一条线,有助于使差异更清晰。

 

现在我们将从线性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

print(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()
plt.show()


对于该数据集,我们将使用内置的RBF内核构建支持向量机分类器(SVC),并检查其对训练数据的准确性。 为了可视化决策边界,这一次我们将根据实例具有负类标签的预测概率来对点做阴影。 从结果可以看出,它们大部分是正确的
 

svc3 = svm.SVC(C=100,gamma=10,probability=True)
print(svc3)

svc3.fit(data[['X1', 'X2']], data['y'])
print(svc3.score(data[['X1', 'X2']], data['y']))

data['Probability'] = svc3.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')
plt.show()
对于第三个数据集,我们给出了训练和验证集,并且基于验证集性能为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_valuse = [0.01,0.03,0.1,0.3,1,3,10,30,100]

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

# 遍历查找出分数最高的参数C与gamma
for C in C_values:
    for gamma in gamma_valuse:
        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
print(best_score,best_params)

 

第二部分的练习:

在这一部分中,我们的目标是使用SVM来构建垃圾邮件过滤器。 在练习文本中,有一个任务涉及一些文本预处理,以获得适合SVM处理的格式的数据。 然而,这个任务很简单(将字词映射到为练习提供的字典中的ID),而其余的预处理步骤(如HTML删除,词干,标准化等)已经完成。 我将跳过机器学习任务,而不是重现这些预处理步骤,其中包括从预处理过的训练集构建分类器,以及将垃圾邮件和非垃圾邮件转换为单词出现次数的向量的测试数据集。

spam_train = loadmat('data/spamTrain.mat')
spam_test = loadmat('data/spamTest.mat')
print(spam_train)

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

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

每个文档已经转换为一个向量,其中1,899个维对应于词汇表中的1,899个单词。 它们的值为二进制,表示文档中是否存在单词。 在这一点上,训练评估是用一个分类器拟合测试数据的问题。

svc3 = svm.SVC()
svc3.fit(X,y)
print('训练的准确率 = {0}%'.format(np.round(svc.score(X, y) * 100, 2)))
print('测试的准确率 = {0}%'.format(np.round(svc.score(Xtest, ytest) * 100, 2)))
训练的准确率 = 99.32%
测试的准确率 = 98.7%

结果是使用使用默认参数的。 我们可能会使用一些参数调整来获得更高的精度,现在这个结果已经是非常让人满意的了

小结

虽然现在SVM已经不用自己手写但是要学会通过分析进行调参数,比如C与gamma参数的调整,从而得到满意的准确率

参考资料:
黄海广博士的课后笔记-机器学习练习 6 - 支持向量机

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忆_恒心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值