[机器学习-原理篇]支持向量机(SVM)深入理解
利用sklearn中自带的dataset,鸢尾花数据库为例,进行二分类。
#载入鸢尾花数据集,datasets自带数据库,房价的、鸢尾花等,
#导入:datasets_load_name(),直接np数组形式
from sklearn import svm,datasets
iris = datasets.load_iris()
#X是特征集,150*4,这里只取其中两列作为特征
X = iris.data[:,(1,2)]
#y是标签集,共012三个类别,这里将1替换为2,化为两个类别
y = iris.target
y[y==1]=2
print(y)
print (X)
[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 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2]
[[3.5 1.4]
[3. 1.4]
[3.2 1.3]
[3.1 1.5]
....
[3. 5.1]]
import numpy as np
import pylab as pl
#画出散点图
#c=y,以标签值为散点着色,形式为cmap
pl.scatter(X[:, 0], X[:, 1], c=y, cmap=pl.cm.Paired)
#调用SVC(),二分类,采用线性核函数
clf = svm.SVC(kernel='linear',C=0.1)
clf.fit(X,y)
#计算分割超平面
w = clf.coef_[0]
a = -w[0] / w[1]
xx = np.linspace(2, 4)
yy = a * xx - (clf.intercept_[0]) / w[1]
pl.plot(xx, yy, 'k-')
pl.axis('tight')
# 超平面:a1*X1+a2*X2+b=0,clf.intercept 为截距b,clf.coef为系数 a1 a2(只在线性核时,存在)
#计算上下分割线
b = clf.support_vectors_[0]
yy_down = a * xx + (b[1] - a * b[0])
b = clf.support_vectors_[-1]
yy_up = a * xx + (b[1] - a * b[0])
pl.plot(xx, yy_down, 'k--')
pl.plot(xx, yy_up, 'k--')
#输出系数项,斜率,支持向量等
print("w: ", w)
print("a: ", a)
print("support_vectors_: ", clf.support_vectors_)
print("clf.coef_: ", clf.coef_)
print ('支持向量:',clf.support_vectors_)
# 获得支持向量的索引
print ('支持向量索引:',clf.support_)
# 为每一个类别获得支持向量的数量
print ('支持向量数量:',clf.n_support_)
pl.show()
w: [-0.32871371 0.86232368]
a: 0.3811952715822236
support_vectors_: [[3.3 1.7]
[3.4 1.9]
[3. 1.6]
[3.1 1.6]
[2.3 1.3]
[3.8 1.9]
[2.4 3.3]
[2. 3.5]
[2.9 3.6]
[2.6 3.5]
[2.3 3.3]
[2.5 3. ]]
clf.coef_: [[-0.32871371 0.86232368]]
支持向量: [[3.3 1.7]
[3.4 1.9]
[3. 1.6]
[3.1 1.6]
[2.3 1.3]
[3.8 1.9]
[2.4 3.3]
[2. 3.5]
[2.9 3.6]
[2.6 3.5]
[2.3 3.3]
[2.5 3. ]]
支持向量索引: [23 24 25 30 41 44 57 60 64 79 93 98]
支持向量数量: [6 6]
C:错误项的惩罚系数。C越大,即对分错样本的惩罚程度越大,因此在训练样本中准确率越高,但是泛化能力降低,也就是对测试数据的分类准确率降低。相反,减小C的话,容许训练样本中有一些误分类错误样本,泛化能力强。对于训练样本带有噪声的情况,一般采用后者,把训练样本集中错误分类的样本作为噪声。
kernel='linear’时,为线性核,C越大分类效果越好,但有可能会过拟合(defaul C=1)。
kernel='rbf’时(default),为高斯核,gamma值越小,分类界面越连续;gamma值越大,分类界面越“散”,分类效果越好,但有可能会过拟合。
kernel='poly’时,多项式函数,degree 表示多项式的程度-----支持非线性分类。更高gamma值,将尝试精确匹配每一个训练数据集,可能会导致泛化误差和引起过度拟合问题。
kernel='sigmoid’时,支持非线性分类。更高gamma值,将尝试精确匹配每一个训练数据集,可能会导致泛化误差和引起过度拟合问题。
gamma:float参数 默认为auto。核函数系数,只对‘rbf’,‘poly’,‘sigmod’有效。如果gamma为auto,代表其值为样本特征数的倒数,即1/n_features.
decision_function_shape='ovr’时,为one v rest,即一个类别与其他类别进行划分,
decision_function_shape='ovo’时,为one v one,即将类别两两之间进行划分,用二分类的方法模拟多分类的结果。
probability:bool参数 默认为False,是否启用概率估计。 这必须在调用fit()之前启用,并且会fit()方法速度变慢。
cache_size:float参数 默认为200,指定训练所需要的内存,以MB为单位,默认为200MB。
class_weight:字典类型或者‘balance’字符串。默认为None,给每个类别分别设置不同的惩罚参数C,如果没有给,则会给所有类别都给C=1,即前面参数指出的参数C.如果给定参数‘balance’,则使用y的值自动调整与输入数据中的类频率成反比的权重。
max_iter :int参数 默认为-1,最大迭代次数,如果为-1,表示不限制 model = svm.SVC(C=1.0, kernel=‘rbf’, gamma=‘auto’, decision_function_shape=‘ovr’,cache_size=500)
from sklearn import svm,datasets
X = [[0], [1], [2], [3]]
Y = [0, 1, 2, 3]
clf = svm.SVC(decision_function_shape='ovo')
clf.fit(X, Y)
dec = clf.decision_function([[1]])
print(dec.shape[1]) # 4 classes: 4*3/2 = 6
clf.decision_function_shape = "ovr"
dec = clf.decision_function([[1]])
print(dec.shape[1]) # 4 classes
lin_clf = svm.LinearSVC()
lin_clf.fit(X, Y)
dec = lin_clf.decision_function([[1]])
print(dec.shape[1])
print(dec.shape)
print(lin_clf.coef_)
print(lin_clf.intercept_)
clf = svm.SVC(kernel='linear',C=0.1, decision_function_shape='ovr')
clf.fit(X, Y)
print(lin_clf.coef_)
print(lin_clf.intercept_)
6
4
4
(1, 4)
[[-0.90908846]
[-0.20513063]
[ 0.10255497]
[ 0.41022512]]
[ 0.36363269 -0.17094457 -0.58122498 -0.99144108]
[[-0.90908846]
[-0.20513063]
[ 0.10255497]
[ 0.41022512]]
[ 0.36363269 -0.17094457 -0.58122498 -0.99144108]
import matplotlib.pyplot as plt
import numpy as np
from sklearn.svm import SVC
X = np.array([[-1, -1], [-2, -1], [1, 1], [2, 1], [-1, 1], [-1, 2], [1, -1], [1, -2]])
y = np.array([0, 0, 1, 1, 2, 2, 3, 3])
# y=np.array([1,1,2,2,3,3,4,4])
# clf = SVC(decision_function_shape="ovr",probability=True)
clf = SVC(probability=True, decision_function_shape="ovo")
clf.fit(X, y)
print(clf.decision_function(X))
'''
对于n分类,会有n个分类器,然后,任意两个分类器都可以算出一个分类界面,这样,用decision_function()时,对于任意一个样例,就会有n*(n-1)/2个值。
任意两个分类器可以算出一个分类界面,然后这个值就是距离分类界面的距离。
我想,这个函数是为了统计画图,对于二分类时最明显,用来统计每个点离超平面有多远,为了在空间中直观的表示数据以及画超平面还有间隔平面等。
decision_function_shape="ovr"时是4个值,为ovo时是6个值。
'''
print(clf.predict(X))
clf.predict_proba(X) # 这个是得分,每个分类器的得分,取最大得分对应的类。
# 画图
plot_step = 0.02
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, plot_step),
np.arange(y_min, y_max, plot_step))
print('xx:=',xx, xx.shape)
print('yy:=', yy, yy.shape)
print('xx.ravel()=',xx.ravel(), xx.ravel().shape)
print('yy.ravel()=', yy.ravel(), yy.ravel().shape)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) # 对坐标风格上的点进行预测,来画分界面。其实最终看到的类的分界线就是分界面的边界线。
Z = Z.reshape(xx.shape)
cs = plt.contourf(xx, yy, Z, cmap=plt.cm.Paired)
plt.axis("tight")
class_names = "ABCD"
plot_colors = "rybg"
for i, n, c in zip(range(4), class_names, plot_colors):
idx = np.where(y == i) # i为0或者1,两个类
plt.scatter(X[idx, 0], X[idx, 1],
c=c, cmap=plt.cm.Paired,
label="Class %s" % n)
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.legend(loc='upper right')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Decision Boundary')
plt.show()
[[ 1.00006256 0.99980309 0.83477528 -0.27845811 -0.24727203 -0.07609727]
[ 0.99980785 0.9998031 1.00046589 -0.28445414 -0.00873952 0.12009339]
[-0.99993521 -0.24727203 -0.27845811 0.83477528 0.99980309 0.07622272]
[-0.99993521 -0.00873952 -0.28445414 1.00046589 0.9998031 -0.12002341]
[ 0.07622272 -0.83425862 0.24756982 -1.00023294 0.27849207 1.00006256]
[-0.12002341 -0.99960621 0.00894039 -1.00023295 0.28451059 0.99980785]
[-0.07609727 0.27849207 -1.00023294 0.24756982 -0.83425862 -0.99993521]
[ 0.12009339 0.28451059 -1.00023295 0.00894039 -0.99960621 -0.99993521]]
[0 0 1 1 2 2 3 3]
xx:= [[-3. -2.98 -2.96 ... 2.94 2.96 2.98]
[-3. -2.98 -2.96 ... 2.94 2.96 2.98]
[-3. -2.98 -2.96 ... 2.94 2.96 2.98]
...
[-3. -2.98 -2.96 ... 2.94 2.96 2.98]
[-3. -2.98 -2.96 ... 2.94 2.96 2.98]
[-3. -2.98 -2.96 ... 2.94 2.96 2.98]] (300, 300)
yy:= [[-3. -3. -3. ... -3. -3. -3. ]
[-2.98 -2.98 -2.98 ... -2.98 -2.98 -2.98]
[-2.96 -2.96 -2.96 ... -2.96 -2.96 -2.96]
...
[ 2.94 2.94 2.94 ... 2.94 2.94 2.94]
[ 2.96 2.96 2.96 ... 2.96 2.96 2.96]
[ 2.98 2.98 2.98 ... 2.98 2.98 2.98]] (300, 300)
xx.ravel()= [-3. -2.98 -2.96 ... 2.94 2.96 2.98] (90000,)
yy.ravel()= [-3. -3. -3. ... 2.98 2.98 2.98] (90000,)
from sklearn import svm
X = [[0, 0], [2, 2]]
y = [0.5, 2.5]
regr = svm.SVR()
regr.fit(X, y)
print(regr.predict([[1, 1]]))
[1.5]
参考资料
[1] https://scikit-learn.org/stable/modules/svm.html