4.4 sklearn实战:鸢尾花分类与房价预测

发布时间:2026/6/3 20:20:03

4.4 sklearn实战:鸢尾花分类与房价预测 sklearn实战鸢尾花分类与房价预测两个完整项目从数据加载到模型保存把前面学过的所有概念串联起来。1.1 项目1鸢尾花分类多分类sklearn 机器学习完整工作流——从数据加载到模型部署的六个步骤这是机器学习的Hello World但我们做得比Hello World更完整数据探索、多模型对比、混淆矩阵可视化、模型保存——这是真实项目的完整工作流。1.1.1 这段代码在做什么目标在鸢尾花数据集150个样本4个特征3个品种上比较4种分类算法的效果选出最好的保存模型并用它预测新样本。1.1.2 步骤1数据探索在建模之前先了解数据的基本情况有多少样本、特征是什么、各类别分布是否均衡。importnumpyasnpimportpandasaspdimportmatplotlib.pyplotaspltimportseabornassnsfromsklearn.datasetsimportload_irisfromsklearn.model_selectionimporttrain_test_split,cross_val_scorefromsklearn.preprocessingimportStandardScalerfromsklearn.pipelineimportPipelinefromsklearn.ensembleimportRandomForestClassifier,GradientBoostingClassifierfromsklearn.linear_modelimportLogisticRegressionfromsklearn.svmimportSVCfromsklearn.metricsimportclassification_report,confusion_matrix# 加载数据# iris.data: 形状(150, 4)4个特征# iris.target: 形状(150,)0/1/2代表三个品种irisload_iris()dfpd.DataFrame(iris.data,columnsiris.feature_names)df[species]pd.Categorical.from_codes(iris.target,iris.target_names)print(数据形状:,df.shape)# (150, 5)print(\n前5行:)print(df.head())print(\n统计信息:)print(df.describe())print(\n类别分布:)print(df[species].value_counts())# 每种品种各50个完全均衡你应该看到数据集有150个样本、5列4个特征1个标签三种品种各50个类别完全均衡特征包括花萼长度/宽度、花瓣长度/宽度1.1.3 步骤2多模型对比这段代码在做什么同时训练4种模型用5折交叉验证比较它们的准确率选出最好的。# 划分训练集和测试集Xiris.data yiris.target X_train,X_test,y_train,y_testtrain_test_split(X,y,test_size0.2,random_state42,stratifyy# 按类别比例分层抽样保证训练/测试集中各类别比例一致)# 定义4种模型# Pipeline把数据预处理和模型训练串联成一个整体防止数据泄露models{逻辑回归:Pipeline([(scaler,StandardScaler()),# 标准化统一特征的数值范围(clf,LogisticRegression(max_iter1000))]),随机森林:RandomForestClassifier(n_estimators100,random_state42),SVM:Pipeline([(scaler,StandardScaler()),(clf,SVC(kernelrbf,probabilityTrue))]),梯度提升:GradientBoostingClassifier(n_estimators100,random_state42)}# 5折交叉验证比较所有模型results{}print(5折交叉验证结果:)forname,modelinmodels.items():cv_scorescross_val_score(model,X_train,y_train,cv5)results[name]cv_scoresprint(f{name}:{cv_scores.mean():.4f}±{cv_scores.std():.4f})你应该看到类似这样的输出5折交叉验证结果: 逻辑回归: 0.9583 ± 0.0304 随机森林: 0.9583 ± 0.0304 SVM: 0.9750 ± 0.0190 梯度提升: 0.9500 ± 0.0354所有模型准确率都在95%以上说明这是个相对容易的数据集。SVM在这里表现最好。1.1.4 步骤3最佳模型评估这段代码在做什么用随机森林通常最稳定在测试集上做最终评估并画出混淆矩阵。# 用随机森林做最终评估best_modelmodels[随机森林]best_model.fit(X_train,y_train)y_predbest_model.predict(X_test)print(\n 最终评估测试集)print(classification_report(y_test,y_pred,target_namesiris.target_names))# 混淆矩阵行是真实类别列是预测类别对角线是预测正确的数量cmconfusion_matrix(y_test,y_pred)plt.figure(figsize(8,6))sns.heatmap(cm,annotTrue,fmtd,xticklabelsiris.target_names,yticklabelsiris.target_names,cmapBlues)plt.title(混淆矩阵)plt.ylabel(真实标签)plt.xlabel(预测标签)plt.show()你应该看到精确率、召回率、F1分数都在95%以上混淆矩阵的对角线值较大预测正确的样本多非对角线值很小预测错误的样本少1.1.5 步骤4保存和加载模型这段代码在做什么把训练好的模型保存到文件然后加载回来预测一个新样本。importjoblib# 保存模型到文件joblib.dump(best_model,iris_classifier.pkl)print(模型已保存到 iris_classifier.pkl)# 加载并预测一个新样本loaded_modeljoblib.load(iris_classifier.pkl)sample[[5.1,3.5,1.4,0.2]]# 一个新样本的4个特征predictionloaded_model.predict(sample)prediction_probaloaded_model.predict_proba(sample)print(f\n新样本特征:{sample[0]})print(f预测品种:{iris.target_names[prediction[0]]})# 应该是 setosaprint(f预测概率:{dict(zip(iris.target_names,prediction_proba[0].round(3)))})你应该看到模型已保存到 iris_classifier.pkl 新样本特征: [5.1, 3.5, 1.4, 0.2] 预测品种: setosa 预测概率: {setosa: 1.0, versicolor: 0.0, virginica: 0.0}这个样本的花瓣很小1.4和0.2是setosa的典型特征模型以100%的置信度预测正确。1.2 项目2房价预测回归这个项目更贴近真实业务处理缺失值、特征工程、多模型对比、误差分析。1.2.1 这段代码在做什么目标在加州房价数据集上预测房价比较线性模型和集成学习的效果并分析哪些因素最影响房价。1.2.2 步骤1加载数据importnumpyasnpimportpandasaspdfromsklearn.datasetsimportfetch_california_housingfromsklearn.model_selectionimporttrain_test_splitfromsklearn.preprocessingimportStandardScalerfromsklearn.pipelineimportPipelinefromsklearn.ensembleimportRandomForestRegressor,GradientBoostingRegressorfromsklearn.linear_modelimportLinearRegression,Ridgefromsklearn.metricsimportmean_squared_error,r2_score,mean_absolute_errorimportmatplotlib.pyplotasplt# 加载加州房价数据集housingfetch_california_housing()dfpd.DataFrame(housing.data,columnshousing.feature_names)df[MedHouseVal]housing.target# 目标房价10万美元为单位print(数据形状:,df.shape)# (20640, 9)print(\n特征说明:)feature_desc{MedInc:收入中位数,HouseAge:房屋年龄中位数,AveRooms:平均房间数,AveBedrms:平均卧室数,Population:人口,AveOccup:平均入住率,Latitude:纬度,Longitude:经度}forname,descinfeature_desc.items():print(f{name}:{desc})你应该看到数据集有20640个样本8个特征。收入中位数通常是预测房价最重要的特征。1.2.3 步骤2特征工程从原始特征中构造更有意义的特征# 特征工程构造新特征# 理由rooms_per_household更有意义——平均每户有多少间房df[rooms_per_household]df[AveRooms]/df[AveOccup]df[bedrooms_ratio]df[AveBedrms]/df[AveRooms]# 卧室比例df[population_per_household]df[Population]/df[AveOccup]# 每户人口feature_colshousing.feature_names.tolist()[rooms_per_household,bedrooms_ratio,population_per_household]Xdf[feature_cols].values ydf[MedHouseVal].values X_train,X_test,y_train,y_testtrain_test_split(X,y,test_size0.2,random_state42)print(f训练集:{X_train.shape[0]}样本)print(f测试集:{X_test.shape[0]}样本)print(f特征数:{X_train.shape[1]})你应该看到训练集16512个样本测试集4128个样本11个特征8个原始 3个新增。1.2.4 步骤3模型训练与对比这段代码在做什么训练4种模型比较它们在测试集上的RMSE均方根误差、MAE平均绝对误差和R²分数。# 定义4种模型models{线性回归:Pipeline([(scaler,StandardScaler()),(reg,LinearRegression())]),Ridge回归:Pipeline([(scaler,StandardScaler()),(reg,Ridge(alpha1.0))# alpha正则化强度防止过拟合]),随机森林:RandomForestRegressor(n_estimators100,random_state42,n_jobs-1),梯度提升:GradientBoostingRegressor(n_estimators100,learning_rate0.1,random_state42)}print(模型对比测试集:)print(f{模型:15}{RMSE:12}{MAE:12}{R²:10})print(-*50)forname,modelinmodels.items():model.fit(X_train,y_train)y_predmodel.predict(X_test)# RMSE均方根误差单位和目标变量一致10万美元rmsenp.sqrt(mean_squared_error(y_test,y_pred))# MAE平均绝对误差更直观平均误差多少10万美元maemean_absolute_error(y_test,y_pred)# R²越接近1越好模型解释了多少数据变化r2r2_score(y_test,y_pred)print(f{name:15}{rmse:12.4f}{mae:12.4f}{r2:10.4f})你应该看到类似这样的输出模型对比测试集: 模型 RMSE MAE R² -------------------------------------------------- 线性回归 0.7268 0.5275 0.5758 Ridge回归 0.7268 0.5275 0.5759 随机森林 0.5079 0.3324 0.7783 梯度提升 0.4588 0.2995 0.8179梯度提升的RMSE最小约0.46即平均误差约4.6万美元、R²最高0.82说明它在这个数据集上效果最好。线性模型R²只有0.58说明房价和特征之间不是简单的线性关系。1.2.5 步骤4误差分析这段代码在做什么可视化最佳模型的预测效果和误差分布帮助理解模型在哪些区间预测得准、在哪些区间不准。# 使用最佳模型梯度提升做深入分析best_modelmodels[梯度提升]y_predbest_model.predict(X_test)# 预测值 vs 真实值理想情况下所有点在对角线上plt.figure(figsize(10,4))plt.subplot(1,2,1)plt.scatter(y_test,y_pred,alpha0.3)plt.plot([y_test.min(),y_test.max()],[y_test.min(),y_test.max()],r--,lw2,label理想预测)plt.xlabel(真实房价10万美元)plt.ylabel(预测房价10万美元)plt.title(预测 vs 真实)plt.legend()# 残差分布好的模型残差应接近正态分布且均值为0plt.subplot(1,2,2)residualsy_test-y_pred plt.hist(residuals,bins50)plt.xlabel(残差真实值-预测值)plt.ylabel(频次)plt.title(残差分布越接近正态越好)plt.tight_layout()plt.show()print(f\n残差统计:)print(f均值:{residuals.mean():.4f}接近0说明模型无系统性偏差)print(f标准差:{residuals.std():.4f})你应该看到预测 vs 真实图大部分点分布在对角线附近但高价房区域4的区域预测偏差较大残差分布接近正态分布均值接近0说明模型无系统性偏差1.3 Pipeline工业级代码的标配在实际项目中数据往往有缺失值、混合类型特征等Pipeline让你的代码更健壮、更不容易出错这段代码在做什么展示如何用Pipeline处理同时含有数值和类别特征的真实数据这是工业级ML代码的标准写法。fromsklearn.pipelineimportPipelinefromsklearn.composeimportColumnTransformerfromsklearn.preprocessingimportStandardScaler,OneHotEncoderfromsklearn.imputeimportSimpleImputer# 真实场景数据有缺失值、有数值和类别特征numeric_features[age,income,score]categorical_features[city,education]# 数值特征处理填充缺失值 标准化numeric_transformerPipeline([(imputer,SimpleImputer(strategymedian)),# 用中位数填充缺失值(scaler,StandardScaler())])# 类别特征处理填充缺失值 One-Hot编码# One-Hot编码把北京/上海/广州这样的类别变成0/1的数字表示categorical_transformerPipeline([(imputer,SimpleImputer(strategymost_frequent)),(encoder,OneHotEncoder(handle_unknownignore))])# 组合处理器preprocessorColumnTransformer([(num,numeric_transformer,numeric_features),(cat,categorical_transformer,categorical_features)])# 完整Pipeline预处理 模型训练一体化full_pipelinePipeline([(preprocessor,preprocessor),(classifier,RandomForestClassifier(n_estimators100))])# 一行代码完成所有预处理和训练# full_pipeline.fit(X_train, y_train)# full_pipeline.predict(X_test)print(Pipeline构建完成调用 full_pipeline.fit() 即可开始训练)Pipeline的三大好处防止数据泄露StandardScaler的均值和方差只在训练集上计算测试集用同样的参数变换不会把测试集信息泄露进去代码整洁预处理和模型封装在一起部署时只需保存一个Pipeline对象方便调优GridSearchCV可以直接在Pipeline上进行搜索包括预处理参数在内的所有超参数小结sklearn完整工作流1. 数据探索EDA了解数据形状、分布、缺失值 2. 特征工程构造有意义的特征 3. 多模型对比交叉验证选最好的 4. 超参数调优GridSearchCV或RandomizedSearchCV 5. 最终评估在测试集上用正确的指标评估 6. 模型保存joblib.dump这个流程在实际工作中会反复使用。下一篇我们看传统ML和LLM的分工——什么时候用哪个

相关新闻