使用cross_val_score时持续得到0分的技术求助
咱们一步步拆解你遇到的问题,找到核心原因和修复方案:
初始代码的致命错误
你第一次用LogisticRegression完全找错了方向——这是一个分类模型,专门用来预测离散的类别标签,但你的目标变量Plant Weight(g)是连续的浮点数值,属于回归任务。用分类模型去拟合连续值,模型根本无法理解任务要求,得到0分是必然结果。
另外,你还错误地把目标变量转换成了字符串类型:
y = np.array(df.iloc[:, 0], dtype="S6")
就算是分类任务,把连续数值转成字符串会让每个样本都变成独一无二的类别,在LeaveOneOut交叉验证中,模型训练时从未见过测试样本的“类别”,自然无法预测,得分只能是0。
第二次代码的潜在问题
你换成了适合回归任务的RandomForestRegressor,但还是得到0分,可能有以下几个原因:
1. 目标变量提取不严谨
你用df.iloc[:, 0]提取目标变量,完全依赖列的顺序,但pd.get_dummies处理后列顺序可能和你预期的不一致。更稳妥的方式是直接通过列名提取,彻底避免顺序问题:
y = df["Plant Weight(g)"]
这样不管特征列怎么变化,都能精准拿到目标变量。
2. 评分指标的误解
cross_val_score对回归模型默认使用R²得分,这个指标的范围是(-∞, 1]:
- 1表示完美预测
- 0表示模型的预测效果和直接取均值一样差
- 负值表示模型预测比均值还差
如果你看到的是0分,说明模型完全没学到任何模式,和瞎猜均值一样。你可以换成更直观的回归指标,比如负均方误差(注意sklearn里回归指标大多是负值,取绝对值就是实际误差):
scores = cross_val_score(forest, X, y, cv=loo, scoring="neg_mean_squared_error") # 转换为正的均方误差 mse_scores = -scores print(mse_scores)
3. 样本量过小
从你给出的示例数据来看,样本只有8个。用LeaveOneOut交叉验证时,每个训练集只有7个样本,这么小的数据集很难让RandomForestRegressor学到有效的特征与目标的关联,模型根本无法泛化,自然预测效果极差。
修正后的完整代码
from sklearn.model_selection import LeaveOneOut from sklearn.model_selection import cross_val_score from sklearn.ensemble import RandomForestRegressor import numpy as np import pandas as pd # 读取数据 df = pd.read_csv("Flaveria.csv") # 生成虚拟变量,处理分类特征 df = pd.get_dummies(df, columns=["N level", "species"], drop_first=True) # 精准提取特征和目标变量 X = df.drop("Plant Weight(g)", axis=1) y = df["Plant Weight(g)"] # 初始化模型和交叉验证策略(设置random_state保证结果可复现) forest = RandomForestRegressor(random_state=42) loo = LeaveOneOut() # 使用MAE作为评分指标(更直观反映预测误差) scores = cross_val_score(forest, X, y, cv=loo, scoring="neg_mean_absolute_error") mae_scores = -scores print("每个样本的预测绝对误差:", mae_scores) print("平均绝对误差:", np.mean(mae_scores))
额外建议
- 如果你的数据集整体样本量都很小,考虑换用更简单的回归模型(比如线性回归),复杂模型在小数据集上容易过拟合。
- 尝试收集更多样本或挖掘更多特征,提升模型的学习能力。
内容的提问来源于stack exchange,提问作者JokkeMedKniven

