【问题标题】:cross_val_score and StratifiedKFold give different resultcross_val_score 和 StratifiedKFold 给出不同的结果
【发布时间】:2023-03-30 10:30:01
【问题描述】:

这是StratifiedKFold 的代码,带有循环

kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=2020)
for train_idx, val_idx in kfold.split(train,labels):
  x_train,y_train=train[train_idx],labels[train_idx]
  x_val,y_val=train[val_idx],labels[val_idx]

  count_vectorizer = CountVectorizer()
  count_vectorizer.fit(x_train)
  X_train_cv = count_vectorizer.transform(x_train)
  X_val_cv  = count_vectorizer.transform(x_val)

  cv_classifier = LogisticRegression(solver='lbfgs',C=25,max_iter=500)
  cv_classifier.fit(X_train_cv, y_train)
  y_pred = cv_classifier.predict(X_val_cv)
  f1=f1_score(y_val, y_pred,average='macro')
  print(f1)

我得到的结果是

0.49
0.46
0.48
0.48
0.50

遵循cross_val_score 代码

from sklearn.model_selection import cross_val_score
cv_classifier = LogisticRegression(solver='lbfgs',C=25,max_iter=500,class_weight='balance')
count_vectorizer = CountVectorizer()
count_vectorizer.fit(train)
train_cv = count_vectorizer.transform(train)
print(cross_val_score(cv_classifier,train_cv, labels, cv=StratifiedKFold(5,shuffle = True),scoring='f1_macro'))

我得到的结果是

0.70 0.74 0.70 0.734 0.679

EIDT 我加了pipeline

cv_classifier = LogisticRegression(solver='lbfgs',C=25,max_iter=500,class_weight='balance')
classifier_pipeline = make_pipeline(CountVectorizer(), cv_classifier)

print(cross_val_score(classifier_pipeline,train, labels, cv=StratifiedKFold(5,shuffle = True),scoring='f1_macro'))

【问题讨论】:

    标签: python machine-learning scikit-learn data-science


    【解决方案1】:

    第二种情况下结果更好的原因是train_cv数据集已经被count_vectorizer拟合和转换了。

    在前一种情况下,在每个 CV 折叠中,您将矢量化器拟合到训练数据上并转换验证数据。这是正确的方法,因为向量化器在拟合期间看不到验证数据。

    为了对cross_val_score() 执行相同的操作,您应该创建一个包含矢量化器和逻辑回归模型的pipeline。然后,将此管道传递给cross_val_score(),而数据应该是初始train 数据集(不是train_cv 数据集)。

    【讨论】:

    • 我添加了管道,请查看帖子,但结果不匹配
    • 我看到在管道中,逻辑模型有class_weight='balance',而手动循环中没有指定。你也可以在这两种情况下设置相同的 random_state 吗?
    【解决方案2】:

    您还需要在cv=StratifiedKFold(5,shuffle = True) 此处设置随机种子,或者为cross_val_score 提供相同的kfold。

    我为您的工作流程创建了一个玩具示例。

    from sklearn.pipeline import make_pipeline
    from sklearn.model_selection import StratifiedKFold, cross_val_score
    from sklearn.feature_extraction.text import CountVectorizer
    from sklearn.datasets import fetch_20newsgroups
    from sklearn.metrics import f1_score
    import numpy as np
    
    categories = ['alt.atheism', 'talk.religion.misc']
    newsgroups_train = fetch_20newsgroups(subset='train',
                                          categories=categories)
    
    from sklearn.linear_model import LogisticRegression
    
    train, labels = np.array(newsgroups_train.data), newsgroups_train.target
    
    
    kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=2020)
    for train_idx, val_idx in kfold.split(train, labels):
        x_train, y_train = train[train_idx], labels[train_idx]
        x_val, y_val = train[val_idx], labels[val_idx]
    
        count_vectorizer = CountVectorizer()
        count_vectorizer.fit(x_train)
        X_train_cv = count_vectorizer.transform(x_train)
        X_val_cv = count_vectorizer.transform(x_val)
    
        cv_classifier = LogisticRegression(solver='lbfgs', C=25, max_iter=500)
        cv_classifier.fit(X_train_cv, y_train)
        y_pred = cv_classifier.predict(X_val_cv)
        f1 = f1_score(y_val, y_pred, average='macro')
        print(f1)
    
    cv_classifier = LogisticRegression(solver='lbfgs',C=25,max_iter=500,class_weight='balance') 
    classifier_pipeline = make_pipeline(CountVectorizer(), cv_classifier) 
    print(cross_val_score(classifier_pipeline,train, labels, cv=kfold,scoring='f1_macro'))
    
    

    输出:

    0.9059466848940533
    0.9527147766323024
    0.9174937965260546
    0.9336297237218165
    0.9526315789473685
    [0.90594668 0.95271478 0.9174938  0.93362972 0.95263158]
    

    【讨论】:

    • 你提供了一个很好的玩具例子。我添加了相同的 kfold,但结果不匹配。我认为手动 for loop kfold 存在问题...不是cross_val_score,因为从StratifiedKFold 获得的结果与train_test_split 不匹配
    • 令人惊讶!当您提供相同的kfold 时,结果应该完全匹配。你能提供一个可重现的例子吗?
    • 你能检查一下这个colab link
    • 您好像在cross_val_score 中添加了class_weight='balance'?
    • 我都添加了,但同样的问题,检查更新colab file
    猜你喜欢
    • 2020-06-01
    • 2018-07-20
    • 2012-07-12
    • 2021-09-25
    • 1970-01-01
    • 2011-04-03
    • 2015-08-26
    • 2021-12-25
    • 1970-01-01
    相关资源
    最近更新 更多