我希望能够在使用SelectKBest时,通过自己执行网格搜索简历来再现学习GridSearchCV的结果。但是,我发现我的代码可以产生不同的结果。下面是一个可重复的例子:
import numpy as np
from sklearn.datasets import make_classification
from sklearn.feature_selection import SelectKBest
from sklearn.model_selection import GridSearchCV, StratifiedKFold
from sklearn.metrics import roc_auc_score
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
import itertools
r = 1
X, y = make_classification(n_samples = 50, n_features = 20, weights = [3/5], random_state = r)
np.random.seed(r)
X = np.random.rand(X.shape[0], X.shape[1])
K = [1,3,5]
C = [0.1,1]
cv = StratifiedKFold(n_splits = 10)
space = dict()
space['anova__k'] = K
space['svc__C'] = C
clf = Pipeline([('anova', SelectKBest()), ('svc', SVC(probability = True, random_state = r))])
search = GridSearchCV(clf, space, scoring = 'roc_auc', cv = cv, refit = True, n_jobs = -1)
result = search.fit(X, y)
print('GridSearchCV results:')
print(result.cv_results_['mean_test_score'])
scores = []
for train_indx, test_indx in cv.split(X, y):
X_train, y_train = X[train_indx,:], y[train_indx]
X_test, y_test = X[test_indx,:], y[test_indx]
scores_ = []
for k, c in itertools.product(K, C):
anova = SelectKBest(k = k)
X_train_k = anova.fit_transform(X_train, y_train)
clf = SVC(C = c, probability = True, random_state = r).fit(X_train_k, y_train)
y_pred = clf.predict_proba(anova.transform(X_test))[:, 1]
scores_.append(roc_auc_score(y_test, y_pred))
scores.append(scores_)
print('Manual grid-search CV results:')
print(np.mean(np.array(scores), axis = 0)) 对我来说,这会产生以下输出:
GridSearchCV results:
[0.41666667 0.4 0.4 0.4 0.21666667 0.26666667]
Manual grid-search CV results:
[0.58333333 0.6 0.53333333 0.46666667 0.48333333 0.5 ]直接使用make_classification数据集时,输出将匹配。另一方面,当X是基于np.random.rand计算时,分数是不同的。
下面有没有我不知道的随机过程?
发布于 2021-03-15 00:16:09
编辑:重组我的答案,因为你似乎在追求更多的“为什么?”还有“我该怎么做”和“我怎么能?”
问题
在GridSearchCV中使用的记分器不会像在循环版本中那样传递predict_proba的输出。它正在传递decision_function的输出。对于支持向量机,概率的论证可能与决策不同,如这里所述
Platt所涉及的交叉验证对于大型数据集来说是一项昂贵的操作。此外,概率估计可能与分数不一致:
我会怎样修正它
在管道/GridSearchCV方法和循环中使用SVC(probability = False, ...),在循环中使用decision_function而不是predict_proba。根据上面的信息,这也将加速您的代码。
我对你问题的原原本本的回答
要使循环与GridSearchCV匹配,只需使用GridSearchCV方法:
y_pred = clf.decision_function(anova.transform(X_test)) # instead of predict_proba要使GridSearchCV与您的循环匹配,只需保留循环代码:
from sklearn.metrics import make_scorer
roc_auc_scorer = make_scorer(roc_auc_score, greater_is_better=True, needs_proba=True)
search = GridSearchCV(clf, space, scoring = roc_auc_scorer, cv = cv, refit = True, n_jobs = -1)发布于 2021-03-15 12:42:31
您的实现与GridSearchCV操作方式之间的关键区别在于
decision_function方法计算roc_auc。predict_proba。只需更改以下一行:
y_pred = clf.decision_function(anova.transform(X_test))在此之后,两种方法都会得到相同的结果。
GridSearchCV results:
[0.41666667 0.4 0.4 0.4 0.21666667 0.26666667]
Manual grid-search CV results:
[0.41666667 0.4 0.4 0.4 0.21666667 0.26666667]关于GridSearchCV 这里评分的更多解释。
这种不一致性记录在SVC的概率参数中:
概率 bool,default=False 是否启用概率估计。这必须在调用fit之前启用,因为它内部使用5倍交叉验证,并且predict_proba可能与预测不一致,因此会减慢该方法的速度。在用户指南中阅读更多内容。
这可能是为什么在使用make_classification数据集时没有区别的原因。也就是说,基于cv的5倍概率估计将与predict_proba输出类似,因为Xs是从高斯分布中提取的。而在np.random.rand()中,基于5倍的估计可能给出了完全不同的估计。
https://stackoverflow.com/questions/66499364
复制相似问题