有没有办法在 One-Class SVM 上执行网格搜索超参数优化
Posted
技术标签:
【中文标题】有没有办法在 One-Class SVM 上执行网格搜索超参数优化【英文标题】:Is there a way to perform grid search hyper-parameter optimization on One-Class SVM 【发布时间】:2017-11-25 16:55:41 【问题描述】:有没有办法使用 GridSearchCV 或任何其他内置的 sklearn 函数来为 OneClassSVM 分类器找到最佳超参数?
我目前所做的是使用这样的训练/测试拆分自己执行搜索:
Gamma 和 nu 值定义为:
gammas = np.logspace(-9, 3, 13)
nus = np.linspace(0.01, 0.99, 99)
探索所有可能的超参数并找到最佳超参数的函数:
clf = OneClassSVM()
results = []
train_x = vectorizer.fit_transform(train_contents)
test_x = vectorizer.transform(test_contents)
for gamma in gammas:
for nu in nus:
clf.set_params(gamma=gamma, nu=nu)
clf.fit(train_x)
y_pred = clf.predict(test_x)
if 1. in y_pred: # Check if at least 1 review is predicted to be in the class
results.append(((gamma, nu), (accuracy_score(y_true, y_pred),
precision_score(y_true, y_pred),
recall_score(y_true, y_pred),
f1_score(y_true, y_pred),
roc_auc_score(y_true, y_pred),
))
)
# Determine and print the best parameter settings and their performance
print_best_parameters(results, best_parameters(results))
结果存储在表单的元组列表中:
((gamma, nu)(accuracy_score,precision_score,recall_score,f1_score, roc_auc_score))
为了找到最好的准确率,f1,roc_auc 分数和参数我写了自己的函数:
最佳参数(结果)
【问题讨论】:
你用 GridSearchCV 试过了吗?你有任何错误吗? 如何在不应用交叉验证的情况下做到这一点,因为 One-Class SVM 只需要适合属于分类器正在处理的类的数据。我所做的是:在属于该类的 80% 的实例上进行训练,然后将其余 20% 与不属于该类的实例结合起来进行测试。 如何将数据划分为训练和测试? @Yustx 您能否分享一下您是如何使用 OC-SVM 解决此问题的。我正在努力解决同样的问题,我不确定如何将您的问题与答案结合起来才能使其发挥作用。 【参考方案1】:是的,有一种方法可以在不对输入数据执行交叉验证的情况下搜索超参数。此方法称为ParameterGrid()
,存储在sklearn.model_selection
中。这是官方文档的链接:
http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.ParameterGrid.html
您的情况可能如下所示:
grid = 'gamma' : np.logspace(-9, 3, 13),
'nu' : np.linspace(0.01, 0.99, 99)
要使用 grid 声明所有可能的步骤,您可以输入 list(ParameterGrid(grid))
。我们也可以通过len(list(ParameterGrid(grid)))
来检查它的长度,它总共给出了 1287 个模型,因此有 1287 个模型适合训练数据。
要使用该方法,您必然需要一个 for 循环。暗示您有 clf 变量,因为您不适合从 sklearn.svm
导入的一类 SVM,循环将如下所示:
for z in ParameterGrid(grid):
clf.set_params(**z)
clf.fit(X_train, y_train)
clf.predict(X_test)
...
我希望这就足够了。不要忘记 grid 中的名称应该与一类 SVM 的参数一致。要获取这些参数的名称,您可以输入 clf.get_params().keys()
,然后您会看到“gamma”和“nu”。
【讨论】:
这个解决方案很好。但是话又说回来,OP 必须维护所有关于分数、拟合、参数等的信息。GridSearchCV 会自动完成。由于用户将数据划分为训练和测试,因此我们可以使用自定义 cv 迭代器来相应地拆分数据。 这对我来说也有点令人困惑。我会做和你指出的一样的事情。不过,我不确定这个 for 循环是否比基本的 GridSearchCV 更耗时,或者它们是否几乎相等。 我不能确定这个for循环,但是GridSearchCV会并行化不同参数的内部拟合,所以可能会比这个有更高的性能/ 哦,是的。肯定会更快。 它将嵌套减少一个缩进。性能似乎差不多。但是,这并不是很有用,因为我仍然必须使用自己的实现来寻找最佳超参数。【参考方案2】:我在寻找解决方案时遇到了同样的问题并发现了这个问题。我最终找到了一个使用 GridSearchCV
的解决方案,并将这个答案留给其他任何搜索并找到这个问题的人。
GridSearchCV 类的 cv
参数可以将可迭代的产生(训练、测试)拆分作为索引数组作为其输入。您可以生成仅使用训练折叠中正类中的数据以及正类中的剩余数据加上测试折叠中负类中的所有数据的拆分。
您可以使用sklearn.model_selection.KFold
进行拆分
from sklearn.model_selection import KFold
假设Xpos
是OneClassSVM
的正类数据的nXp numpy 数组,而Xneg
是已知异常示例的mXp 数据数组。
您可以首先使用为Xpos
生成拆分
splits = KFold(n_splits=5).split(Xpos)
这将构造一个(train, test)
形式的元组生成器,其中train
是一个numpy 数组,其中包含训练折叠中示例的索引,test
是一个包含测试示例索引的numpy 数组折叠。
然后,您可以使用将Xpos
和Xneg
组合成一个数据集
X = np.concatenate([Xpos, Xneg], axis=0)
OneClassSVM
将对它认为属于正类的示例进行预测 1.0
,对它认为异常的示例进行预测 -1.0
。我们可以使用
y = np.concatenate([np.repeat(1.0, len(Xpos)), np.repeat(-1.0, len(Xneg))])
然后我们可以创建一个新的(train, test)
拆分生成器,其中包含测试折叠中包含的异常示例的索引。
n, m = len(Xpos), len(Xneg)
splits = ((train, np.concatenate([test, np.arange(n, n + m)], axis=0)
for train, test in splits)
然后,您可以使用数据 X, y
以及您希望的任何评分方法和其他参数将这些拆分传递给 GridSearchCV
。
grid_search = GridSearchCV(estimator, param_grid, cv=splits, scoring=...)
编辑:我没有注意到 Vivek Kumar 在另一个答案的 cmets 中建议了这种方法,并且 OP 拒绝了它,因为他们不相信它可以与他们选择最佳参数的方法。我仍然更喜欢我所描述的方法,因为 GridSearchCV 将自动处理多处理并提供异常处理以及信息警告和错误消息。
评分方式的选择也很灵活。您可以通过将字典映射字符串传递给可调用对象来使用多种评分方法,甚至可以定义自定义 评分 callables。这在 Scikit-learn 文档here 中有描述。选择最佳参数的定制方法可能会通过自定义评分函数来实现。 OP 使用的所有指标都可以使用文档中描述的字典方法包含在内。
您可以找到真实世界的示例here。当它合并到 master 时,我会记下更改链接。
【讨论】:
@asj3 线 splits = ((train, np.concatenate([test, np.arange(n, n + m), axis=0) for train, test in splits) 是否有语法错误? @tisch 很好。缺少一个括号。现已修复 @asj3 我也不认为您可以将 X 和 y 传递给 GridSearchCV。稍后传递给 grid_Search.fit(X,y)以上是关于有没有办法在 One-Class SVM 上执行网格搜索超参数优化的主要内容,如果未能解决你的问题,请参考以下文章