机器学习大作业_机器学习编程作业6-支持向量机(Python版)

本文通过Python的scikit-learn库实现支持向量机(SVM),首先展示线性SVM在2D数据集上的应用,接着实现非线性分类的高斯核SVM,并进行参数调优。最后,SVM被用于垃圾邮件过滤器,经过预处理后的数据在训练和测试集上表现出高精度。
摘要由CSDN通过智能技术生成

本次编程作业的实现环境是Python3、Anaconda3(64-bit)、Jupyter Notebook。是在深度之眼“机器学习训练营”作业基础上完成的,个别代码有修改,供交流学习之用。

45ebcc82fbe87d67cd9c4d86cf94f00d.png

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

第一件事是看一个简单的二维数据集,看看线性SVM如何对数据集进行不同的C值(类似于线性/逻辑回归中的正则化项)。

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as sbfrom scipy.io import loadmat​raw_data = loadmat('data/ex6data1.mat')raw_dataraw_data['X'].shape, type(raw_data['X']), raw_data['y'].shape, type(raw_data['X'])

Out[52]:

((51, 2), numpy.ndarray, (51, 1), numpy.ndarray)

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

data = pd.DataFrame(raw_data['X'], columns=['X1','X2'])data.shape,type(data)data['y'] = raw_data['y']#print(data)​positive = data[data['y'].isin([1])]negative = data[data['y'].isin([0])]#print('positive', positive)#print('negative', negative)​fig, ax = plt.subplots(figsize=(9,6))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()
fd875b69fa141cdc5cb040ed97c8accd.png

请注意,还有一个异常的正例在其他样本之外。 这些类仍然是线性分离的,但它非常紧凑。 我们要训练线性支持向量机来学习类边界。 在这个练习中,我们没有从头开始执行SVM的任务,所以我要用scikit-learn。

from sklearn import svmsvc = svm.LinearSVC(C=1, loss='hinge', max_iter=1000)svc

Out[54]:

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 看下结果如何。

model1 = svc.fit(data[['X1', 'X2']], data['y']) #根据给定的数据拟合svm模型svc.score(data[['X1','X2']], data['y']) #返回给定测试数据和标签的平均精确度

Out[55]:

0.9803921568627451

我们可以通过查看每个类别预测的置信水平来看出这一点,这是该点与超平面距离的函数。

data['SVM 1 Confidence'] = svc.decision_function(data[['X1', 'X2']])​#准备画直线x1_min, x1_max = data['X1'].min() * 1.1, data['X1'].max() * 1.1x2_min, x2_max = data['X2'].min() * 1.1, data['X2'].max() * 1.1x1x, x2x = np.meshgrid(np.linspace(x1_min, x1_max, 500), np.linspace(x2_min, x2_max, 500)) 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')#画边界线z = model1.predict(np.c_[x1x.ravel(), x2x.ravel()])z = z.reshape(x1x.shape)plt.contour(x1x, x2x, z)plt.show()
91253d45fc9211ad9961723f7a27fea5.png

其次,让我们看看如果C的值越大,会发生什么

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

Out[58]: 0.9411764705882353

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')#画边界线z = model2.predict(np.c_[x1x.ravel(), x2x.ravel()])z = z.reshape(x1x.shape)plt.contour(x1x, x2x, z)plt.show()
77d470a4430e0afd72c07ca6c7063405.png

第二件事:现在我们将从线性SVM转移到能够使用内核进行非线性分类的SVM。 我们首先负责实现一个高斯核函数。 虽然scikit-learn具有内置的高斯内核,但为了实现更清楚,我们将从头开始实现。

def gaussian_kernel(x1, x2, sigma):# INPUT:两个维度的值x1,x2,高斯核参数sigma# OUTPUT:高斯核函数计算后的值# TODO:根据参数和输入的数据计算高斯核函数  # STEP:计算高斯核函数,这里的输入时向量化的 # your code here (appro ~ 1 lines) gausk = np.exp(- np.power((x1-x2),2).sum() / (2 * np.power(sigma,2))) return gauskx1 = np.array([1.0, 2.0, 1.0])x2 = np.array([0.0, 4.0, -1.0])sigma = 2​gaussian_kernel(x1, x2, sigma)

Out[9]: 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内核构建支持向量机分类器,并检查其对训练数据的准确性。 为了可视化决策边界,这一次我们将根据实例具有负类标签的预测概率来对点做阴影。 从结果可以看出,它们大部分是正确的。

#svm.SVC构建支持向量机分类器,gamma为rbf/poly/sigmoid核函数的参数,默认auto,选择1/n(特征数)。probability为是否采用概率估计,默认Falsesvc = svm.SVC(C=10, gamma=10, probability=True) model = svc.fit(data[['X1', 'X2']], data['y'])svc.score(data[['X1', 'X2']], data['y'])#print(data[['X1', 'X2']]), print(data['y'])

Out[70]: 0.9466975666280417

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='rainbow')#准备画边界线x1_min, x1_max = data['X1'].min() * 1.1, data['X1'].max() * 1.1x2_min, x2_max = data['X2'].min() * 1.1, data['X2'].max() * 1.1x1x, x2x = np.meshgrid(np.linspace(x1_min, x1_max, 500), np.linspace(x2_min, x2_max, 500))#画边界线z = model.predict(np.c_[x1x.ravel(), x2x.ravel()])z = z.reshape(x1x.shape)plt.contour(x1x, x2x, z)plt.show()
d69346bb2f5766172c3a4fc993031730.png

第三件事情:对于第三个数据集,我们给出了训练和验证集,并且基于验证集性能为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]print(type(C_values))#初始化变量best_score = 0best_params = {'C':None, 'gamma':None}​# TODO:寻找SVM模型最优的超参数# STEP1:遍历每一个超参数for cv in C_values: for gv in gamma_values: # STEP2:调用SVM包,计算当前参数下的得分 # your code here (appro ~ 2 lines)  svc = svm.SVC(C=cv, gamma=gv, probability=True) svc.fit(X, y) #对训练集数据拟合模型 score = svc.score(Xval, yval) #对交叉验证集数据计算其精确度 # STEP3:替换得分最高的超参数组合 # your code here (appro ~ 3 lines)  if best_score < score: best_score = score best_params['C'] = cv best_params['gamma'] = gv​best_score, best_params

Out[29]: (0.965, {'C': 0.3, 'gamma': 100})

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

spam_train = loadmat('data/spamTrain.mat')spam_test = loadmat('data/spamTest.mat')​spam_train, spam_test# TODO: 获取训练和测试数据,这里应注意把标签y矩阵拉直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

Out[33]:

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

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

svc = svm.SVC()svc.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)))

训练精确度为:94.4%

测试精确度为:95.3%

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值