数据来源:Iris数据集,下载地址为:http://archive.ics.uci.edu/ml/datasets/Iris,
Iris.data中有5个属性,包括4个预测属性(萼片长度、萼片宽度、花瓣长度、花瓣宽度)和1个类别属性(Iris-setosa、Iris-versicolor、Iris-virginica三种类别)。
这里没什么要说的,网上一大堆。放两个给大家参考一下。
https://www.cnblogs.com/luyaoblog/p/6775342.html
https://blog.csdn.net/qq_45769063/article/details/106628800
from sklearn import svm
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.utils import shuffle
from sklearn.model_selection import RepeatedKFold
# 将label与数字对应,简化数据集
def Iris_label(s):
it = {b'Iris-setosa': 0, b'Iris-versicolor': 1, b'Iris-virginica': 2}
return it[s]
# 载入数据
path = 'iris.data'
data = np.loadtxt(path, dtype=float, delimiter=',', converters={4: Iris_label})
# print(data.shape) output:(150, 5)
# print(data.dtype) output:float64
# 在第4列之后进行切割,切割成2份
# axis=1表示竖着切
x, y = np.split(data, indices_or_sections=(4,), axis=1)
x = x[:, 0:2]
# 打乱数据集,使结果更加准确
x, y = shuffle(x, y, random_state=123)
# print(x, y)
# 划分训练集与测试集
# random_state相当于随机数种子,方便复现结果
train_data, test_data, train_label, test_label = train_test_split(x, y, random_state=1, train_size=0.7, test_size=0.3)
# 训练
classifier = svm.SVC(C=1, kernel='rbf', gamma=10)
classifier.fit(train_data, train_label.ravel())
# ravel()把标签集转换为list
# print(train_label.shape) output:(105, 1)
# print(train_label.ravel().shape) output:(105,)
# 计算准确率
print("train:", classifier.score(train_data, train_label))
print("test:", classifier.score(test_data, test_label))
# 法2
# tra_label = classifier.predict(train_data)
# tes_label = classifier.predict(test_data)
# print("train:", accuracy_score(train_label, tra_label))
# print("test:", accuracy_score(test_label, tes_label))
# 决策函数和预测结果
# print('train_decision_function:\n', classifier.decision_function(train_data))
# print('predict_result:\n', classifier.predict(train_data))
输出结果:
train: 0.8571428571428571
test: 0.7111111111111111
注意此时的超参数C=1, gamma=10。
svm.SVC参数说明:
https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html#sklearn.svm.SVC
通过修改C与gamma的值,来优化预测的准确率,使用交叉验证来获得更为准确的反馈,帮助我们选择最优参数。
有关交叉验证的说明如下:
以下内容摘自:
https://sklearn.apachecn.org/#/docs/master/30?id=_311-%e8%ae%a1%e7%ae%97%e4%ba%a4%e5%8f%89%e9%aa%8c%e8%af%81%e7%9a%84%e6%8c%87%e6%a0%87
当评价估计器的不同设置(”hyperparameters(超参数)”)时,例如手动为 SVM 设置的 C 参数, 由于在训练集上,通过调整参数设置使估计器的性能达到了最佳状态;但在测试集上可能会出现过拟合的情况。 此时,测试集上的信息反馈足以颠覆训练好的模型,评估的指标不再有效反映出模型的泛化性能。 为了解决此类问题,还应该准备另一部分被称为 “validation set(验证集)” 的数据集,模型训练完成以后在验证集上对模型进行评估。 当验证集上的评估实验比较成功时,在测试集上进行最后的评估。
然而,通过将原始数据分为3个数据集合,我们就大大减少了可用于模型学习的样本数量, 并且得到的结果依赖于集合对(训练,验证)的随机选择。这个问题可以通过交叉验证(CV ) 来解决。
交叉验证仍需要测试集做最后的模型评估,但不再需要验证集。最基本的方法被称之为,k-折交叉验证 。 k-折交叉验证将训练集划分为 k 个较小的集合。每一个 k 折都会遵循下面的过程:
将 k-1 份训练集子集作为 training data (训练集)训练模型
将剩余的1份训练集子集用于模型验证(也就是把它当做一个测试集来计算模型的性能指标,例如准确率)。
k-折交叉验证得出的性能指标是循环计算中每个值的平均值。 该方法虽然计算代价很高,但是它不会浪费太多的数据(如固定任意测试集的情况一样), 在处理样本数据集较少的问题(例如,逆向推理)时比较有优势。
参考:https://blog.csdn.net/qq_45769063/article/details/106693502
scoring的参数选择:https://scikit-learn.org/stable/modules/model_evaluation.html#scoring-parameter
代码其实很简单,两行就搞定了!!!
X = []
Y = []
Z = []
M = []
for C in range(5, 15, 1):
for gamma in range(1, 11, 1):
# 重复五次五折交叉验证
rbk = RepeatedKFold(n_splits=5, n_repeats=5, random_state=12)
accuracy = cross_val_score(svm.SVC(C=C / 10, kernel='rbf', gamma=gamma), x, y.ravel(), cv=rbk, scoring='accuracy').mean()
X.append(C / 10)
Y.append(gamma)
Z.append(accuracy)
M.append((C / 10, gamma, accuracy))
# print(M)
print(max(Z))
classifier = svm.SVC(C=0.6, kernel='rbf', gamma=1)
classifier.fit(train_data, train_label.ravel())
# 计算准确率
print("train:", classifier.score(train_data, train_label))
print("test:", classifier.score(test_data, test_label))
输出结果:
0.8057142857142857
train: 0.8380952380952381
test: 0.7777777777777778
通过此方法得到的最优参数分别为:C=1, gamma=10。
我们优化的目的是为了提高预测模型的泛化性,提高模型在测试集上的准确度。
0.78 > 0.71!!! nice~
还可以通过提高K的数值来进行模型优化,比如来个10折、20折交叉验证…
PS:多说一点
参考:https://stackoom.com/question/4QoaS
RepeatedKFold是重复KFold 。它执行n_repeats次。 当n_repeats=1 ,与KFold(n_splits = 5, shuffle = True)完全相同。当然,random_state要一样。
所以在RepeatedKFold中,数据集是默认被打乱滴~
所以前面打乱数据集的操作在用到这个函数的时候可以省略。
GridSearchCV的名字其实可以拆分为两部分,GridSearch和CV,即网格搜索和交叉验证。网格搜索,搜索的是参数,即在指定的参数范围内,按步长依次调整参数,利用调整的参数训练学习器,从所有的参数中找到在验证集上精度最高的参数,这其实是一个训练和比较的过程。k折交叉验证将所有数据集分成k份,不重复地每次取其中一份做测试集,用其余k-1份做训练集训练模型,之后计算该模型在测试集上的得分,将k次的得分取平均得到最后的得分。
GridSearchCV可以保证在指定的参数范围内找到精度最高的参数,但是这也是网格搜索的缺陷所在,他要求遍历所有可能参数的组合,在面对大数据集和多参数的情况下,非常耗时。
GridSearchCV,它存在的意义就是自动调参,只要把参数输进去,就能给出最优化结果和参数。但是这个方法适合于小数据集,一旦数据的量级上去了,很难得到结果。
C_range = []
gamma_range = []
for C in range(5, 15, 1):
C_range.append(C / 10)
for gamma in range(1, 11, 1):
gamma_range.append(gamma)
param_grid = dict(gamma=gamma_range, C=C_range)
print(param_grid)
rbk = RepeatedKFold(n_splits=5, n_repeats=5, random_state=12)
grid = GridSearchCV(svm.SVC(kernel='rbf'), param_grid=param_grid, scoring="accuracy", cv=rbk)
grid.fit(x, y.ravel())
print(
"The best parameters are %s with a score of %0.2f"
% (grid.best_params_, grid.best_score_)
)
输出结果:
{‘gamma’: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ‘C’: [0.5, 0.6, 0.7, 0.8,
0.9, 1.0, 1.1, 1.2, 1.3, 1.4]} The best parameters are {‘C’: 0.5, ‘gamma’: 1} with a score of 0.81
classifier = svm.SVC(C=0.5, kernel='rbf', gamma=1)
classifier.fit(train_data, train_label.ravel())
# 计算准确率
print("train:", classifier.score(train_data, train_label))
print("test:", classifier.score(test_data, test_label))
输出结果:
train: 0.819047619047619
test: 0.8
0.8 > 0.78
更有效果!nice~
from sklearn import svm
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.utils import shuffle
from sklearn.model_selection import RepeatedKFold
from sklearn.model_selection import GridSearchCV
# 将label与数字对应,简化数据集
def Iris_label(s):
it = {b'Iris-setosa': 0, b'Iris-versicolor': 1, b'Iris-virginica': 2}
return it[s]
# 载入数据
path = 'iris.data'
data = np.loadtxt(path, dtype=float, delimiter=',', converters={4: Iris_label})
# print(data.shape) output:(150, 5)
# print(data.dtype) output:float64
# 在第4列之后进行切割,切割成2份
# axis=1表示竖着切
x, y = np.split(data, indices_or_sections=(4,), axis=1)
x = x[:, 0:2]
x, y = shuffle(x, y, random_state=123)
# print(x, y)
# 划分训练集与测试集
# random_state相当于随机数种子,方便复现结果
train_data, test_data, train_label, test_label = train_test_split(x, y, random_state=1, train_size=0.7, test_size=0.3)
# 训练
# classifier = svm.SVC(C=1, kernel='rbf', gamma=10)
# classifier.fit(train_data, train_label.ravel())
# ravel()把标签集转换为list
# print(train_label.shape) output:(105, 1)
# print(train_label.ravel().shape) output:(105,)
# X = []
# Y = []
# Z = []
# M = []
# for C in range(5, 15, 1):
# for gamma in range(1, 11, 1):
# # 重复五次五折交叉验证
# rbk = RepeatedKFold(n_splits=5, n_repeats=5, random_state=12)
# accuracy = cross_val_score(svm.SVC(C=C / 10, kernel='rbf', gamma=gamma), train_data, train_label.ravel(),
# cv=rbk, scoring='accuracy').mean()
# X.append(C / 10)
# Y.append(gamma)
# Z.append(accuracy)
# M.append((C / 10, gamma, accuracy))
# # print(M)
# print(max(Z))
C_range = []
gamma_range = []
for C in range(5, 15, 1):
C_range.append(C / 10)
for gamma in range(1, 11, 1):
gamma_range.append(gamma)
param_grid = dict(gamma=gamma_range, C=C_range)
print(param_grid)
rbk = RepeatedKFold(n_splits=5, n_repeats=5, random_state=12)
grid = GridSearchCV(svm.SVC(kernel='rbf'), param_grid=param_grid, cv=rbk)
grid.fit(train_data, train_label.ravel())
print(
"The best parameters are %s with a score of %0.2f"
% (grid.best_params_, grid.best_score_)
)
classifier = svm.SVC(C=0.5, kernel='rbf', gamma=1)
classifier.fit(train_data, train_label.ravel())
# 计算准确率
print("train:", classifier.score(train_data, train_label))
print("test:", classifier.score(test_data, test_label))
# 法2
# tra_label = classifier.predict(train_data)
# tes_label = classifier.predict(test_data)
# print("train:", accuracy_score(train_label, tra_label))
# print("test:", accuracy_score(test_label, tes_label))
# 决策函数和预测结果
# print('train_decision_function:\n', classifier.decision_function(train_data))
# print('predict_result:\n', classifier.predict(train_data))