网站如何上传网站建设的对比分析
网站如何上传,网站建设的对比分析,php 怎么做 网站吗,排版设计的网站1. 从零开始#xff1a;为什么Kaggle房价预测是入门机器学习的绝佳选择
如果你对机器学习感兴趣#xff0c;想找一个能上手、有数据、有明确目标#xff0c;还能和全球高手过招的项目#xff0c;那我强烈推荐你从Kaggle的房价预测项目开始。我自己带过不少新人#xff0c;…1. 从零开始为什么Kaggle房价预测是入门机器学习的绝佳选择如果你对机器学习感兴趣想找一个能上手、有数据、有明确目标还能和全球高手过招的项目那我强烈推荐你从Kaggle的房价预测项目开始。我自己带过不少新人发现很多人学了一堆理论一到实战就懵了。这个项目就像学游泳与其在岸上看一百遍教程不如直接跳进一个安全的泳池——Kaggle的House Prices: Advanced Regression Techniques竞赛就是那个水温合适、有救生员的完美泳池。这个项目为什么好首先它的目标非常直观根据房子的各种特征比如面积、地段、建造年份、装修质量等等来预测它的最终售价。这个场景我们每个人都能理解不像一些图像识别或者自然语言处理项目一开始可能连“特征”是什么都摸不着头脑。其次Kaggle提供了结构清晰、内容丰富的训练集和测试集数据量适中大约1500条训练样本既有数值型数据如面积、房间数也有分类型数据如社区类型、房屋风格非常适合练习完整的数据处理流程。最后这个项目在Kaggle上历史悠久社区里积累了海量的公开笔记Kernel和讨论你几乎能遇到的所有问题都有人踩过坑并分享了解决方案。我刚开始接触时也是从这个项目入的门。当时觉得不就是预测个价格嘛把数据扔进模型不就行了结果被现实狠狠教育了一番。数据里有大量的缺失值有的特征分布歪得离谱直接建模效果一塌糊涂。这个过程恰恰是它的价值所在它能逼着你走完一个标准机器学习项目的全流程——数据探索、清洗、特征工程、模型选择、调优、集成直到最后提交结果。走完这一遍你对“数据科学”这四个字会有完全不同的、脚踏实地的理解。2. 数据探索与清洗像侦探一样审视你的数据拿到数据后千万别急着建模型。我见过太多新手一上来就导入sklearn开始拟合结果模型表现很差却不知道问题出在哪。数据探索EDA就是你破案的第一步目的是了解数据的“脾气秉性”。2.1 初窥全貌与目标变量分析我们先用Pandas把数据读进来看看它长什么样。这里有个小技巧我会习惯性地先看数据维度、列名以及目标变量SalePrice售价的分布。import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns sns.set_style(whitegrid) %matplotlib inline # 加载数据 train_df pd.read_csv(./train.csv) test_df pd.read_csv(./test.csv) print(f训练集形状: {train_df.shape}) print(f测试集形状: {test_df.shape}) print(\n训练集列名预览:\n, train_df.columns.tolist()[:10], ...)运行后你会发现训练集有1460行、81列包括目标列测试集有1459行、80列。这81个特征就是我们的“破案线索”。接下来重点关照我们的“受害人”——房价。# 查看目标变量的统计摘要 print(train_df[SalePrice].describe()) # 绘制分布图 plt.figure(figsize(10, 6)) sns.histplot(train_df[SalePrice], kdeTrue) plt.title(SalePrice Distribution) plt.show() # 计算偏度和峰度 from scipy.stats import skew, kurtosis print(f偏度(Skewness): {skew(train_df[SalePrice].dropna()):.4f}) print(f峰度(Kurtosis): {kurtosis(train_df[SalePrice].dropna()):.4f})你会看到房价的分布明显右偏偏度远大于0并且有一个又长又重的尾巴峰度很高。这意味着数据中存在一些价格极高的豪宅它们会把模型的学习方向“带歪”。很多线性模型假设数据服从正态分布这种偏态分布会严重影响模型性能。所以我们后续需要对目标变量进行变换比如取对数让它更接近正态分布。2.2 揪出异常值与缺失值异常值是数据中的“捣蛋鬼”。在这个数据集里通过绘制居住面积(GrLivArea)与售价的散点图可以轻松发现它们。plt.figure(figsize(10, 6)) plt.scatter(train_df[GrLivArea], train_df[SalePrice], alpha0.6) plt.xlabel(GrLivArea (Above grade living area)) plt.ylabel(SalePrice) plt.title(Living Area vs SalePrice) plt.show()图上右下角会有几个点居住面积很大超过4000平方英尺但售价却很低低于30万美元。这不符合常理很可能是数据录入错误或者是极其特殊的个案。对于这种明显的异常点我的处理方式是直接剔除因为它们会对回归线产生不合理的拉扯。在真实业务中你需要和业务方确认但在这个练习中直接删除是通用做法。缺失值是另一个大坑。用一行代码就能看出每个特征缺失的比例# 合并训练集和测试集以便统一处理缺失值先剔除目标列 all_data pd.concat([train_df.drop([SalePrice], axis1), test_df], axis0) missing_ratio (all_data.isnull().sum() / len(all_data)).sort_values(ascendingFalse) missing_ratio missing_ratio[missing_ratio 0] print(missing_ratio.head(15))你会发现像PoolQC游泳池质量、MiscFeature其他特征等字段缺失率高达95%以上。这其实传递了一个信息不是所有房子都有游泳池或其他设施。对于这类特征缺失本身就有意义通常我们用“None”来填充表示“没有”。而对于像LotFrontage临街距离这类有实际意义但缺失较少的数值特征我常用的方法是按房屋所在的社区(Neighborhood)分组用该组的中位数来填充这比用全局均值更合理。3. 特征工程从原始数据中“炼金”数据清洗干净只是第一步特征工程才是提升模型性能的“魔法”。它的核心思想是把原始数据转换成对模型更友好、信息量更大的形式。3.1 处理偏态分布与创造新特征之前我们看到目标变量SalePrice是偏态的许多数值特征也可能如此。我们可以用np.log1p即 log(1x)对偏态严重的数值特征进行变换使其分布更平滑这能显著提升线性模型的稳定性。同时检查所有数值特征的偏度是一个好习惯。numeric_feats all_data.dtypes[all_data.dtypes ! object].index skewed_feats all_data[numeric_feats].apply(lambda x: skew(x.dropna())).sort_values(ascendingFalse) skewness pd.DataFrame({Skew: skewed_feats}) high_skew skewness[abs(skewness[Skew]) 0.75] print(f有 {high_skew.shape[0]} 个高偏度特征需要处理) # 使用Box-Cox变换一种更通用的变换log变换是它的特例 from scipy.special import boxcox1p lam 0.15 # 这个参数可以通过统计方法优化但0.15是个经验起始值 for feat in high_skew.index: all_data[feat] boxcox1p(all_data[feat], lam)除了变换创造新特征往往能带来惊喜。房子总价和总面积强相关但数据集中没有“总面积”。我们可以自己创造TotalSF TotalBsmtSF 1stFlrSF 2ndFlrSF。类似地你还可以创造“浴室总数”、“房龄”用销售年份减去建造年份等。这些复合特征有时比原始特征更具预测力。3.2 编码分类变量与数据准备机器学习模型大多只能处理数值。所以我们需要把“MSZoning”分区类型、“Neighborhood”社区这类文本型分类变量转换成数字。这里要小心两种编码方式标签编码 (Label Encoding)给每个类别一个数字ID比如[A, B, C]变成[0, 1, 2]。这适用于有内在顺序的类别如质量评级Po, Fa, TA, Gd, Ex我们可以手动映射为数字。独热编码 (One-Hot Encoding)为每个类别创建一个新的二值列0或1。这适用于没有顺序的类别如社区名。使用Pandas的get_dummies可以轻松实现但要小心特征维度爆炸类别太多时。# 示例对有序分类特征进行标签编码 from sklearn.preprocessing import LabelEncoder cols_for_label_encode [ExterQual, KitchenQual, BsmtQual] # 这些特征的值如 Ex, Gd, TA, Fa, Po 是有序的 for col in cols_for_label_encode: lbl LabelEncoder() # 注意要基于合并后的all_data进行fit以保证训练集和测试集编码一致 lbl.fit(list(all_data[col].astype(str).values)) all_data[col] lbl.transform(list(all_data[col].astype(str).values)) # 对无序分类特征进行独热编码 all_data pd.get_dummies(all_data) print(f编码后特征维度: {all_data.shape})做完这一切我们终于得到了干净、规整、可供模型使用的数据集。记得把处理好的数据重新拆分成训练集和测试集。4. 模型构建与调优找到你的预测利器现在进入最激动人心的环节——建模。在这个项目里我们不会只用一个模型而是尝试多种并让它们“团队作战”。4.1 基础模型试水与交叉验证我们先尝试几个不同风格的回归模型看看它们的 baseline 表现。这里的关键是使用交叉验证来评估而不是简单地在训练集上划分一次验证集。交叉验证能更稳健地估计模型在未知数据上的表现。from sklearn.linear_model import Lasso, ElasticNet from sklearn.kernel_ridge import KernelRidge from sklearn.ensemble import GradientBoostingRegressor import xgboost as xgb import lightgbm as lgb from sklearn.model_selection import KFold, cross_val_score from sklearn.metrics import mean_squared_error from sklearn.preprocessing import RobustScaler from sklearn.pipeline import make_pipeline import numpy as np # 准备数据 X_train all_data[:train_df.shape[0]].values y_train np.log1p(train_df[SalePrice]).values # 对目标变量也取对数 X_test all_data[train_df.shape[0]:].values # 定义交叉验证函数评估指标为RMSE def rmse_cv(model, XX_train, yy_train): kf KFold(n_splits5, shuffleTrue, random_state42) rmse np.sqrt(-cross_val_score(model, X, y, scoringneg_mean_squared_error, cvkf)) return rmse # 初始化模型 # Lasso回归擅长特征选择可以自动将不重要的特征系数降为0 lasso make_pipeline(RobustScaler(), Lasso(alpha0.0005, random_state1)) # 弹性网络结合了Lasso和Ridge的优点 ENet make_pipeline(RobustScaler(), ElasticNet(alpha0.0005, l1_ratio0.9, random_state3)) # 核岭回归可以捕捉非线性关系 KRR KernelRidge(alpha0.6, kernelpolynomial, degree2, coef02.5) # 梯度提升树强大的集成树模型 GBoost GradientBoostingRegressor(n_estimators3000, learning_rate0.05, max_depth4, max_featuressqrt, min_samples_leaf15, min_samples_split10, losshuber, random_state5) # XGBoost优化过的梯度提升库速度精度俱佳 xgb_model xgb.XGBRegressor(colsample_bytree0.4603, gamma0.0468, learning_rate0.05, max_depth3, min_child_weight1.7817, n_estimators2200, reg_alpha0.4640, reg_lambda0.8571, subsample0.5213, random_state7, n_jobs-1) # LightGBM微软出品训练更快内存更省 lgb_model lgb.LGBMRegressor(objectiveregression, num_leaves1000, learning_rate0.05, n_estimators350, reg_alpha0.9, random_state42) # 评估模型 models [(Lasso, lasso), (ENet, ENet), (KRR, KRR), (GBoost, GBoost), (XGBoost, xgb_model), (LightGBM, lgb_model)] for name, model in models: score rmse_cv(model) print(f{name:10} 平均RMSE: {score.mean():.6f}, 标准差: {score.std():.6f})跑完这段代码你可能会发现Lasso和ElasticNet这类线性模型表现不错而树模型如XGBoost, LightGBM也有很强的竞争力。没有哪个模型永远最好这就是我们需要集成的原因。4.2 高级技巧模型堆叠与集成学习单个模型再强也可能有局限性。集成学习的思想是“三个臭皮匠顶个诸葛亮”。这里介绍两种高级玩法平均法和堆叠法。平均法最简单就是把几个模型的预测结果取平均。虽然简单但常常能有效降低方差提升稳定性。class AveragingModels: def __init__(self, models): self.models models def fit(self, X, y): self.models_ [clone(model) for model in self.models] for model in self.models_: model.fit(X, y) return self def predict(self, X): predictions np.column_stack([model.predict(X) for model in self.models_]) return np.mean(predictions, axis1) # 尝试平均几个表现好的模型 averaged_models AveragingModels(models(ENet, GBoost, KRR)) score_avg rmse_cv(averaged_models) print(f平均模型 RMSE: {score_avg.mean():.6f})堆叠法更巧妙一些。它把第一层多个模型基模型的预测结果作为新的特征输入给第二层的一个模型元模型进行最终预测。这相当于让元模型去学习如何组合基模型的输出。from sklearn.base import BaseEstimator, RegressorMixin, clone class StackingAveragedModels(BaseEstimator, RegressorMixin): def __init__(self, base_models, meta_model, n_folds5): self.base_models base_models self.meta_model meta_model self.n_folds n_folds def fit(self, X, y): self.base_models_ [list() for _ in self.base_models] self.meta_model_ clone(self.meta_model) kfold KFold(n_splitsself.n_folds, shuffleTrue, random_state156) # 生成折外预测作为元特征 meta_features np.zeros((X.shape[0], len(self.base_models))) for i, model in enumerate(self.base_models): for train_idx, holdout_idx in kfold.split(X, y): instance clone(model) self.base_models_[i].append(instance) instance.fit(X[train_idx], y[train_idx]) y_pred instance.predict(X[holdout_idx]) meta_features[holdout_idx, i] y_pred # 用生成的元特征训练元模型 self.meta_model_.fit(meta_features, y) return self def predict(self, X): # 用每个基模型预测X然后取平均作为最终的元特征 meta_features np.column_stack([ np.column_stack([model.predict(X) for model in base_models]).mean(axis1) for base_models in self.base_models_ ]) return self.meta_model_.predict(meta_features) # 使用ENet, GBoost, KRR作为基模型Lasso作为元模型 stacked_model StackingAveragedModels(base_models(ENet, GBoost, KRR), meta_modellasso) score_stacked rmse_cv(stacked_model) print(f堆叠模型 RMSE: {score_stacked.mean():.6f})在实际操作中我通常会把表现最好的几个模型比如Stacking模型、XGBoost和LightGBM的预测结果用一个简单的加权平均进行融合。权重可以通过在验证集上的表现来手动调整或者用简单的网格搜索来确定。最终这个融合模型往往能稳定地取得比任何单一模型都更好的成绩。5. 提交结果与复盘完成你的第一次Kaggle之旅模型训练和调优完成后最后一步就是用测试集生成预测并提交到Kaggle看排名。这里有个至关重要的细节我们之前对目标变量SalePrice取了自然对数np.log1p进行训练所以现在预测出的结果是取了对数的值。在提交前必须用np.expm1函数把它转换回原始的价格尺度。# 训练最终选择的集成模型例如加权平均 def train_and_predict(models, weights): 训练模型并生成测试集预测models和weights是列表一一对应 test_predictions np.zeros(X_test.shape[0]) for model, weight in zip(models, weights): model.fit(X_train, y_train) pred model.predict(X_test) test_predictions pred * weight return test_predictions # 假设我们决定用Stacked, XGB, LGB三个模型权重分别为0.6, 0.2, 0.2 final_models [stacked_model, xgb_model, lgb_model] final_weights [0.6, 0.2, 0.2] final_predictions train_and_predict(final_models, final_weights) # 将预测值从对数尺度转换回原尺度 final_predictions np.expm1(final_predictions) # 生成提交文件 submission pd.DataFrame({ Id: test_df[Id], SalePrice: final_predictions }) submission.to_csv(my_submission.csv, indexFalse) print(提交文件已生成)把生成的my_submission.csv文件上传到Kaggle竞赛页面系统会自动计算你的模型在私有测试集上的误差通常是RMSE的对数形式并给出一个实时排名。第一次提交看到自己的名字出现在排行榜上那种感觉非常棒即使排名不靠前也没关系重要的是你完整地走完了一个流程。回过头来看这个项目的价值远不止于学会预测房价。它教会你如何系统地对待一个数据问题从理解业务房价由什么决定、探索数据、处理脏数据、创造特征、选择并组合模型到最终产出结果。每一个环节都有坑每一个决策都需要思考。我建议你在自己的笔记本上尝试不同的特征组合、试试不同的模型参数、甚至实现不同的集成策略。Kaggle的魅力就在于你可以不断迭代优化看着自己的分数一点点提高这个过程中积累的经验才是你真正能带走的宝贵财富。