系列文章目录
监督学习:参数方法
【学习笔记】 陈强-机器学习-Python-Ch4 线性回归
【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归
【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv)
【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归
【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析
【学习笔记】 陈强-机器学习-Python-Ch8 朴素贝叶斯
【学习笔记】 陈强-机器学习-Python-Ch9 惩罚回归
【课后题练习】 陈强-机器学习-Python-Ch9 惩罚回归(student-mat.csv)
监督学习:非参数方法
【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch10 KNN法
【学习笔记】 陈强-机器学习-Python-Ch11 决策树(Decision Tree)
监督学习:集成学习
【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch12 随机森林(Random Forest)
【学习笔记】 陈强-机器学习-Python-Ch13 提升法
文章目录
前言
本学习笔记 仅为以防自己忘记了,顺便分享给一起学习的网友们参考。如有不同意见/建议,可以友好讨论。
本学习笔记 所有的代码和数据都可以从 陈强老师的个人主页 上下载
参考书目:陈强.机器学习及Python应用. 北京:高等教育出版社, 2021.
数学原理等 详见陈强老师的 PPT
参考了:网友阡之尘埃的Python机器学习11——支持向量机
一、支持向量机(Support Vector Machine, SVM)
分类问题
在分类任务中,SVM的目标是找到一个最佳的超平面(hyperplane),以便将数据集中的不同类别分开。这个超平面在特征空间中将数据点分为不同的类别,并且与这些点的距离尽可能远。这样做的目的是最大化分类的边界,增强模型的泛化能力。
回归问题
对于回归任务,SVM旨在找到一个函数,使得预测值与实际值之间的差异尽可能小。与分类任务不同,回归任务中的目标是使预测值落在一个容忍误差的范围内,而不是严格地将数据分开。
核技巧(Kernel Trick)
SVM能够处理非线性分类问题,主要得益于核技巧。核函数通过将数据映射到高维空间,使得在原始空间中不可分的数据在高维空间中变得线性可分。常见的核函数包括:
1.线性核(Linear Kernel):
(
⟨
x
,
x
′
⟩
)
(\langle \mathbf{x}, \mathbf{x'} \rangle)
(⟨x,x′⟩)
2.多项式核(Polynomial Kernel):
(
(
γ
⟨
x
,
x
′
⟩
+
r
)
d
)
((\gamma \langle \mathbf{x}, \mathbf{x'} \rangle + r)^d)
((γ⟨x,x′⟩+r)d)
3.高斯径向基核(RBF Kernel):
(
exp
(
−
γ
∣
x
−
x
′
∣
2
)
)
(\exp(-\gamma |\mathbf{x} - \mathbf{x'}|^2))
(exp(−γ∣x−x′∣2))
4.Sigmoid核(Sigmoid Kernel):
(
tanh
(
γ
⟨
x
,
x
′
⟩
+
r
)
)
(\tanh(\gamma \langle \mathbf{x}, \mathbf{x'} \rangle + r))
(tanh(γ⟨x,x′⟩+r))
SVM优点与缺点
优点:
高效的高维数据处理: SVM在高维数据中表现良好,特别是在特征空间非常大时。强大的泛化能力: 通过最大化间隔,SVM可以有效地防止过拟合。
缺点: 计算复杂度: 对于非常大的数据集,SVM的训练时间可能较长。参数选择: 核函数的选择和超参数(如C、γ)的调整可能较为复杂,需要进行交叉验证。
二、SVM二分类 案例
使用过滤垃圾邮件的spam数据( 参见【学习笔记】 陈强-机器学习-Python-Ch8 朴素贝叶斯 )
1. 载入、处理数据
import pandas as pd
import numpy as np
# 读取数据
csv_path = r'D:\桌面文件\Python\【陈强-机器学习】MLPython-PPT-PDF\MLPython_Data\spam.csv'
spam = pd.read_csv(csv_path)
X = spam.iloc[:, :-1]
y = spam.iloc[:, -1]
#定义X与y
X = spam.iloc[:, :-1]
y = spam.iloc[:, -1]
#全样本随机分20%测试集和80%训练集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=1000, #训练集;1000个观测值
stratify=y,
random_state=0)
#特征变量 标准化
from sklearn.preprocessing import StandardScaler
#生成一个实例scaler
scaler = StandardScaler()
#进行估计
scaler.fit(X_train)
#使用transform()分别将 训练集、测试集的特征变量进行标准化
X_train_s = scaler.transform(X_train)
X_test_s = scaler.transform(X_test)
#检验标准化:均值/标准差
print(np.mean(X_train_s,axis=0))
np.std(X_train_s,axis=0)
注意:即使标准化后,测试集的特征变量的均值也不为0,标准差也不为1。这是正常结果。
2. 分别采用不同的核函数进行SVC估计
1)线性核函数
from sklearn.svm import SVC
# 1. 线性核函数
model_linear = SVC(kernel="linear",
random_state=123) #默认:C=1.0,γ='scale'(即γ=[pVar(x)]^-1,p为特征变量个数)
model_linear.fit(X_train_s, y_train)
model_linear.score(X_test_s, y_test)
结果输出: 0.935
2)二次多项式核
# 2. 二次多项式核
model_2poly = SVC(kernel="poly", #多项式
degree=2, #二阶
random_state=123)
model_2poly.fit(X_train_s, y_train)
model_2poly.score(X_test_s, y_test)
结果输出: 0.848
3)三次多项式
# 3. 三次多项式
model_3poly = SVC(kernel="poly",
degree=3,
random_state=123)
model_3poly.fit(X_train_s, y_train)
model_3poly.score(X_test_s, y_test)
结果输出: 0.77
4)径向核 RBF
# 4. 径向核 RBF
model_rbf = SVC(kernel="rbf",
random_state=123)
model_rbf.fit(X_train_s, y_train)
model_rbf.score(X_test_s, y_test)
结果输出: 0.944
5)Sigmoid核
# 5. S型核 (Sigmoid kernel)
model_sigmoid = SVC(kernel="sigmoid",
random_state=123)
model_sigmoid.fit(X_train_s, y_train)
model_sigmoid.score(X_test_s, y_test)
结果输出: 0.891
笔记:SVC()
SVC(支持向量分类器)是 scikit-learn 中用于分类任务的支持向量机(SVM)实现。
#基本语法和参数
from sklearn.svm import SVC
# 创建 SVC 模型
model = SVC(
C=1.0, #正则化参数,默认为 1.0
kernel='rbf', #核函数类型,默认为 'rbf'。可选值包括 'linear', 'poly', 'rbf', 'sigmoid', 'precomputed'。
degree=3, # 【仅在使用 'poly' 核函数】时有效,指定多项式核的度数,默认为 3。
gamma='scale', #核函数的系数,默认为 'scale'。可以设置为 'scale'(1 / (n_features * X.var()))或 'auto'(1 / n_features)或一个浮点数值。特征标准化后,'scale'=(1 / n_features)
coef0=0.0, #核函数中的常数项,默认为 0.0。【在 'poly' 和 'sigmoid' 核函数中使用。】
shrinking=True, #是否使用启发式收缩策略,默认为 True
probability=False, #是否启用概率估计,默认为 False
tol=0.001, #停止标准,默认为 0.001。表示算法停止训练的误差容忍度。
cache_size=200, #核函数计算缓存大小(MB),默认为 200。
class_weight=None, #类别权重,默认为 None。或使用 'balanced' 来自动调整。
verbose=False, #是否输出详细的训练过程信息,默认为 False。
max_iter=-1, #最大迭代次数,默认为 -1,表示不限制迭代次数。【另,只能是整数!!浮点不行!!!】
decision_function_shape='ovr', #决策函数的形状,默认为 'ovr'(一对多)。还可以设置为 'ovo'(一对一)。
break_ties=False, #在决策函数形状为 'ovr' 时是否打破决策函数中的平局,默认为 False。
random_state=None)
3. 选择最优的调节参数组合(C,γ)
不同的核函数SVM估计中,径向核(rbf)的预测效果最好。以径向核作为网格搜索的模型对象,通过交叉验证,选择出最优的调节参数组合(C,γ)。
#设定字典形式的参数网格 :
param_grid = {'C': [0.1, 1, 10],
'gamma': [0.01, 0.1, 1]}
#使用GridSearchCV类,进行10折交叉验证,并展示最优参数组合:
from sklearn.model_selection import StratifiedKFold
kfold = StratifiedKFold(n_splits=10,
shuffle=True,
random_state=1)
from sklearn.model_selection import GridSearchCV
model = GridSearchCV(
SVC(kernel='rbf', random_state=123),
param_grid,
cv=kfold)
model.fit(X_train_s, y_train)
model.best_params_
结果输出: {‘C’: 10, ‘gamma’: 0.01}
#根据前面所估的最优模型model,使用score()方法,计算测试集的预测准确率
model.score(X_test_s, y_test)
结果输出: 0.948 高于默认参数的rbf
4. 在测试集中进行预测,并计算混淆矩阵
#在测试集中进行预测,并计算混淆矩阵
pred = model.predict(X_test)
pd.crosstab(y_test, pred,
rownames=['Actual'],
colnames=['Predicted'])
结果输出:
三、SVM多分类 案例
以 sklearn模块自带的手写数字数据 作 sklearn digits 为案例。
1. 载入、处理数据
import pandas as pd
import numpy as np
# 读取数据
from sklearn.datasets import load_digits
digits=load_digits()
dir(digits) #查看digits的各组成部分
结果输出: [‘DESCR’, ‘data’, ‘feature_names’, ‘frame’, ‘images’, ‘target’, ‘target_names’]
target:每张图片对于的数字(取值0-9之间的10个整数),作为响应变量
1)响应变量:target
print(digits.target.shape)
pd.Series(digits.target).value_counts()
结果输出:(1797,)
3 183
1 182
5 182
4 181
6 181
9 180
7 179
0 178
2 177
8 174
Name: count, dtype: int64
#打印第8个图像
import matplotlib.pyplot as plt
plt.imshow(digits.images[8], cmap=plt.cm.gray_r)
#考察第8个元素
print(digits.target[8])
结果输出: 8
#打印最前面9个数字“8”
images_8 = digits.images[digits.target==8]
for i in range(1, 10):
plt.subplot(3, 3, i)
plt.imshow(images_8[i-1], cmap=plt.cm.gray_r)
plt.tight_layout()
2)取出X,y;分训练集、测试集
X = digits.data
y = digits.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, stratify=y, test_size=0.2, random_state=0)
2. 分别采用不同的核函数进行SVC估计
1)线性核函数
from sklearn.svm import SVC
# 1. 线性核函数
model_linear = SVC(kernel="linear",
random_state=123)
model_linear.fit(X_train, y_train)
model_linear.score(X_test, y_test)
结果输出: 0.9722222222222222
2)二次多项式核
# 2. 二次多项式核
model_2poly = SVC(kernel="poly",
degree=2,
random_state=123)
model_2poly.fit(X_train, y_train)
model_2poly.score(X_test, y_test)
结果输出: 0.9888888888888889
3)三次多项式
# 3. 三次多项式
model_3poly = SVC(kernel="poly",
degree=3,
random_state=123)
model_3poly.fit(X_train, y_train)
model_3poly.score(X_test, y_test)
结果输出: 0.9944444444444445
4)径向核 RBF
# 4. 径向核 RBF
model_rbf = SVC(kernel="rbf",
random_state=123)
model_rbf.fit(X_train_s, y_train)
model_rbf.score(X_test_s, y_test)
结果输出: 0.9833333333333333
5)Sigmoid核
# 5. S型核 (Sigmoid kernel)
model_sigmoid = SVC(kernel="sigmoid",
random_state=123)
model_sigmoid.fit(X_train_s, y_train)
model_sigmoid.score(X_test_s, y_test)
结果输出: 0.8916666666666667
3. 选择最优的调节参数(C,γ)
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import StratifiedKFold
#先设定字典形式的参数网格 :
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10],
'gamma': [0.001, 0.01, 0.1, 1, 10]}
#使用GridSearchCV类,进行10折交叉验证,并展示最优参数组合:
kfold = StratifiedKFold(n_splits=10,
shuffle=True,
random_state=1)
model = GridSearchCV(
SVC(kernel='rbf', random_state=123),
param_grid, cv=kfold)
model.fit(X_train_s, y_train)
model.best_params_
结果输出: {‘C’: 1, ‘gamma’: 0.001}
#根据前面所估的最优模型model,使用score()方法,计算测试集的预测准确率
model.score(X_test_s, y_test)
结果输出: 0.9888888888888889
4. 在测试集中进行预测,并计算混淆矩阵
#在测试集中进行预测,并计算混淆矩阵
pred = model.predict(X_test)
pd.crosstab(y_test, pred,
rownames=['Actual'],
colnames=['Predicted'])
结果输出:
5.画 混淆矩阵 热图:ConfusionMatrixDisplay
陈强老师书上用的函数是plot_confusion_matrix, 在 scikit-learn 1.0 中已弃用,并在 1.2 中删除。
参考了:
网友少冰半糖冰淇淋的解决报错:from sklearn.metrics import plot_confusion_matrix
网友算法驯化师的【Sklearn-Bug驯化-混淆矩阵】成功Sklearn中plot_confusion_matrix出现ImportError: cannot import name ‘plot_confusion (还提供了降低版本的方法)
1)ConfusionMatrixDisplay.from_predictions()
我个人更喜欢这个,更简单一点
from sklearn.metrics import ConfusionMatrixDisplay
ConfusionMatrixDisplay.from_predictions(
y_test, pred)
结果输出:
笔记:ConfusionMatrixDisplay.from_predictions()
ConfusionMatrixDisplay.from_predictions() 是 scikit-learn 1.0 版本引入的一个便捷方法,用于直接从预测结果和真实标签创建并显示混淆矩阵。这种方法简化了生成混淆矩阵的过程,不需要手动计算混淆矩阵。
#基本语法和参数
from sklearn.metrics import ConfusionMatrixDisplay
# 创建并显示混淆矩阵
ConfusionMatrixDisplay.from_predictions(
y_true, #真实标签数组或列表
y_pred, #预测
*, #以下可选
labels=None, #标签列表,定义混淆矩阵的标签顺序。默认值为 None
sample_weight=None, #样本权重数组。默认值为 None。
normalize=None, #字符串或 None。用于规范化混淆矩阵的方式,选择 'true'(按真实标签行进行规范化)、'pred'(按预测标签列进行规范化)或 'all'(按所有样本进行规范化)。默认值为 None。
include_values=True, #是否在图中显示数值。默认值为 True。
cmap='viridis', #颜色映射,用于混淆矩阵的颜色。默认值为 'viridis'。
ax=None,
colorbar=True, #是否显示颜色条。默认值为 True。
im_kw=None, #imshow 函数的关键字参数。用于调整图像显示的参数。
text_kw=None, #文本显示的关键字参数。用于调整文本显示的参数。
display_labels=None #标签名称的列表。用于指定混淆矩阵的显示标签。
)
2)ConfusionMatrixDisplay.from_estimator()
更接近陈强老师书里的表达
from sklearn.metrics import ConfusionMatrixDisplay
ConfusionMatrixDisplay.from_estimator(
model, # 训练好的模型
X_test, # 测试特征
y_test, # 测试标签
cmap=plt.cm.Blues, # 颜色图
display_labels=digits.target_names # 类别标签
)
plt.title('ConfusionMatrix') #可以不写
plt.show() #可以不写
结果输出:
笔记:ConfusionMatrixDisplay.from_estimator()
ConfusionMatrixDisplay.from_estimator() 是 scikit-learn 提供的一个函数,用于**从估计器(模型)**生成混淆矩阵并进行可视化。它通过从训练好的模型直接获取预测结果和真实标签来创建混淆矩阵。
#基本语法和参数
from sklearn.metrics import ConfusionMatrixDisplay
# 创建并显示混淆矩阵
ConfusionMatrixDisplay.from_estimator(
estimator, # 已训练的估计器(模型)
X, #特征数据
y_true=None, #真实标签数组或列表。如果未提供,函数将无法计算混淆矩阵。
*, #以下可选
labels=None, #标签列表,定义混淆矩阵的标签顺序。默认值为 None
sample_weight=None, #样本权重数组。默认值为 None。
normalize=None, #用于规范化混淆矩阵的方式,选择 'true'(按真实标签行进行规范化)、'pred'(按预测标签列进行规范化)或 'all'(按所有样本进行规范化)。默认值为 None。
include_values=True, #是否在图中显示数值。默认值为 True。
cmap='viridis', #颜色映射,用于混淆矩阵的颜色。默认值为 'viridis'。
ax=None,
colorbar=True, #是否显示颜色条。默认值为 True。
im_kw=None, #imshow 函数的关键字参数。
text_kw=None, #文本显示的关键字参数。
display_labels=None #标签名称的列表。
)
四、SVM回归 案例
以波士顿房价数据 boston为例(参见【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 )
1. 载入、处理数据
import numpy as np
import pandas as pd
# 从原始来源加载数据
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep=r"\s+", skiprows=22, header=None)
# 处理数据
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]
# 创建DataFrame
columns = [
"CRIM", "ZN", "INDUS", "CHAS", "NOX", "RM", "AGE", "DIS", "RAD", "TAX",
"PTRATIO", "B", "LSTAT"
]
df = pd.DataFrame(data, columns=columns)
df['MEDV'] = target
# 确定特征
X = df.drop(columns=['MEDV'])
y = df['MEDV']
# 将数据分割为训练集(70%)和测试集(30%)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=1)
#特征变量 标准化
from sklearn.preprocessing import StandardScaler
#生成一个实例scaler
scaler = StandardScaler()
#进行估计
scaler.fit(X_train)
#使用transform()分别将 训练集、测试集的特征变量进行标准化
X_train_s = scaler.transform(X_train)
X_test_s = scaler.transform(X_test)
#检验标准化:均值/标准差
print(np.mean(X_train_s,axis=0))
np.std(X_train_s,axis=0)
结果输出:
2. SVR估计
from sklearn.svm import SVR
model_rbf = SVR(kernel="rbf") #默认参数ε=0.1
model_rbf.fit(X_train_s, y_train)
model_rbf.score(X_test_s, y_test)
结果输出: 0.6638733322326673
笔记:SVR()
xgb.XGBRegressor() 是 XGBoost 库中的一个类,用于解决回归问题。XGBoost(eXtreme Gradient Boosting)是一个高效的实现梯度提升算法的库,广泛用于机器学习中的回归、分类和排序任务。它是基于决策树算法的集成方法,通过构建多个模型并组合它们的预测结果来提高预测的准确性和稳定性。
#基本语法和参数
from sklearn.svm import SVR
#创建SVR 模型
SVR(C=1.0, #正则化参数,默认为 1.0
epsilon=0.1, # 阈值,表示在预测值与真实值之间的容忍度。模型允许预测与真实值之间的误差在这个范围内,默认为 0.1。
kernel='rbf', #核函数类型,默认为 'rbf'(径向基函数)。可以选择 'linear'(线性核)、'poly'(多项式核)、'rbf'(径向基函数核)、'sigmoid'(Sigmoid核)或 'precomputed'(预计算核)。
degree=3, #【仅在使用 'poly' 核函数时】有效,指定多项式核的度数,默认为 3。
gamma='scale', # 核函数的系数,默认为 'scale'。
coef0=0.0, #核函数中的常数项,默认为 0.0。在 'poly' 和 'sigmoid' 核函数中使用。
shrinking=True, #是否使用启发式收缩策略,默认为 True
tol=0.001, #停止标准,默认为 0.001。表示算法停止训练的误差容忍度。
cache_size=200, # 核函数计算缓存大小(MB),默认为 200。
verbose=False, #是否输出详细的训练过程信息,默认为 False。
max_iter=-1,
random_state=None)
3. 选择最优的调节参数(C,γ)
#先设定字典形式的参数网格 :
param_grid = {'C': [0.01, 0.1, 1, 10, 50, 100, 150],
'epsilon': [0.01, 0.1, 1, 10],
'gamma': [0.01, 0.1, 1, 10]}
#使用GridSearchCV类,进行10折交叉验证,并展示最优参数组合:
from sklearn.model_selection import KFold
kfold = KFold(n_splits=10, shuffle=True, random_state=1)
from sklearn.model_selection import GridSearchCV
model = GridSearchCV(
SVR(),
param_grid,
cv=kfold)
model.fit(X_train_s, y_train)
model.best_params_
结果输出: {‘C’: 100, ‘epsilon’: 1, ‘gamma’: 0.1}
#根据前面所估的最优模型model,使用score()方法,计算测试集的预测准确率
model.score(X_test_s, y_test)
结果输出: 0.9155607536119317 明显高了很多
4. 对比:线性回归
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X_train, y_train)
model.score(X_test, y_test)
结果输出: 0.7836295385076302 低于最优参数组合的最优模型