在Scikit-learn中绘制类别权重验证曲线报错求助
解决Scikit-learn中class_weight验证曲线绘图的TypeError问题
嘿,我一眼就看出问题所在了——你用validation_curve计算分数的部分是对的,但绘图的时候直接把字典列表传给了Matplotlib,而它根本不知道怎么把字典转换成坐标轴上的数值,所以才会抛出float() argument must be a string or a number, not 'dict'这个错误。
错误根源
param_range2是一个包含class_weight字典的列表(比如[{0:1,1:6}, ...]),validation_curve能识别这种格式来给模型传参,但plt.plot()需要的是数值型的x轴数据,字典显然不符合要求。
解决方案
我们只需要把每个class_weight字典里的少数类权重值提取出来(也就是你设置的1: w里的w),用这个数值列表作为x轴的输入就行。具体修改分两步:
- 从字典列表中提取数值,作为绘图的x轴标签
- 保持
validation_curve的param_range不变(因为模型需要字典格式的class_weight参数)
修改后的完整代码
from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split, StratifiedKFold, validation_curve, GridSearchCV from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.pipeline import Pipeline import numpy as np import matplotlib.pyplot as plt def plot_validation_curve(param_range, train_scores, test_scores, title, alpha=0.1): train_mean = np.mean(train_scores, axis=1) train_std = np.std(train_scores, axis=1) test_mean = np.mean(test_scores, axis=1) test_std = np.std(test_scores, axis=1) plt.plot(param_range, train_mean, label='train score', color='blue', marker='o') plt.fill_between(param_range, train_mean + train_std, train_mean - train_std, color='blue', alpha=alpha) plt.plot(param_range, test_mean, label='test score', color='red', marker='o') plt.fill_between(param_range, test_mean + test_std, test_mean - test_std, color='red', alpha=alpha) plt.title(title) plt.grid(ls='--') plt.xlabel('Minority Class Weight') # 优化x轴标签,让图表更易读 plt.ylabel('F-measure') plt.legend(loc='best') plt.show() if __name__ == '__main__': X, y = make_classification(n_classes=2, class_sep=2, weights=[0.9, 0.1], n_informative=3, n_redundant=1, flip_y=0, n_features=20, n_clusters_per_class=1, n_samples=1000, random_state=10) X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0) st = StandardScaler() rg = LogisticRegression(class_weight={0: 1, 1: 6.5}, random_state=42, solver='saga', max_iter=100, n_jobs=-1) param_grid = {'clf__C': [0.001, 0.01, 0.1], 'clf__class_weight': [{0: 1, 1: 6}, {0: 1, 1: 5.5}]} pipeline = Pipeline(steps=[('scaler', st), ('clf', rg)]) cv = StratifiedKFold(n_splits=5, random_state=42, shuffle=True) # 加上shuffle让交叉验证划分更随机 rg_cv = GridSearchCV(pipeline, param_grid, cv=cv, scoring='f1') rg_cv.fit(X_train, y_train) plt.figure(figsize=(9, 6)) param_range2 = [{0: 1, 1: 6}, {0: 1, 1: 4}, {0: 1, 1: 5.5}] # 从每个字典中提取少数类(类别1)的权重值,作为x轴的数值 param_values = [weight_dict[1] for weight_dict in param_range2] train_scores, test_scores = validation_curve( estimator=rg_cv.best_estimator_, X=X_train, y=y_train, param_name="clf__class_weight", param_range=param_range2, # 这里依然用字典列表,模型需要这个格式 cv=cv, scoring="f1", n_jobs=-1 ) # 传入提取后的数值列表绘图 plot_validation_curve(param_values, train_scores, test_scores, title="Validation Curve for Minority Class Weight", alpha=0.1)
额外优化点
- 给
StratifiedKFold加上了shuffle=True,让交叉验证的划分更随机,结果更可靠 - 修改了x轴标签为
Minority Class Weight,让图表的含义更清晰
这样修改后,代码就能正常运行,你也能直观看到少数类权重变化时模型F1分数的波动情况啦!
内容的提问来源于stack exchange,提问作者ebrahimi
相关产品推荐
相关产品推荐

