在机器学习中,选择合适的超参数对于模型的性能至关重要。线性支持向量机(SVM)是一种常用的分类算法,其性能受到多个超参数的影响,如正则化强度(alpha)、L1和L2正则化的混合比例(l1_ratio)等。为了找到最优的超参数组合,可以使用随机搜索(RandomizedSearchCV)和网格搜索(GridSearchCV)两种方法。本文将比较这两种方法在搜索效率和模型性能方面的差异。
随机搜索和网格搜索都探索了相同的参数空间,但随机搜索的运行时间显著低于网格搜索。尽管随机搜索的性能可能略逊于网格搜索,但这主要是由于随机性引起的,并不一定会影响独立测试集上的性能。在实际应用中,通常不会同时使用网格搜索来搜索如此多的参数,而是选择那些被认为最重要的参数。
随机搜索在15个候选参数设置上花费了1.02秒,而网格搜索在60个候选参数设置上花费了3.59秒。随机搜索得到的最优模型的平均验证分数为0.991,而网格搜索得到的最优模型的平均验证分数为0.993。这表明,尽管随机搜索的运行时间更短,但其性能与网格搜索相当接近。
以下是使用随机搜索和网格搜索得到的最优模型的参数设置:
模型排名1:平均验证分数0.991(标准差0.006),参数设置:{'alpha': 0.05063247886572012, 'average': False, 'l1_ratio': 0.13822072286080167}。
模型排名2:平均验证分数0.987(标准差0.014),参数设置:{'alpha': 0.010877306503748912, 'average': True, 'l1_ratio': 0.9226260871125187}。
模型排名3:平均验证分数0.976(标准差0.023),参数设置:{'alpha': 0.727148206404819, 'average': False, 'l1_ratio': 0.25183501383331797}。
模型排名1:平均验证分数0.993(标准差0.011),参数设置:{'alpha': 0.1, 'average': False, 'l1_ratio': 0.1111111111111111}。
模型排名2:平均验证分数0.987(标准差0.013),参数设置:{'alpha': 0.01, 'average': False, 'l1_ratio': 0.5555555555555556}。
模型排名3:平均验证分数0.987(标准差0.007),参数设置:{'alpha': 0.01, 'average': False, 'l1_ratio': 0.0}。
为了进行这些搜索,首先从sklearn.datasets中加载了数字识别数据集,并构建了一个使用SGDClassifier的线性SVM分类器。然后,定义了一个报告函数来输出最佳分数和相应的参数设置。
from time import time
import numpy as np
import scipy.stats as stats
from sklearn.datasets import load_digits
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
# 获取数据
X, y = load_digits(return_X_y=True, n_class=3)
# 构建分类器
clf = SGDClassifier(loss="hinge", penalty="elasticnet", fit_intercept=True)
# 报告最佳分数的实用函数
def report(results, n_top=3):
for i in range(1, n_top+1):
candidates = np.flatnonzero(results["rank_test_score"] == i)
for candidate in candidates:
print("Model with rank: {0}".format(i))
print("Mean validation score: {0:.3f} (std: {1:.3f})".format(
results["mean_test_score"][candidate], results["std_test_score"][candidate]))
print("Parameters: {0}".format(results["params"][candidate]))
print("")
# 指定要采样的参数和分布
param_dist = {
"average": [True, False],
"l1_ratio": stats.uniform(0, 1),
"alpha": stats.loguniform(1e-2, 1e0),
}
# 运行随机搜索
n_iter_search = 15
random_search = RandomizedSearchCV(clf, param_distributions=param_dist, n_iter=n_iter_search)
start = time()
random_search.fit(X, y)
print("RandomizedSearchCV took %.2f seconds for %d candidates parameter settings." % ((time() - start), n_iter_search))
report(random_search.cv_results_)
# 使用所有参数的完整网格
param_grid = {
"average": [True, False],
"l1_ratio": np.linspace(0, 1, num=10),
"alpha": np.power(10, np.arange(-2, 1, dtype=float)),
}
# 运行网格搜索
grid_search = GridSearchCV(clf, param_grid=param_grid)
start = time()
grid_search.fit(X, y)
print("GridSearchCV took %.2f seconds for %d candidate parameter settings." % (time() - start, len(grid_search.cv_results_["params"])))
report(grid_search.cv_results_)