我在这里问这个问题,尽管我犹豫了一下是否把它发布在CrossValidated(或DataScience) StackExchange上。我有一个包含60个标记对象(用于训练)和150个未标记对象(用于测试)的数据集。问题的目的是预测150个物体的标签(这曾经作为家庭作业问题给出)。对于每个对象,我计算了258个特征。考虑每个对象作为一个样本,我有X_train : (60,258)
, y_train : (60,)
(用于训练的对象的标签)和X_test : (150,258)
。由于作业问题的解已经给出,我也有了y_test : (150,)
中150个对象的真标签。
为了预测150个对象的标签,我选择使用LogisticRegression (Scikit-learn实现)。在数据归一化之后,分类器在(X_train, y_train)
上进行训练,并用于对150个对象进行预测。将这些预测结果与y_test
进行比较,以评估模型的性能。为了再现性,我复制了我所使用的代码。
from sklearn import metrics
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import cross_val_score, crosss_val_predict
# Fit classifier
LogReg = LogisticRegression(C=1, class_weight='balanced')
scaler = StandardScaler()
clf = make_pipeline(StandardScaler(), LogReg)
LogReg.fit(X_train, y_train)
# Performance on training data
CV_score = cross_val_score(clf, X_train, y_train, cv=10, scoring='roc_auc')
print(CV_score)
# Performance on test data
probas = LogReg.predict_proba(X_test)[:, 1]
AUC = metrics.roc_auc_score(y_test, probas)
print(AUC)
矩阵X_train
, y_train
, X_test
和y_test
保存在此链接提供的.mat文件中。我的问题如下:
使用这种方法,我在训练数据上获得了良好的性能(CV_score = 0.8),但在测试数据上的性能要差得多:loggreg中C=1的AUC = 0.54, C=0.01的AUC = 0.40。如果朴素分类器的AUC = 0.5,我怎么能得到AUC<0.5呢?这是因为我有少量的样本用于训练吗?我注意到,如果我更改
的代码,测试数据的性能会得到改善:y_pred = cross_val_predict(clf, X_test, y_test, cv=5)
AUC = metrics.roc_auc_score(y_test, y_pred)
print(AUC)
确实,当C=1时AUC=0.87,当C=0.01时AUC= 0.9。为什么使用交叉验证预测的AUC分数会好得多?是因为交叉验证允许对不包含降低AUC的对象/样本的测试数据子集进行预测吗?
看起来你遇到了一个过拟合问题,即使用训练数据训练的分类器对训练数据过拟合。泛化能力差。这就是为什么在测试数据集上的性能不是很好。
cross_val_predict
实际上是使用部分测试数据训练分类器,然后对其余部分进行预测。所以性能要好得多。
总的来说,你的训练数据集和测试数据集之间似乎有很大的不同。所以训练精度最高的分类器在你的测试集上不能很好地工作。
与你的问题没有直接关系的另一点是:由于你的训练样本的数量比特征维数要小得多,所以在输入到分类器之前进行降维可能会有所帮助。
看起来你们的培训和测试过程不一致。尽管您打算从代码中标准化您的数据,但您在测试期间未能做到这一点。我的意思:
clf = make_pipeline(StandardScaler(), LogReg)
LogReg.fit(X_train, y_train)
虽然您定义了一个管道,但您不适合管道(clf.fit
),而只适合逻辑回归。这很重要,因为您的交叉验证分数是用管道(CV_score = cross_val_score(clf, X_train, y_train, cv=10, scoring='roc_auc')
)计算的,但是在测试期间,您没有像预期的那样使用管道来预测,而是只使用LogReg
,因此测试数据不是标准化的。
你提出的第二点是不同的。在y_pred = cross_val_predict(clf, X_test, y_test, cv=5)
中,您通过对测试数据进行交叉验证来获得预测,同时忽略训练数据。在这里,你做数据标准化,因为你使用clf
,因此你的分数很高;这证明了标准化步骤的重要性。
综上所述,标准化考试数据,我相信会提高你的考试成绩。
首先,为60个训练项目提供258个功能是没有意义的。其次,60个项目的CV=10意味着你将数据分成10个训练/测试集。每个测试集中只有6个项目。所以无论你得到什么结果都是无用的。你需要更多的训练数据和更少的特征。