在sklearn.model_selection.GridSearchCV中使用自定义验证集进行模型调参

本文链接:http://blog.youkuaiyun.com/ismarvellous/article/details/78195010

模型调参是一门玄学。为了获得模型最优参数,我们需要不断地尝试不同的参数,这一过程相当繁琐。好在python的sklearn包中为我们提供了GridSearchCV,大大方便了调参过程。本文使用实际例程简单介绍一GridSearchCV的使用,并展示如何使用自定义验证集进行模型调参。
首先解释一下什么叫使用自定义验证集进行模型调参。GridSearchCV默认使用的模型验证方法是KFold交叉验证,但很多时候我们自己已经预先分配好了验证集,我们就要在这个验证集上评价模型好坏(有些任性),所以我们并不需要GridSearchCV为我们自动产生验证集,这就是所谓的使用自定义验证集进行模型调参。好了,我们首先简单认识一下GridSearchCV的使用。

1. 问题背景

现在假设我有一个训练集,特征为数组train_features,标签为数组train_labels。我还有一个测试集,特征为数组test_features,没有标签。我希望在训练集上学习一个线性SVM,来预测测试集标签。我们知道,SVM有一些超参数需要人工设置,对于线性SVM,最关键的应该就是惩罚参数C。如何找到最优的C呢?通常情况下,我们使用KFold交叉验证。下面就简单介绍一下。

2. GridSearchCV使用简介

直接上代码:

import numpy as np
from sklearn.grid_search import GridSearchCV
from sklearn.svm import LinearSVC
from sklearn.externals import joblib

train_features = np.load('train_features.npy')
train_labels = np.load('train_labels.npy')
test_features = np.load('test_features.npy')

clf = LinearSVC(random_state=0)
params_search = {'C':[1,10,100,1000]}               # 我们想要优化的参数
grid_search_params = {'estimator': clf,             # 目标分类器
                      'param_grid': params_search,  # 前面定义的我们想要优化的参数
                      'cv': 3,                      # 交叉验证split策略
                      'n_jobs': -1,                 # 并行运行的任务数,-1表示使用所有CPU
                      'verbose': 32}                # 输出信息,数字越大输出信息越多
grsearch = GridSearchCV(**grid_search_params)
grsearch.fit(train_features, train_labels)
joblib.dump(grsearch, 'grsearch.model')

bst = grsearch.best_estimator_
preds = bst.predict(test_features)

在上面的代码中,我们使用3-fold交叉验证策略需找C的最优取值,每次的验证集从总的训练集中随机产生。

3. 使用自定义验证集

现在假设我们已经通过某种方式自己定义了训练集和验证集的划分方式,分别为train_featuresval_features,我们并不想使用随机的划分,这时候要怎么办呢?可以使用PredefinedSplit

import numpy as np
from sklearn.grid_search import GridSearchCV
from sklearn.cross_validation import PredefinedSplit
from sklearn.svm import LinearSVC
from sklearn.externals import joblib

train_features = np.load('train_features.npy')
train_labels = np.load('train_labels.npy')
val_features = np.load('val_features.npy')
val_labels = np.load('val_labels.npy')
test_features = np.load('test_features.npy')

# 合并训练集和验证集
train_val_features = np.concatenate((train_features,val_features ),axis=0)
train_val_labels = np.concatenate((train_labels,val_labels ),axis=0)

clf = LinearSVC(random_state=0)
test_fold = np.zeros(train_val_features.shape[0])   # 将所有index初始化为0,0表示第一轮的验证集
test_fold[:train_features.shape[0]] = -1            # 将训练集对应的index设为-1,表示永远不划分到验证集中
ps = PredefinedSplit(test_fold=test_fold)
params_search = {'C':[1,10,100,1000]}
grid_search_params = {'estimator': clf,             # 目标分类器
                      'param_grid': params_search,  # 前面定义的我们想要优化的参数
                      'cv': ps,                     # 使用前面自定义的split验证策略
                      'n_jobs': -1,                 # 并行运行的任务数,-1表示使用所有CPU
                      'verbose': 32}                # 输出信息,数字越大输出信息越多
print train_features.shape
print train_labels.shape
grsearch = GridSearchCV(**grid_search_params)
grsearch.fit(train_test_features, train_test_labels)

joblib.dump(grsearch, model_save_path)
bst = grsearch.best_estimator_
preds = bst.predict(test_features)

这里test_fold是一个索引list,用于划分数据集。除了上面使用的固定一个验证集,还可以划分多重验证集。加入数据集中有4个样本,那么test_fold = [0, 1, -1, 1]就表示在第一个验证集包含索引值为0的样本,第二个验证集包含引值为1的样本,以此类推,从而建立自定义的多重验证集。
这里有一段代码展示了这种划分方式:

>>> from sklearn.cross_validation import PredefinedSplit
>>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
>>> y = np.array([0, 0, 1, 1])
>>> ps = PredefinedSplit(test_fold=[0, 1, -1, 1])
>>> len(ps)
2
>>> print(ps)       
sklearn.cross_validation.PredefinedSplit(test_fold=[ 0  1 -1  1])
>>> for train_index, test_index in ps:
...    print("TRAIN:", train_index, "TEST:", test_index)
...    X_train, X_test = X[train_index], X[test_index]
...    y_train, y_test = y[train_index], y[test_index]
TRAIN: [1 2 3] TEST: [0]
TRAIN: [0 2] TEST: [1 3]

相关链接

  1. http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html#sklearn.model_selection.GridSearchCV
  2. http://scikit-learn.org/stable/modules/generated/sklearn.grid_search.GridSearchCV.html
  3. http://scikit-learn.org/stable/modules/generated/sklearn.cross_validation.PredefinedSplit.html
  4. https://stackoverflow.com/questions/31948879/using-explict-predefined-validation-set-for-grid-search-with-sklearn
import matplotlib.pyplot as plt from sklearn.datasets import fetch_lfw_people # 筛选数据,只保留图像数达到60幅的图像类别 faces = fetch_lfw_people(min_faces_per_person=60) #筛选结果包含8个类别,1348幅图像,图像大小为62x47 print(faces.target_names) print(faces.images.shape) #展示数据集前15幅图像内容 fig,ax = plt.subplots(3,5) for i, axi in enumerate(ax.flat): axi.imshow(faces.images[i],cmap = 'bone') axi.set(xticks = [],yticks = [],xlabel = faces.target_names[faces.target[i]]) plt.show() from sklearn.svm import SVC # from sklearn. decomposition import RandomizedPCA from sklearn. decomposition import PCA from sklearn. pipeline import make_pipeline #数据集将每个像素点当成一个特征,数量过多,用PCA降维后保存150个主成分特征 pca = PCA(n_components = 150, whiten = True, random_state = 42) # 构建基于径向基函数的SVM分类器 svc = SVC(kernel='rbf', class_weight ='balanced') # 构建降维建模流水线 model = make_pipeline(pca, svc) from sklearn. model_selection import train_test_split # 切分训练集和测试集数据 Xtrain, Xtest, ytrain, ytest = train_test_split(faces.data, faces.target, random_state = 40) from sklearn. model_selection import GridSearchCV # 使用 grid search cross-validation来选择最佳模型参数, #穷举测试9种C值和Y值的组合生成的分类器的性能 param_grid = {'svc__C':[1, 5, 10],'svc__gamma': [0.0001, 0.0005,0.001]} grid = GridSearchCV(model, param_grid) grid.fit(Xtrain,ytrain) #选出的最佳超参数为C=5,y=0.001 print(grid.best_params_) model = grid. best_estimator_ yfit = model.predict(Xtest) #打印出测试集大小,值为337 print(yfit.shape) fig, ax = plt.subplots(4, 6) #人脸图像类别分类结果展示,成功的用黑色表示,不成功的用红色表示 for i, axi in enumerate(ax.flat): axi.imshow(Xtest[i].reshape(62, 47), cmap='bone') axi.set(xticks=[], yticks=[]) axi.set_ylabel(faces.target_names[yfit[i]].split()[-1], color='black' if yfit[i] == ytest[i] else 'red') fig.suptitle('Predicted Names; Incorrect Labels in Red', size=14); plt.show() from sklearn. metrics import classification_report print(classification_report(ytest, yfit, target_names = faces. target_names)) from sklearn. metrics import confusion_matrix import seaborn as sns mat = confusion_matrix(ytest,yfit) sns.heatmap(mat.T, square= True, annot = True, fmt ='d', cbar = False, xticklabels = faces. target_names, yticklabels= faces.target_names) plt.xlabel('true label') plt.ylabel('predicted label') plt.show()将该代码中的人脸数据集替换为x文件夹中的人脸数据集
05-11
import matplotlib.pyplot as plt from sklearn.datasets import fetch_lfw_people # 筛选数据,只保留图像数达到60幅的图像类别 faces = fetch_lfw_people(min_faces_per_person=60) #筛选结果包含8个类别,1348幅图像,图像大小为62x47 print(faces.target_names) print(faces.images.shape) #展示数据集前15幅图像内容 fig,ax = plt.subplots(3,5) for i, axi in enumerate(ax.flat): axi.imshow(faces.images[i],cmap = 'bone') axi.set(xticks = [],yticks = [],xlabel = faces.target_names[faces.target[i]]) plt.show() from sklearn.svm import SVC # from sklearn. decomposition import RandomizedPCA from sklearn. decomposition import PCA from sklearn. pipeline import make_pipeline #数据集将每个像素点当成一个特征,数量过多,用PCA降维后保存150个主成分特征 pca = PCA(n_components = 150, whiten = True, random_state = 42) # 构建基于径向基函数的SVM分类器 svc = SVC(kernel='rbf', class_weight ='balanced') # 构建降维建模流水线 model = make_pipeline(pca, svc) from sklearn. model_selection import train_test_split # 切分训练集和测试集数据 Xtrain, Xtest, ytrain, ytest = train_test_split(faces.data, faces.target, random_state = 40) from sklearn. model_selection import GridSearchCV # 使用 grid search cross-validation来选择最佳模型参数, #穷举测试9种C值和Y值的组合生成的分类器的性能 param_grid = {'svc__C':[1, 5, 10],'svc__gamma': [0.0001, 0.0005,0.001]} grid = GridSearchCV(model, param_grid) grid.fit(Xtrain,ytrain) #选出的最佳超参数为C=5,y=0.001 print(grid.best_params_) model = grid. best_estimator_ yfit = model.predict(Xtest) #打印出测试集大小,值为337 print(yfit.shape) fig, ax = plt.subplots(4, 6) #人脸图像类别分类结果展示,成功的用黑色表示,不成功的用红色表示 for i, axi in enumerate(ax.flat): axi.imshow(Xtest[i].reshape(62, 47), cmap='bone') axi.set(xticks=[], yticks=[]) axi.set_ylabel(faces.target_names[yfit[i]].split()[-1], color='black' if yfit[i] == ytest[i] else 'red') fig.suptitle('Predicted Names; Incorrect Labels in Red', size=14); plt.show() from sklearn. metrics import classification_report print(classification_report(ytest, yfit, target_names = faces. target_names)) from sklearn. metrics import confusion_matrix import seaborn as sns mat = confusion_matrix(ytest,yfit) sns.heatmap(mat.T, square= True, annot = True, fmt ='d', cbar = False, xticklabels = faces. target_names, yticklabels= faces.target_names) plt.xlabel('true label') plt.ylabel('predicted label') plt.show()仅将代码中获取的数据集改变为x文件夹中的数据集,其余不做改变,请给出改写后的完整代码
05-11
import matplotlib.pyplot as plt from sklearn.datasets import fetch_lfw_people # 筛选数据,只保留图像数达到60幅的图像类别 faces = fetch_lfw_people(min_faces_per_person=60) #筛选结果包含8个类别,1348幅图像,图像大小为62x47 print(faces.target_names) print(faces.images.shape) #展示数据集前15幅图像内容 fig,ax = plt.subplots(3,5) for i, axi in enumerate(ax.flat): axi.imshow(faces.images[i],cmap = 'bone') axi.set(xticks = [],yticks = [],xlabel = faces.target_names[faces.target[i]]) plt.show() from sklearn.svm import SVC # from sklearn. decomposition import RandomizedPCA from sklearn. decomposition import PCA from sklearn. pipeline import make_pipeline #数据集将每个像素点当成一个特征,数量过多,用PCA降维后保存150个主成分特征 pca = PCA(n_components = 150, whiten = True, random_state = 42) # 构建基于径向基函数的SVM分类器 svc = SVC(kernel='rbf', class_weight ='balanced') # 构建降维建模流水线 model = make_pipeline(pca, svc) from sklearn. model_selection import train_test_split # 切分训练集和测试集数据 Xtrain, Xtest, ytrain, ytest = train_test_split(faces.data, faces.target, random_state = 40) from sklearn. model_selection import GridSearchCV # 使用 grid search cross-validation来选择最佳模型参数, #穷举测试9种C值和Y值的组合生成的分类器的性能 param_grid = {'svc__C':[1, 5, 10],'svc__gamma': [0.0001, 0.0005,0.001]} grid = GridSearchCV(model, param_grid) grid.fit(Xtrain,ytrain) #选出的最佳超参数为C=5,y=0.001 print(grid.best_params_) model = grid. best_estimator_ yfit = model.predict(Xtest) #打印出测试集大小,值为337 print(yfit.shape) fig, ax = plt.subplots(4, 6) #人脸图像类别分类结果展示,成功的用黑色表示,不成功的用红色表示 for i, axi in enumerate(ax.flat): axi.imshow(Xtest[i].reshape(62, 47), cmap='bone') axi.set(xticks=[], yticks=[]) axi.set_ylabel(faces.target_names[yfit[i]].split()[-1], color='black' if yfit[i] == ytest[i] else 'red') fig.suptitle('Predicted Names; Incorrect Labels in Red', size=14); plt.show() from sklearn. metrics import classification_report print(classification_report(ytest, yfit, target_names = faces. target_names)) from sklearn. metrics import confusion_matrix import seaborn as sns mat = confusion_matrix(ytest,yfit) sns.heatmap(mat.T, square= True, annot = True, fmt ='d', cbar = False, xticklabels = faces. target_names, yticklabels= faces.target_names) plt.xlabel('true label') plt.ylabel('predicted label') plt.show()仅将代码中获取的数据库替换为x文件夹中的数据库,其余部分不做改变
05-11
对该界面的主题、按钮和布局进行美化: import tkinter as tk from tkinter import filedialog, messagebox import pandas as pd from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.naive_bayes import GaussianNB from sklearn.tree import DecisionTreeClassifier, plot_tree from sklearn.metrics import classification_report, confusion_matrix import seaborn as sns import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus'] = False class DiabetesApp: def __init__(self, root): self.root = root self.root.title("糖尿病智能辅助诊断系统") self.root.geometry("800x600") self.df = None self.model_nb = None self.model_tree = None # 界面控件 self.label = tk.Label(root, text="请选择CSV数据文件:") self.label.pack(pady=5) self.upload_btn = tk.Button(root, text="上传CSV", command=self.load_data) self.upload_btn.pack(pady=5) self.nb_btn = tk.Button(root, text="训练朴素贝叶斯模型", command=self.train_nb) self.nb_btn.pack(pady=5) self.tree_btn = tk.Button(root, text="训练决策树模型(含调参)", command=self.train_tree) self.tree_btn.pack(pady=5) self.report_text = tk.Text(root, height=25, width=100) self.report_text.pack(pady=10) def load_data(self): """加载CSV文件""" file_path = filedialog.askopenfilename(filetypes=[("CSV Files", "*.csv")]) if not file_path: return try: self.df = pd.read_csv(file_path) except Exception as e: messagebox.showerror("错误", f"读取失败:{e}") return if '诊断结果' not in self.df.columns: messagebox.showerror("错误", "数据中缺少“诊断结果”列!") return messagebox.showinfo("成功", f"数据加载成功,共 {self.df.shape[0]} 条记录,{self.df.shape[1]} 个字段") def preprocess(self): """数据预处理""" data = self.df.copy() data = data.select_dtypes(include='number') # 仅保留数值型 data = data.dropna()#删除缺失值 X = data.drop(columns=['诊断结果']) y = data['诊断结果'] return train_test_split(X, y, test_size=0.2, random_state=42) def train_nb(self): """训练朴素贝叶斯模型""" if self.df is None: messagebox.showerror("错误", "请先上传数据!") return X_train, X_test, y_train, y_test = self.preprocess() self.model_nb = GaussianNB() self.model_nb.fit(X_train, y_train) y_pred = self.model_nb.predict(X_test) report = classification_report(y_test, y_pred) matrix = confusion_matrix(y_test, y_pred) self.display_results("朴素贝叶斯分类结果", report, matrix) def train_tree(self): """训练决策树模型使用网格搜索调参""" if self.df is None: messagebox.showerror("错误", "请先上传数据!") return X_train, X_test, y_train, y_test = self.preprocess() param_grid = {'max_depth': [3, 5, 7, 9, None]} grid = GridSearchCV(DecisionTreeClassifier(random_state=42), param_grid, cv=3) grid.fit(X_train, y_train) self.model_tree = grid.best_estimator_ y_pred = self.model_tree.predict(X_test) report = classification_report(y_test, y_pred) matrix = confusion_matrix(y_test, y_pred) self.display_results("决策树分类结果 (最优深度: {})".format(grid.best_params_['max_depth']), report, matrix) self.plot_tree_structure() def display_results(self, title, report, matrix): """在文本框中展示分类报告,并显示混淆矩阵图""" self.report_text.delete('1.0', tk.END) self.report_text.insert(tk.END, f"{title}\n") self.report_text.insert(tk.END, f"{report}\n") plt.figure(figsize=(4, 3)) sns.heatmap(matrix, annot=True, fmt='d', cmap='Blues') plt.title(f"{title} - 混淆矩阵") plt.xlabel("预测") plt.ylabel("实际") plt.tight_layout() plt.show() def plot_tree_structure(self): """绘制决策树结构图""" plt.figure(figsize=(12, 6)) plot_tree(self.model_tree, filled=True, feature_names=self.model_tree.feature_names_in_) plt.title("决策树结构图") plt.tight_layout() plt.show() if __name__ == "__main__": root = tk.Tk() app = DiabetesApp(root) root.mainloop()
05-28
<think>好的,我现在需要帮助用户解决如何使用Pythonsklearn库通过支持向量机(SVM)对鸢尾花数据集进行分类并绘制决策边界的问题。首先,我应该回忆一下SVM的基本原理和sklearn中的相关模块。用户提到了数据集是鸢尾花,所以需要先加载数据,可能使用load_iris函数。引用中的内容显示,用户提供的引用[1]、[2]、[3]都涉及到了SVM在鸢尾花数据集上的应用,这可能对回答有帮助。 接下来,我应该考虑数据预处理的步骤。通常,加载数据后需要划分训练集和测试集,使用train_test_split函数。引用[1]中的代码展示了如何导入数据并划分数据集,所以我可以参考这部分内容。然后,训练SVM模型,可能需要调整参数如C、kernel类型等。引用[3]提到了使用SVC类,并设置了kernel为'rbf',gamma为'auto',这些参数可以作为示例。用户可能需要知道如何选择不同的核函数以及参数的影响。 关于可视化部分,绘制决策边界需要用到一些库如matplotlib和mlxtend中的plot_decision_regions函数。引用[3]中的代码使用了这个函数来展示分类结果,所以需要指导用户安装mlxtend库,并正确调用该函数。但需要注意,如果数据是多维的(如四个特征),直接可视化可能需要降维处理。用户的问题中提到的是“绘制决策边界”,通常决策边界是在二维空间中展示的,所以可能需要选择两个主要特征进行可视化,或者使用PCA降维到两个主成分。 此外,用户可能对模型评估感兴趣,比如准确率、混淆矩阵等。在引用[2]中提到了使用交叉验证来选择参数C,但用户的问题主要关注实现和可视化,所以这部分可以作为补充,但可能不需要详细展开。 步骤总结应该是:加载数据、数据预处理(划分训练测试集、标准化)、训练模型、评估模型、可视化决策边界。需要确保代码示例正确,特别是可视化部分可能需要处理多维数据的问题。比如,在鸢尾花数据集中有四个特征,而可视化通常只能显示两个特征,所以可能需要选择两个特征或者使用PCA。引用[3]中的示例使用自定义数据,可能进行了特征选择,但用户可能需要处理原始数据,所以需要调整代码。 最后,生成相关问题时要围绕SVM的实现、参数调整、可视化方法、数据集特点等方面提问,帮助用户进一步探索。</think>以下是使用Pythonsklearn库实现SVM分类器并对鸢尾花数据集进行可视化决策边界的详细步骤: --- ### **步骤1:导入库和加载数据** ```python from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC import pandas as pd import matplotlib.pyplot as plt from mlxtend.plotting import plot_decision_regions # 需要安装mlxtend库 ``` 加载鸢尾花数据集(自动包含在sklearn中): ```python X, y = load_iris(return_X_y=True, as_frame=True) ``` --- ### **步骤2:数据预处理** 1. **划分数据集** ```python X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) ``` 2. **标准化数据**(SVM对特征尺度敏感) ```python scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test) ``` --- ### **步骤3:训练SVM模型** 选择高斯核(RBF kernel)并训练: ```python svm = SVC(kernel='rbf', C=1.0, gamma='scale') svm.fit(X_train, y_train) ``` --- ### **步骤4:模型评估** 计算测试集准确率: ```python accuracy = svm.score(X_test, y_test) print(f"测试集准确率:{accuracy:.2f}") # 示例输出:测试集准确率:0.97 ``` --- ### **步骤5:可视化决策边界** 由于鸢尾花数据集有4个特征,需选择两个特征进行降维可视化: ```python # 选择前两个特征(萼片长度和宽度) X_2d = X_train[:, :2] svm_2d = SVC(kernel='rbf', C=1.0, gamma='scale') svm_2d.fit(X_2d, y_train) # 绘制决策边界 plt.figure(figsize=(8, 6)) plot_decision_regions(X_2d, y_train.values, clf=svm_2d, legend=2) plt.xlabel("萼片长度(标准化)") plt.ylabel("萼片宽度(标准化)") plt.title("SVM决策边界(基于前两个特征)") plt.show() ``` --- ### **关键参数说明** - `kernel`:核函数类型,可选`linear`、`poly`、`rbf`等[^3] - `C`:正则化参数,控制分类器的容错能力[^2] - `gamma`:RBF核的带宽参数,值越大模型越复杂 --- ### **扩展优化方法** 1. **使用PCA降维** 若需保留更多原始信息,可对4维数据降维至2维: ```python from sklearn.decomposition import PCA pca = PCA(n_components=2) X_pca = pca.fit_transform(X_train) svm_pca = SVC(kernel='rbf').fit(X_pca, y_train) plot_decision_regions(X_pca, y_train.values, clf=svm_pca) ``` 2. **网格搜索调参** 通过交叉验证优化`C`和`gamma`参数: ```python from sklearn.model_selection import GridSearchCV params = {'C': [0.1, 1, 10], 'gamma': [0.1, 1, 'scale']} grid = GridSearchCV(SVC(), params, cv=5) grid.fit(X_train, y_train) ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值