基于K折交叉验证计算Accuracy、Precision等指标的代码正确性疑问
K折交叉验证中指标计算的准确性验证与代码优化
你的代码存在的两个核心问题
- 拆分方式错误:用
train_test_split循环拆分数据不是标准K折交叉验证——每次拆分都是随机从全量数据中抽取测试集,会导致不同折的测试集甚至训练集重叠,不符合K折“数据互不重叠、全覆盖”的要求,得到的指标平均值没有统计意义。 - 指标函数参数顺序错误:sklearn的指标函数(如
accuracy_score)要求第一个参数是真实标签,第二个是预测标签,你写的accuracy_score(x_test_prediction, y_test)把顺序搞反了,会导致计算结果完全错误。
关于“求和除以折数”的合理性
如果是正确的K折拆分(将数据分成K个互不重叠的子集,每折用其中一个做测试集,其余做训练集),对每折的Accuracy、Precision等指标取平均是K折交叉验证中常用且合理的指标汇总方式。但前提是拆分和指标计算的逻辑都正确。
正确的代码实现
分类任务优先使用StratifiedKFold,它能保证每折的类别分布与原数据一致,避免因拆分导致的类别失衡。以下是修正后的代码:
from sklearn.model_selection import StratifiedKFold from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score # 初始化分层K折,shuffle=True打乱数据,random_state保证结果可复现 skf = StratifiedKFold(n_splits=n_folds, shuffle=True, random_state=42) total_acc = 0 total_prec = 0 total_recall = 0 total_f1 = 0 # 标准K折拆分:每折测试集互不重叠,全覆盖 for train_idx, test_idx in skf.split(X, y): X_train, X_test = X[train_idx], X[test_idx] y_train, y_test = y[train_idx], y[test_idx] clf.fit(X_train, y_train) y_pred = clf.predict(X_test) # 修正参数顺序:真实标签在前,预测标签在后 total_acc += accuracy_score(y_test, y_pred) total_prec += precision_score(y_test, y_pred) total_recall += recall_score(y_test, y_pred) total_f1 += f1_score(y_test, y_pred) # 计算平均指标 avg_acc = total_acc / n_folds avg_prec = total_prec / n_folds avg_recall = total_recall / n_folds avg_f1 = total_f1 / n_folds print(f"accuracy score : {avg_acc:.4f}") print(f"precision score : {avg_prec:.4f}") print(f"recall score : {avg_recall:.4f}") print(f"f1 score : {avg_f1:.4f}")
如何验证计算的准确性
你可以通过以下三种方式验证结果的正确性:
与sklearn内置工具对比:用
cross_validate直接计算指标,对比手动计算的平均值是否一致:from sklearn.model_selection import cross_validate # 根据任务选择合适的评分指标,二分类用'precision',多分类用'precision_macro' scoring = ['accuracy', 'precision', 'recall', 'f1'] results = cross_validate(clf, X, y, cv=skf, scoring=scoring) print("cross_validate 平均准确率:", results['test_accuracy'].mean()) print("cross_validate 平均精确率:", results['test_precision'].mean())两者结果应基本一致(误差来自浮点数精度)。
两种指标汇总方式对比:除了平均每折指标,还可以收集所有折的真实标签和预测标签,整体计算指标,对比两种方式的差异:
all_y_true = [] all_y_pred = [] for train_idx, test_idx in skf.split(X, y): X_train, X_test = X[train_idx], X[test_idx] y_train, y_test = y[train_idx], y[test_idx] clf.fit(X_train, y_train) y_pred = clf.predict(X_test) all_y_true.extend(y_test) all_y_pred.extend(y_pred) print("整体计算准确率:", accuracy_score(all_y_true, all_y_pred)) print("整体计算精确率:", precision_score(all_y_true, all_y_pred))两种方式结果可能略有差异:“平均折指标”是先每折计算再平均,“整体计算”是合并所有结果后计算,两种都是合理的,按需选择即可。
小数据集手动验证:用一个极小的已知标签数据集(比如10个样本,5正5负),手动拆分K折(如K=2),手动计算每折指标再平均,和代码运行结果对比,看是否完全一致。
内容的提问来源于stack exchange,提问作者AL MAHMUD SIAM
相关产品推荐
相关产品推荐

