2023.10.11学习
人工智能基础学习
复习了支持向量机的概念,并对核函数和软间隔多学习了一些。
在应用于二分类的情况下,svc算法的目标是试图找到一个区分两类数据的平面,这个平面最好位于中间,这样的话分类的准确性较高,容许误差的能力较好,鲁棒性好。
拉格朗日乘子法:将有约束的极值问题转化为无约束的极值问题,就是在最优控制里面讲到的算法。
核函数
线性核函数 svc = SVC(kernel='linear')
,只有使用线性核函数的SVC有 coef_
参数
非线性核函数:
(1)默认参数为高斯核函数 (kernel='rbf'
),svc = SVC()
,高斯分布即正态分布,一般认为这种方法比较好
(2)poly多项式核函数 svc = SVC(kernel='poly')
(升维,数据由少变多),参数degree
可指定最高幂次,偏置项coef0
可设置常数项(对结果影响较小)
(3)sigmoid核函数 svc = SVC(kernel='sigmoid')
硬间隔和软间隔
硬间隔:样本点完全线性可分,不容忍误差。
软间隔:允许个别点出现在间隔带中
C,可理解为错误样本的惩罚程度
C越大,正则化越大,松弛因子越小,分类严格,越容易出现过拟合;C趋于正无穷,则意味着数据完全线性可分
对于同一问题,使用不同的核函数效果不同,也并不是所有的数据用高斯核函数最好
from sklearn import datasets
from matplotlib import pyplot as plt
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from matplotlib.colors import ListedColormap
X, y = datasets.load_wine(return_X_y=True) # 返回葡萄酒数据
# 参数:return_X_y=True则返回(data, target),数据类型为pandas DataFrames或Series。其默认参数为False, 返回类字典对象Bunch
print(X.shape, type(X)) # (178, 13) <class 'numpy.ndarray'>
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) # 划分训练集和测试集
print(X_train.shape) # (142, 13)
# 创建模型
svc = SVC(kernel='linear')
svc.fit(X_train, y_train)
print(svc.coef_, svc.intercept_) # 权重参数和偏执截距
# 使用的数据共有三个类别,属性为13种,故数据的维度为(3, 13),svc.coef_为3个13维的向量(3个法向量,分别有13个维度)
# 因为使用的核函数为线性核函数,故intercept_对应3个截距
y_test_predict = svc.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_test_predict)
print(accuracy) # 近1.0
# 创建模型(poly核函数)
svc = SVC(kernel='poly') # 升维,将数据由少变多
svc.fit(X_train, y_train)
y_test_predict = svc.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_test_predict)
print(accuracy) # 0.6944444444444444
# 写了个小函数省略代码行数
def svc_kernel_test(kernel):
svc = SVC(kernel=kernel)
svc.fit(X_train, y_train)
y_test_predict = svc.predict(X_test)
accuracy = accuracy_score(y_test, y_test_predict)
print(accuracy)
svc_kernel_test('rbf') # 0.6388888888888888
svc_kernel_test('sigmoid') # 0.2777777777777778
说明对于葡萄酒数据的分类,使用线性核函数的效果是最好的。
——————————————
非线性核函数应用,以两个圆的散点分类为例
X, y = datasets.make_circles(n_samples=100, factor=0.7) # 参数:生成100个数据,大小0.7
X += np.random.randn(100, 2)*0.05 # 给数据加一些噪声
print(X.shape, y.shape) # (100, 2) (100,)
fig1 = plt.figure(figsize=(5, 5))
cmap = ListedColormap(colors=['red', 'blue']) # 指定不同类别数据的颜色列表
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap)
plt.show()
# 先测试一下线性核函数
svc1 = SVC(kernel='linear')
svc1.fit(X, y)
print(svc1.score(X, y)) # 返回拟合精确度,参数是待测试的数据及其标签。0.53
y_predict = svc1.predict(X)
fig2 = plt.figure(figsize=(5, 5))
x_axis = np.linspace(-1.1, 1.1, 100).reshape(-1, 1)
w = svc1.coef_[0]
b = svc1.intercept_[0]
decision_boundary = (-x_axis*w[0] - b)/w[1]
plt.plot(x_axis, decision_boundary)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap)
plt.scatter(X[:, 0], X[:, 1], c=y_predict)
plt.title("kernel='linear'")
plt.show()
# 测试多项式poly核函数
svc2 = SVC(kernel='poly', degree=3) # 参数degree:多项式的最高幂次,默认为3次
svc2.fit(X, y)
print(svc2.score(X, y)) # 三次:0.68; 二次:1.0
y2_predict = svc2.predict(X)
# 坐标数据生成与预测
x_1_axis = np.linspace(-1.1, 1.1, 100)
x_2_axis = np.linspace(-1.1, 1.1, 100)
print(x_1_axis.shape, x_2_axis.shape) # (100,) (100,)
x_1_axis, x_2_axis = np.meshgrid(x_1_axis, x_2_axis) # 网格交叉
print(x_1_axis.shape, x_2_axis.shape) # (100, 100) (100, 100)
X_axis = np.column_stack([x_1_axis.ravel(), x_2_axis.ravel()]) # 列的合并
print(X_axis.shape) # (10000, 2)
y2_axis_predict = svc2.predict(X_axis)
fig3 = plt.figure(figsize=(5, 5))
plt.scatter(X_axis[:, 0], X_axis[:, 1], c=y2_axis_predict)
plt.scatter(X[:, 0], X[:, 1], c=y2_predict, cmap=cmap)
plt.title("kernel='poly', degree=3")
plt.show()
# 测试高斯核函数
svc3 = SVC()
svc3.fit(X, y)
print(svc3.score(X, y)) # 1.0
y3_predict = svc3.predict(X)
y_axis_predict = svc3.predict(X_axis)
fig4 = plt.figure(figsize=(5, 5))
plt.scatter(X_axis[:, 0], X_axis[:, 1], c=y_axis_predict)
plt.scatter(X[:, 0], X[:, 1], c=y3_predict, cmap=cmap)
plt.title("kernel='rbf'")
plt.show()
关于软间隔的测试
C值较小,容忍一些错误,间隔大,防止过拟合
C值较大,分类严格,间隔小,可能过拟合
代码:(因为数据量较小,C值取的非常小了才看出来区别)
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
# 绘制决策边界和上下边界曲线
def plot_svc_decision_line(svm_clf, xmin, xmax, sv=True):
w = svm_clf.coef_[0] # 权重参数w
b = svm_clf.intercept_[0] # 偏置参数b
x0 = np.linspace(xmin, xmax, 1000) # 设置横轴坐标数据
decision_boundary = (-x0*w[0] - b)/w[1] # 决策边界点值
margin = 1/w[1] # 最近点到决策边界的距离
gutter_up = decision_boundary + margin # 上分离曲线
gutter_down = decision_boundary - margin # 下分离曲线
if sv:
svs = svm_clf.support_vectors_ # 所有的支持向量
plt.scatter(svs[:, 0], svs[:, 1], s=180, facecolors='r') # 绘制支持向量点
plt.plot(x0, decision_boundary, linewidth=2) # 绘制决策边界
plt.plot(x0, gutter_up, 'k--', linewidth=2)
plt.plot(x0, gutter_down, 'k--', linewidth=2)
# 关于软间隔(C值)的测试
data_fault = pd.read_csv('data2.csv')
X2 = data_fault.drop('label', axis=1)
y2 = data_fault.loc[:, 'label']
fig2 = plt.figure()
y2_0 = plt.scatter(X2.loc[:, 'V1'][y2 == 0], X2.loc[:, 'V2'][y2 == 0])
y2_1 = plt.scatter(X2.loc[:, 'V1'][y2 == 1], X2.loc[:, 'V2'][y2 == 1])
plt.show()
svm_clf2 = SVC(kernel='linear', C=1)
svm_clf2.fit(X2, y2)
print(svm_clf2.predict([[50, 41]]))
plot_svc_decision_line(svm_clf2, 0, 160)
y2_0 = plt.scatter(X2.loc[:, 'V1'][y2 == 0], X2.loc[:, 'V2'][y2 == 0])
y2_1 = plt.scatter(X2.loc[:, 'V1'][y2 == 1], X2.loc[:, 'V2'][y2 == 1])
plt.title('C=1')
plt.show()