【问题标题】:How to compute correclty cross validation scores in scikit-learn?如何在 scikit-learn 中计算正确的交叉验证分数?
【发布时间】:2016-12-07 07:21:01
【问题描述】:

我正在做一个分类任务。不过,我得到的结果略有不同:

#First Approach
kf = KFold(n=len(y), n_folds=10, shuffle=True, random_state=False)
pipe= make_pipeline(SVC())
for train_index, test_index in kf:
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]

print ('Precision',np.mean(cross_val_score(pipe, X_train, y_train, scoring='precision')))



#Second Approach
clf.fit(X_train,y_train)
y_pred = clf.predict(X_test)
print ('Precision:', precision_score(y_test, y_pred,average='binary'))

#Third approach
pipe= make_pipeline(SCV())
print('Precision',np.mean(cross_val_score(pipe, X, y, cv=kf, scoring='precision')))

#Fourth approach

pipe= make_pipeline(SVC())
print('Precision',np.mean(cross_val_score(pipe, X_train, y_train, cv=kf, scoring='precision')))

输出:

Precision: 0.780422106837
Precision: 0.782051282051
Precision: 0.801544091998

/usr/local/lib/python3.5/site-packages/sklearn/cross_validation.py in cross_val_score(estimator, X, y, scoring, cv, n_jobs, verbose, fit_params, pre_dispatch)
   1431                                               train, test, verbose, None,
   1432                                               fit_params)
-> 1433                       for train, test in cv)
   1434     return np.array(scores)[:, 0]
   1435 

/usr/local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py in __call__(self, iterable)
    798             # was dispatched. In particular this covers the edge
    799             # case of Parallel used with an exhausted iterator.
--> 800             while self.dispatch_one_batch(iterator):
    801                 self._iterating = True
    802             else:

/usr/local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py in dispatch_one_batch(self, iterator)
    656                 return False
    657             else:
--> 658                 self._dispatch(tasks)
    659                 return True
    660 

/usr/local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py in _dispatch(self, batch)
    564 
    565         if self._pool is None:
--> 566             job = ImmediateComputeBatch(batch)
    567             self._jobs.append(job)
    568             self.n_dispatched_batches += 1

/usr/local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py in __init__(self, batch)
    178         # Don't delay the application, to avoid keeping the input
    179         # arguments in memory
--> 180         self.results = batch()
    181 
    182     def get(self):

/usr/local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py in __call__(self)
     70 
     71     def __call__(self):
---> 72         return [func(*args, **kwargs) for func, args, kwargs in self.items]
     73 
     74     def __len__(self):

/usr/local/lib/python3.5/site-packages/sklearn/externals/joblib/parallel.py in <listcomp>(.0)
     70 
     71     def __call__(self):
---> 72         return [func(*args, **kwargs) for func, args, kwargs in self.items]
     73 
     74     def __len__(self):

/usr/local/lib/python3.5/site-packages/sklearn/cross_validation.py in _fit_and_score(estimator, X, y, scorer, train, test, verbose, parameters, fit_params, return_train_score, return_parameters, error_score)
   1522     start_time = time.time()
   1523 
-> 1524     X_train, y_train = _safe_split(estimator, X, y, train)
   1525     X_test, y_test = _safe_split(estimator, X, y, test, train)
   1526 

/usr/local/lib/python3.5/site-packages/sklearn/cross_validation.py in _safe_split(estimator, X, y, indices, train_indices)
   1589                 X_subset = X[np.ix_(indices, train_indices)]
   1590         else:
-> 1591             X_subset = safe_indexing(X, indices)
   1592 
   1593     if y is not None:

/usr/local/lib/python3.5/site-packages/sklearn/utils/__init__.py in safe_indexing(X, indices)
    161                                    indices.dtype.kind == 'i'):
    162             # This is often substantially faster than X[indices]
--> 163             return X.take(indices, axis=0)
    164         else:
    165             return X[indices]

IndexError: index 900 is out of bounds for size 900

所以,我的问题是上述哪种方法是计算cross validated metrics 的正确方法?我认为我的分数被污染了,因为我对何时执行交叉验证感到困惑。因此,您知道如何正确执行交叉验证分数吗?

更新

在训练步骤中进行评估?

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = False)
clf = make_pipeline(SVC())
# However, fot clf, you can use whatever estimator you like
kf = StratifiedKFold(y = y_train, n_folds=10, shuffle=True, random_state=False)
scores = cross_val_score(clf, X_train, y_train, cv = kf, scoring='precision')
print('Mean score : ', np.mean(scores))
print('Score variance : ', np.var(scores))

【问题讨论】:

    标签: python python-3.x machine-learning scikit-learn


    【解决方案1】:

    对于任何分类任务,使用 StratifiedKFold 交叉验证拆分总是好的。在分层 KFold 中,对于分类问题,您从每个类别中获得相同数量的样本。

    那么这取决于您的分类问题类型。看到准确率和召回率总是好的。在偏斜二进制分类的情况下,人们倾向于使用 ROC AUC 分数:

    from sklearn import metrics
    metrics.roc_auc_score(ytest, ypred)
    

    让我们看看你的解决方案:

    import numpy as np
    from sklearn.cross_validation import cross_val_score
    from sklearn.metrics import precision_score
    from sklearn.cross_validation import KFold
    from sklearn.pipeline import make_pipeline
    from sklearn.svm import SVC
    
    np.random.seed(1337)
    
    X = np.random.rand(1000,5)
    
    y = np.random.randint(0,2,1000)
    
    kf = KFold(n=len(y), n_folds=10, shuffle=True, random_state=42)
    pipe= make_pipeline(SVC(random_state=42))
    for train_index, test_index in kf:
        X_train, X_test = X[train_index], X[test_index]
        y_train, y_test = y[train_index], y[test_index]
    
    print ('Precision',np.mean(cross_val_score(pipe, X_train, y_train, scoring='precision')))
    # Here you are evaluating precision score on X_train.
    
    #Second Approach
    clf = SVC(random_state=42)
    clf.fit(X_train,y_train)
    y_pred = clf.predict(X_test)
    print ('Precision:', precision_score(y_test, y_pred, average='binary'))
    
    # here you are evaluating precision score on X_test
    
    #Third approach
    pipe= make_pipeline(SVC())
    print('Precision',np.mean(cross_val_score(pipe, X, y, cv=kf, scoring='precision')))
    
    # Here you are splitting the data again and evaluating mean on each fold
    

    因此,结果不同

    【讨论】:

    • 感谢您的帮助,关于cross_val_score,您知道为什么我会得到不同的结果吗?计算它们的正确方法是什么?。
    • 这可能是由于随机种子。您是否尝试设置 random_state 参数,看看会发生什么?
    • 是的,我的随机我什至在开始之前就做了以下事情:np.random.seed(1337)
    • 与种子无关。这是因为每种方法都在做不同的事情 :) 但是,如果未指定种子,您最终会在每次交叉验证时得到某种微小的差异结果,并且(非常)会导致平均值略有不同交叉验证。如果它是同一个种子,那么每次运行实验时都会得到完全相同的结果——出于过度拟合的原因,我不建议这样做。
    • 谢谢,两个答案都很好,虽然我都想接受,但我会接受得票多的那个。
    【解决方案2】:

    首先,正如documentation 中的解释和一些examples 中所示,scikit-learn 交叉验证cross_val_score 执行以下操作:

    1. 将您的数据集 X 拆分为 N 个折叠(根据参数 cv)。它会相应地拆分标签y
    2. 使用估计器(参数estimator)在前 N-1 次折叠上对其进行训练。
    3. 使用估计器预测最后折叠的标签。
    4. 通过比较预测值和真实值返回分数(参数scoring
    5. 通过更改测试折叠重复步骤 2 到步骤 4。因此,您最终会得到一个包含 N 个分数的数组。

    让我们来看看你的每一种方法。

    第一种方法:

    你为什么要在 cross_validation 之前拆分训练集,因为 scikit-learn 函数会为你做这件事?因此,您可以在较少的数据上训练您的模型,并以价值验证分数结束

    第二种方法:

    在这里,您在数据上使用了除 cross_validation_sore 之外的其他指标。因此,您无法将其与其他验证分数进行比较——因为它们是两个不同的东西。一个是典型的错误百分比,而precision 是用于校准二元分类器(真或假)的指标。虽然这是一个很好的指标(您可以检查 ROC 曲线,以及精度和召回指标),但只能比较这些指标。

    第三种方法:

    这个比较自然。这个分数是 good 的(我的意思是如果你想将它与其他分类器/估计器进行比较)。但是,我会警告您不要直接取平均值。因为您可以比较两件事:均值和方差。数组的每个分数都彼此不同,您可能想知道与其他估计器相比多少(您肯定希望方差尽可能小)

    第四种方法:

    Kfold 似乎有问题,与cross_val_score 无关

    最后:

    仅使用第二种第三种方法来比较估算器。但他们绝对不会估计同一件事 - 精度与错误率。

    clf = make_pipeline(SVC())
    # However, fot clf, you can use whatever estimator you like
    scores = cross_val_score(clf, X, y, cv = 10, scoring='precision')
    print('Mean score : ', np.mean(scores))
    print('Score variance : ', np.var(scores))
    

    通过将 clf 更改为另一个估算器(或将其集成到一个循环中),您将能够为每个估算器获得一个分数并进行比较

    【讨论】:

    • 感谢您的帮助,关于第三种方法我不明白为什么我不能这样做:cross_val_score(pipe, X_train, y_train, cv=kf, scoring='precision'),我得到以下异常:IndexError: index 900 is out of bounds for size 900,为什么会这样?
    • kf 是全集,即 len(y),而你正在使用 X_train, y_train 。
    • 是的,绝对是 :) 我认为您要做的是cv = 10(而不是cv = kf)。
    • 文档声明For integer/None inputs, if y is binary or multiclass, StratifiedKFold used。所以默认情况下,如果cv = 10 并且您的数据代表类,则默认使用 StratifiedKFold。我没有得到I would like to evaluate in the testing step - 测试步骤集成在cross_val_score 中,但如果您只想进行一次拆分,请使用train_test_split,这可能不是交叉验证的好习惯
    • 您为什么要这样做?我认为cross_val_score 非常适合您尝试做的事情,以防您想比较估算器的性能。
    猜你喜欢
    • 2023-03-22
    • 1970-01-01
    • 2016-04-25
    • 2018-04-02
    • 2016-02-11
    • 2017-09-02
    • 2017-06-12
    • 2021-10-25
    • 2015-12-11
    相关资源
    最近更新 更多