其他问题
升级sklearn到最新版本
conda install scikit-learn=0.21
升级matplotlib到最新版本
conda install matplotlib=3.1.0
支持向量机(SVM)
支持向量机实现简单二分类任务并绘图
详细
- 二分类任务
- 样本数:40,特征数,2
- 无核函数
- 正负样本平衡
目标
- 对样本数据进行分类并绘图
详细代码
# 支持向量机的例子
from sklearn.model_selection import train_test_split
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.datasets import make_blobs
# 使用make_blobs创建了40个点
# 默认是两个特征
# n_samples:样本数量,
# centers 创建的中心数(几类),
# random_state 指定一个数,保证每次生成的数据相同
# cluster_std 两类样本的方差,调整方差使点更加松散
X, y = make_blobs(n_samples=40, centers=2, random_state=6, cluster_std=[1.0, 2.0])
# C是惩罚系数,即对误差的宽容度。c越高,说明越不能容忍出现误差,容易过拟合
# C越小,容易欠拟合。C过大或过小,泛化能力变差
# kernel 这里选择的是线性核,即是最简单的线性svm
clf = svm.SVC(kernel='linear', C=1000)
#分割成训练集和测试集, test_size是比例 ,指定random_state会使每次分割的数据集相同
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=14)
#进行模型训练
clf.fit(X_train, y_train)
#模型预测
clf.predict(X_test)
#打印预测的分数
_score = clf.score(X_test, y_test)
print(_score) #0.8333333333333334
# 画点
# 测试集: 横坐标, 纵坐标, c=y_train y_train的值不同,点的颜色也不同, cmap指定一种颜色分布规律
plt.scatter(X_train[:, 0], X_train[:, 1], c=y_train, s=30, cmap=plt.cm.Paired)
# 训练集: 横坐标, 纵坐标, marker 代表训练集的点使用x来表示,默认是o
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test, s=30, cmap=plt.cm.Paired, marker="x")
#接下来是画svm的超平面
ax = plt.gca()
xlim = ax.get_xlim() # 获得x轴最大最小值
# print(xlim) (3.976374301845057, 10.80436834848946)
ylim = ax.get_ylim() # 获得y轴最大最小值
# print(ylim) (-11.076622589861897, -1.0862982622797808)
#将x轴,y轴分别分成30份
xx = np.linspace(xlim[0], xlim[1], 30)
yy = np.linspace(ylim[0], ylim[1], 30)
# 接受两个一维数组生成两个二维矩阵,
# XX (30, 30)
# YY (30, 30)
YY, XX = np.meshgrid(yy, xx)
# 拉平XX矩阵, 拉平YY矩阵, 并将矩阵竖着拼接
# print(XX.ravel())
# print("---------")
# print(YY.ravel())
# print("---------")
# print(np.vstack([XX.ravel(), YY.ravel()]))
# print("---------")
# print(np.vstack([XX.ravel(), YY.ravel()]).T) # 进行行列转换
# print("---------")
xy = np.vstack([XX.ravel(), YY.ravel()]).T # shape(900,2) xy即每对 (x,y)点坐标
# decision_function 计算出每队(x,y)点到超平面的函数间隔,并使用reshape还原成之前点的矩阵形式
# 求出了每个点的z值,z即是超平面的函数间隔
Z = clf.decision_function(xy).reshape(XX.shape)
# 画出决策边界
ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5,
linestyles=['--', '-', '--']) # alpha表示透明度 cmap渐变标准
# 支持向量上划圈
# clf.support_vectors_ 获得支持向量
# s是圆圈的大小 linewidth是线的粗细 facecolors是颜色填充 edgecolors 边界的颜色
ax.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=500,
linewidth=1, facecolors='none', edgecolors='k')
plt.show() #画图
结果图
结果分析
- 圈起来的是支持向量
- 不同颜色代表不同样本
- 虚线代表决策边界
- x代表测试集,o代表训练集
- 分割正确的样本会出现在正确的位置,否则会落在边界或者是错误的位置
附录
linspace(a,b,10) 生成从a到b 10个数的等差数列
meshgrid 将两个向量合并成一个矩阵
ravel 矩阵拉成一行
vstack 矩阵列合并
.T 矩阵转置
具有单变量特征选择的SVM
详细
目标
- 测试不同特征选择率下的数据拟合效果并绘图
详细代码
# 具有单变量特征选择的SVM
# https://scikit-learn.org/stable/auto_examples/svm/plot_svm_anova.html#sphx-glr-auto-examples-svm-plot-svm-anova-py
# SVM-Anova: SVM with univariate feature selection
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectPercentile, chi2
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
# #############################################################################
# return_X_y控制输出数据的结构,若选为True,则将因变量和自变量独立导出;
# 即X 对应data y对应target
X, y = load_iris(return_X_y=True) # 导入数据
# print(X.shape) # (150, 4)
# 设置随机数种子,保证每次随机到的数据相同
np.random.seed(0)
x_shape_ = 2 * np.random.random((X.shape[0], 36)) # 生成一个随机数矩阵
# print(x_shape_.shape) # (150, 36)
X = np.hstack((X, x_shape_))
# print(X.shape) # (150, 40)
# #############################################################################
# Pipeline, 数据按照给定的参数顺序进行处理,按顺序执行列表中的 ----transform---方法
# 特征选择: 就是看自变量对因变量的相关性
# SelectPercentile 选择排名排在前n%的变量 默认percentile=10 即选择前10%最相关的特征,选择方法:卡方检验(chi2)
# chi2 卡方检验
# preprocessing.scale 是归一化方法,数据会缩到(0,1)范围
# StandardScaler 另一种特征缩放方法,但不会缩到(0,1)范围 但对异常点不敏感
clf = Pipeline([('anova', SelectPercentile(chi2)),
('scaler', StandardScaler()),
('svc', SVC(gamma="auto"))])
# #############################################################################
# 创建用于绘图的数据
score_means = list() # mean平均数
score_stds = list() # std标准差
percentiles = (1, 3, 6, 10, 15, 20, 30, 40, 60, 80, 100)
# anova 方差分析
# 用于确定特征选择的百分比的不同水平对结果的影响程度如何
for percentile in percentiles:
# anova__percentile 改变前面别名anova的percentile参数的 也就是设置 SelectPercentile.percentile属性,即:改变特征选择的百分比
clf.set_params(anova__percentile=percentile)
# 最简单的交叉验证方法,cv选择折数,默认是3折交叉验证 这里是 5折交叉验证
this_scores = cross_val_score(clf, X, y, cv=5)
score_means.append(this_scores.mean())
score_stds.append(this_scores.std())
# errorbar 绘制误差条,即图片上的一堆竖线
# 横坐标百分比, 纵坐标是平均值 , 误差是 np.array(score_stds)
plt.errorbar(percentiles, score_means, yerr=np.array(score_stds))
# plt.errorbar(percentiles, score_means, np.array(score_stds)) 以上两个代码等效
# 所选特征的百分比的改变所引起的SVM方差分析的性能改变程度
plt.title(
'Performance of the SVM-Anova varying the percentile of features selected')
plt.xticks(np.linspace(0, 100, 11, endpoint=True)) # 设置横坐标刻度
plt.xlabel('Percentile')
plt.ylabel('Accuracy Score')
plt.axis('tight')
plt.show()
结果图
结果分析
- 在此例中,特征选择率是10%时,准确率最高
- 竖线是误差条
附录
- pipeline
- Pipeline构造器接受(name, transform) tuple的列表作为参数。按顺序执行列表中的 ----transform----,完成数据预处理
- 除了最后一个tansform,其余的transform必须实现fit_transform函数
- 上一个transform类中fit_transform函数的返回值作为下一个transform类fit_transform函数的参数,所以在自己实现自定义的transform类的时候必须要实现fit_transform函数
- fit_transform 返回值为 numpy array
- SelectPercentile/SelectKBest 特征选择,选择排名靠前特征作为新特征
- SelectPercentile 选择排名排在前n%的变量 默认percentile=10 即选择前10%最相关的特征,
- 特征选择方法:卡方检验(chi2)
- SelectKBest选择排名排在前n个的变量
- StandardScaler 特征缩放
- 一种特征缩放方法,但不会缩到(0,1),对异常点不敏感
- StandardScaler 使用该类的好处在于可以保存训练集中的参数(均值、方差)直接使用其对象转换测试集数据。
- preprocessing.scale 是另一种特征缩放方法,又称归一化方法,数据会缩到(0,1)范围
非线性svm
详细
- 二分类任务
- 样本数300
- 非线性svm, 高斯核(rbf)
- 正负样本均衡
目标
- 对样本数据进行分类并绘图
详细代码
# 非线性SVM
# Non-linear SVM
# https://scikit-learn.org/stable/auto_examples/svm/plot_svm_nonlinear.html#sphx-glr-auto-examples-svm-plot-svm-nonlinear-py
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
# 模拟数据
from sklearn.model_selection import train_test_split
xx, yy = np.meshgrid(np.linspace(-3, 3, 500),
np.linspace(-3, 3, 500))
np.random.seed(0)
X = np.random.randn(300, 2) # randn函数返回一个或一组样本,具有标准正态分布 shape(300,2)
# 为样本添加标签
# 逻辑或操作,如果第一个特征和第二个特征均大于0则为true,否则为false,(true,和false这里作为标签)
Y = np.logical_xor(X[:, 0] > 0, X[:, 1] > 0) # shape(300,) 1行300个 bool数组
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state=14)
# fit the model
# 采用 rbf内核 Radial Based Function 指的是我们要计算的函数的结果只和距离(∥x−xn∥)有关;
# rbf内核可以进行非线性分类
# 与SVC类似,但使用一个参数来控制支持向量的数量
clf = svm.NuSVC(gamma='auto')
# clf = svm.LinearSVC() 如果是linear内核就只能是线性的 polynomial内核 (多项式内核)也是非线性的
# clf = svm.SVC()
clf.fit(X_train, y_train)
y_res = clf.predict(X_test)
_score = clf.score(X_test, y_test)
print(_score)
# np.r_是按列连接两个矩阵,就是把两矩阵上下相加,要求列数相等。 添加行
# np.c_是按行连接两个矩阵,就是把两矩阵左右相加,要求行数相等。 添加列
Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# 绘制热图
# Z 类数组对象(array_like),shape(n,m) 或者(n,m,3)或者(n,m,4) 分别对应颜色表示方式
# 热图(heatmap)是数据分析的常用方法,通过色差、亮度来展示数据的差异、易于理解
# interpolation代表的是插值运算,'nearest'只是选取了其中的一种插值方式 用于图片缩放
# aspect='auto' 则改变图片的横纵比、以便适应坐标轴的横纵比
# extent 图表的X、Y轴的刻度标签所指定的范围. 即让指定了图像四个角的坐标
# 使用origin =’upper’,数组Z的[0,0]索引位于范围的左上角.如果origin =’lower’,它将被放置在左下角.
plt.imshow(Z, interpolation='nearest',
extent=(xx.min(), xx.max(), yy.min(), yy.max()), aspect='auto',
origin='upper', cmap=plt.cm.PuOr_r)
contours = plt.contour(xx, yy, Z, levels=[0], linewidths=2,
linestyles='dashed')
plt.scatter(X_train[:, 0], X_train[:, 1], s=30, c=y_train, cmap=plt.cm.Paired,
edgecolors='k')
plt.scatter(X_test[:, 0], X_test[:, 1], s=30, c=y_test,
edgecolors='k', marker="x", cmap=plt.cm.Paired)
# 设置横纵坐标,因为没有参数,相当于取消横纵坐标
plt.xticks(())
plt.yticks(())
plt.axis([-3, 3, -3, 3])
plt.show()
结果图
- 使用非线性svm
- 使用线性svm
结果分析
- 使用非线性的svm在此例中效果明显更好