在 scikit-learn 中将 RandomizedSearchCV(或 GridSearcCV)与 LeaveOneGroupOut 交叉验证相结合
Posted
技术标签:
【中文标题】在 scikit-learn 中将 RandomizedSearchCV(或 GridSearcCV)与 LeaveOneGroupOut 交叉验证相结合【英文标题】:Combining RandomizedSearchCV (or GridSearcCV) with LeaveOneGroupOut cross validation in scikit-learn 【发布时间】:2017-06-07 08:52:23 【问题描述】:我喜欢结合学习曲线使用 scikit 的 LOGO(留出一组)作为交叉验证方法。这在我处理的大多数情况下都非常有效,但我只能(有效地)使用(我相信)在这些情况下(根据经验)最关键的两个参数:最大特征和估计器数量。下面是我的代码示例:
Fscorer = make_scorer(f1_score, average = 'micro')
gp = training_data["GP"].values
logo = LeaveOneGroupOut()
from sklearn.ensemble import RandomForestClassifier
RF_clf100 = RandomForestClassifier (n_estimators=100, n_jobs=-1, random_state = 49)
RF_clf200 = RandomForestClassifier (n_estimators=200, n_jobs=-1, random_state = 49)
RF_clf300 = RandomForestClassifier (n_estimators=300, n_jobs=-1, random_state = 49)
RF_clf400 = RandomForestClassifier (n_estimators=400, n_jobs=-1, random_state = 49)
RF_clf500 = RandomForestClassifier (n_estimators=500, n_jobs=-1, random_state = 49)
RF_clf600 = RandomForestClassifier (n_estimators=600, n_jobs=-1, random_state = 49)
param_name = "max_features"
param_range = param_range = [5, 10, 15, 20, 25, 30]
plt.figure()
plt.suptitle('n_estimators = 100', fontsize=14, fontweight='bold')
_, test_scores = validation_curve(RF_clf100, X, y, cv=logo.split(X, y, groups=gp),
param_name=param_name, param_range=param_range,
scoring=Fscorer, n_jobs=-1)
test_scores_mean = np.mean(test_scores, axis=1)
plt.plot(param_range, test_scores_mean)
plt.xlabel(param_name)
plt.xlim(min(param_range), max(param_range))
plt.ylabel("F1")
plt.ylim(0.47, 0.57)
plt.legend(loc="best")
plt.show()
plt.figure()
plt.suptitle('n_estimators = 200', fontsize=14, fontweight='bold')
_, test_scores = validation_curve(RF_clf200, X, y, cv=logo.split(X, y, groups=gp),
param_name=param_name, param_range=param_range,
scoring=Fscorer, n_jobs=-1)
test_scores_mean = np.mean(test_scores, axis=1)
plt.plot(param_range, test_scores_mean)
plt.xlabel(param_name)
plt.xlim(min(param_range), max(param_range))
plt.ylabel("F1")
plt.ylim(0.47, 0.57)
plt.legend(loc="best")
plt.show()
...
...
我真正想要的是将 LOGO 与网格搜索或随机搜索结合起来,以进行更彻底的参数空间搜索。
到目前为止,我的代码如下所示:
param_dist = "n_estimators": [100, 200, 300, 400, 500, 600],
"max_features": sp_randint(5, 30),
"max_depth": sp_randint(2, 18),
"criterion": ['entropy', 'gini'],
"min_samples_leaf": sp_randint(2, 17)
clf = RandomForestClassifier(random_state = 49)
n_iter_search = 45
random_search = RandomizedSearchCV(clf, param_distributions=param_dist,
n_iter=n_iter_search,
scoring=Fscorer, cv=8,
n_jobs=-1)
random_search.fit(X, y)
当我将cv = 8
替换为cv=logo.split(X, y, groups=gp)
时,我收到以下错误消息:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-0092e11ffbf4> in <module>()
---> 35 random_search.fit(X, y)
/Applications/anaconda/lib/python2.7/site-packages/sklearn/model_selection/_search.pyc in fit(self, X, y, groups)
1183 self.n_iter,
1184 random_state=self.random_state)
-> 1185 return self._fit(X, y, groups, sampled_params)
/Applications/anaconda/lib/python2.7/site-packages/sklearn/model_selection/_search.pyc in _fit(self, X, y, groups, parameter_iterable)
540
541 X, y, groups = indexable(X, y, groups)
--> 542 n_splits = cv.get_n_splits(X, y, groups)
543 if self.verbose > 0 and isinstance(parameter_iterable, Sized):
544 n_candidates = len(parameter_iterable)
/Applications/anaconda/lib/python2.7/site-packages/sklearn/model_selection/_split.pyc in get_n_splits(self, X, y, groups)
1489 Returns the number of splitting iterations in the cross-validator.
1490 """
-> 1491 return len(self.cv) # Both iterables and old-cv objects support len
1492
1493 def split(self, X=None, y=None, groups=None):
TypeError: object of type 'generator' has no len()
关于 (1) 发生了什么,更重要的是 (2) 我如何使它工作(将 RandomizedSearchCV 与 LeaveOneGroupOut 结合)有什么建议吗?
* 2017 年 2 月 8 日更新*
它使用cv=logo
和@Vivek Kumar 对random_search.fit(X, y, wells)
的建议起作用
【问题讨论】:
【参考方案1】:您不应该将logo.split()
传递给 RandomizedSearchCV,只将cv
对象(如logo
)传递给它。 RandomizedSearchCV 在内部调用split()
来生成训练测试索引。
您可以将您的gp
组传递给fit()
调用RandomizedSearchCV
或GridSearchCV
对象。
不要这样做:
random_search.fit(X, y)
这样做:
random_search.fit(X, y, gp)
编辑:你也可以在参数fit_params
中将 gp 作为字典传递给 GridSearchCV 或 RandomizedSearchCV 的构造函数。
【讨论】:
我不确定我是否理解。我在哪里经过cv.get_n_splits
?
@MyCarta 抱歉,我说的是logo.split()
,而不是cv.get_n_splits
。我编辑了我的答案以消除混乱。
@Vivek Kumar 好的,这有点清楚了。您是说没有解决方法吗?
是的。除非可以将组提供到 LOGO 的构造函数中,否则无法在 GridSearchCV 中直接使用它。还有其他可能的解决方法
@MyCarta 抱歉我的无知,但您可以将您的组传递给 gridsearchcv 或 randomsearchcv 的fit()
方法以上是关于在 scikit-learn 中将 RandomizedSearchCV(或 GridSearcCV)与 LeaveOneGroupOut 交叉验证相结合的主要内容,如果未能解决你的问题,请参考以下文章
在 scikit-learn 中将数据加载到 SVC 模型时尝试避免 .toarray()
如何在 scikit-learn 管道中将时代添加到 Keras 网络
在 scikit-learn 中将 RandomizedSearchCV(或 GridSearcCV)与 LeaveOneGroupOut 交叉验证相结合
scikit-learn:在管道中使用 SelectKBest 时获取选定的功能