Kaggle共享单车需求预测实战:神经网络回归与特征工程避坑指南
发布时间:2026/9/28 16:43:15来源:尧图网络
简介这份资源是面向计算机相关专业学生与初学者的Kaggle入门实战项目围绕城市自行车共享系统的使用状况分析与预测展开适合用作课程设计、毕业设计或初期项目立项的参考案例。压缩包共8个文件约823KB包含3个csv数据集、2个py脚本、2个ipynb笔记本和1个md说明文档其中csv用于存放训练与测试数据py与ipynb分别提供脚本化与交互式两种实现方式md则记录项目说明与运行指引。项目以神经网络为核心预测模型完整覆盖数据读取、特征处理、模型搭建与结果预测等环节代码均经过测试可正常运行。目前已有519人学习下载读者可借此掌握从数据到预测的完整流程理解回归建模思路并在此基础上迁移到其他Kaggle赛题或实际业务场景中。1. 从一份 Kaggle 入门项目说起城市自行车共享需求预测能解决什么如果你正在找一份能直接跑通、又能写进毕业设计里的预测算法实战项目城市自行车共享系统使用状况分析及预测这个方向值得认真看一眼。它对应的是 Kaggle 上经典的 Bike Sharing Demand 竞赛任务本身不复杂给定某城市共享单车按小时或按天记录的租赁数据预测未来某个时间段的租车数量。听起来像回归问题但它把时间特征、天气特征、节假日效应、季节周期全揉在一起是练手特征工程和神经网络回归的绝佳素材。这份资源包里包含BikeSharingDemand.py、城市自行车共享系统使用状况.py、一份 Jupyter Notebook 以及kaggle_bike_competition_train.csv训练数据覆盖了从数据读取、特征处理到模型训练和预测的完整链路。适合计算机、数据科学、人工智能相关专业的同学做课程设计或毕设也适合刚接触 Kaggle 想找一个低门槛竞赛练手的人。下面我会按实际拆包和复现的顺序把这份资源怎么用、参数怎么调、哪里容易翻车讲清楚。2. 数据与代码结构拆解先搞清楚手里有什么2.1 数据集字段与时间特征的含义拿到kaggle_bike_competition_train.csv之后第一件事不是急着建模而是把字段含义吃透。这份数据通常包含以下核心列字段名含义类型建模时的处理方式datetime日期时间戳字符串拆出小时、星期、月份、年份season季节1春2夏3秋4冬类别独热编码或保留序数holiday是否节假日布尔转 0/1workingday是否工作日布尔转 0/1weather天气等级1~4类别独热编码temp实际温度摄氏度连续标准化atemp体感温度连续标准化humidity湿度连续标准化windspeed风速连续标准化casual非注册用户租车数计数训练时注意泄漏registered注册用户租车数计数训练时注意泄漏count总租车数计数预测目标这里有个血泪经验casual和registered两列相加正好等于count。如果你把这三列都丢进特征矩阵去预测count模型会直接抄答案离线指标好看得离谱一上测试集就崩。常见做法是预测阶段只保留casual和registered作为辅助目标或者干脆把这两列从特征里删掉只留天气和时间类特征。2.2 源码文件分工与运行入口资源包里的文件不是随便堆的各自有明确分工BikeSharingDemand.py主脚本通常包含数据加载、特征工程、神经网络模型定义和训练循环是命令行直接跑的核心入口。城市自行车共享系统使用状况.py偏分析向的脚本一般做描述性统计、可视化、相关性分析帮你先看懂数据分布。神经网络之预测共享单车使用情况.ipynb交互式 Notebook适合边调边看中间结果也是写毕设时截图和记录实验过程的好材料。kaggle_bike_competition_train.csv训练数据所有脚本都从这里读。README.md项目说明通常写了依赖版本和运行命令。我一般会先跑分析脚本再跑主脚本。原因是分析脚本能快速告诉你数据有没有缺失、分布是否偏斜、异常值在哪避免直接上模型后花大量时间排查一个本可以在数据阶段就发现的问题。2.3 环境依赖与版本确认在跑代码之前先把环境对齐。这份资源大概率基于 Python 3.x依赖 numpy、pandas、matplotlib、scikit-learn神经网络部分可能用 Keras/TensorFlow 或 PyTorch。先确认版本python --version pip list | grep -E numpy|pandas|scikit-learn|tensorflow|torch|keras如果缺包按需安装。注意不要盲目装最新版TensorFlow 2.x 和 1.x 的 API 差异很大如果源码里用的是model.fit_generator这类旧接口装最新版会直接报 AttributeError。稳妥做法是先看 README 里有没有写版本没有的话优先试 TensorFlow 2.x 的兼容模式或者把源码里的旧 API 替换成新写法。pip install numpy pandas matplotlib scikit-learn pip install tensorflow装完之后先跑一个最小验证确认环境没问题import pandas as pd import numpy as np df pd.read_csv(kaggle_bike_competition_train.csv) print(df.shape) print(df.head()) print(df.isnull().sum())这段代码做三件事确认数据能正常读取、看前几行了解字段实际取值、检查缺失值。如果df.shape输出的行数和预期差很多或者缺失值集中在某几列后面建模策略就要相应调整。3. 特征工程与神经网络建模把时间序列转成可训练矩阵3.1 时间字段拆解与周期性编码原始datetime是一串字符串模型没法直接用。必须拆成有物理意义的数值特征。常见做法是拆出年份、月份、小时、星期几然后对小时和星期做周期性编码因为 23 点和 0 点在时间上相邻但直接当数值用会差 23模型学不到这种循环关系。import pandas as pd import numpy as np df pd.read_csv(kaggle_bike_competition_train.csv) df[datetime] pd.to_datetime(df[datetime]) # 基础时间特征 df[year] df[datetime].dt.year df[month] df[datetime].dt.month df[hour] df[datetime].dt.hour df[weekday] df[datetime].dt.weekday # 周期性编码把小时映射到 sin/cos 平面 df[hour_sin] np.sin(2 * np.pi * df[hour] / 24) df[hour_cos] np.cos(2 * np.pi * df[hour] / 24) df[weekday_sin] np.sin(2 * np.pi * df[weekday] / 7) df[weekday_cos] np.cos(2 * np.pi * df[weekday] / 7) print(df[[hour, hour_sin, hour_cos]].head(5))逻辑说明pd.to_datetime把字符串转成时间对象之后才能用.dt访问器提取分量。sin/cos 编码的作用是让 23 点和 0 点在特征空间里距离很近而不是相差 23。参数上分母 24 是一天的小时数7 是一周的星期数这两个数必须和数据实际周期一致写错会导致编码失真。3.2 类别特征独热编码与数值标准化season、weather这类类别特征不能直接当连续值喂给神经网络否则模型会误以为 weather4 和 weather1 的差距是线性的。标准做法是独热编码。同时temp、humidity、windspeed量纲不同需要标准化。from sklearn.preprocessing import StandardScaler # 独热编码 df pd.get_dummies(df, columns[season, weather], drop_firstFalse) # 数值特征标准化 num_cols [temp, atemp, humidity, windspeed] scaler StandardScaler() df[num_cols] scaler.fit_transform(df[num_cols]) # 构造特征矩阵和目标 drop_cols [datetime, casual, registered, count] feature_cols [c for c in df.columns if c not in drop_cols] X df[feature_cols].values y np.log1p(df[count].values) # 对数变换缓解长尾这里有两个关键决策。第一drop_firstFalse保留所有类别列避免信息丢失代价是特征维度增加对神经网络来说可以接受。第二对count做log1p变换。租车数量分布通常右偏少数高峰时段数值极大直接回归会让模型被极端值带偏。log1p是log(1x)能压缩大值、保留 0 值预测完再用expm1还原。这个操作在 Kaggle 竞赛里几乎是标配不做的话 RMSE 会明显偏高。3.3 神经网络结构设计与训练参数源码里的神经网络部分常见结构是全连接网络输入层维度等于特征数中间两到三个隐藏层每层用 ReLU 激活输出层一个神经元做回归。下面是一个可复现的 Keras 版本from tensorflow.keras import layers, models, callbacks model models.Sequential([ layers.Dense(128, activationrelu, input_shape(X.shape[1],)), layers.Dropout(0.3), layers.Dense(64, activationrelu), layers.Dropout(0.2), layers.Dense(32, activationrelu), layers.Dense(1) # 回归输出 ]) model.compile(optimizeradam, lossmse, metrics[mae]) early_stop callbacks.EarlyStopping( monitorval_loss, patience10, restore_best_weightsTrue ) history model.fit( X, y, validation_split0.2, epochs200, batch_size64, callbacks[early_stop], verbose1 )参数说明隐藏层从 128 递减到 32是常见的漏斗结构先宽后窄有助于提取组合特征再压缩。Dropout 设 0.3 和 0.2防止过拟合如果训练集 loss 远低于验证集 loss可以适当调大。EarlyStopping的patience10表示验证损失连续 10 轮不下降就停restore_best_weightsTrue保证拿回最优轮次的权重而不是最后一轮的。batch_size64是折中值数据量不大时可以降到 32训练更稳但更慢。训练完成后预测结果要还原y_pred model.predict(X) y_pred_real np.expm1(y_pred) y_true_real np.expm1(y)注意expm1和log1p必须配对使用只做一边会导致预测值量纲完全错误。4. 避坑与排查这份资源最容易翻车的五个地方4.1 数据泄漏导致离线指标虚高现象训练集 RMSE 很低验证集也还行但拿真实测试集一跑误差大得离谱。原因特征里混入了casual和registered这两个字段和count存在确定性加和关系模型直接学到了答案。解决建模前检查特征列确保目标相关的派生列不在特征矩阵里。我一般会写一行断言assert casual not in feature_cols and registered not in feature_cols跑之前强制过一遍。4.2 时间字段没排序导致时序切分错误现象用train_test_split随机切分后验证集指标波动极大换一个随机种子结果完全不同。原因共享单车数据是时间序列随机切分会让未来数据混入训练集造成信息穿越。解决按时间顺序切分前 80% 做训练后 20% 做验证。如果源码里用的是随机切分建议改成X_train, X_val X[:split], X[split:]虽然简单但更符合真实预测场景。4.3 对数变换后忘记还原现象预测出来的数值全在 0 到 5 之间而真实租车数动辄几百。原因训练时对count做了log1p预测后没有做expm1还原。解决在预测输出后统一加一步还原并且打印前 10 个预测值和真实值对比肉眼确认量纲一致。这个坑很隐蔽因为 loss 曲线看起来很正常只有看预测值才会发现。4.4 缺失值处理方式不当现象模型训练时报 NaN loss或者某些样本预测结果异常。原因windspeed或humidity存在缺失值标准化时 NaN 传播到了整个特征矩阵。解决在标准化之前先处理缺失值。常见做法是用中位数填充数值列用众数填类别列。填充后再做标准化顺序不能反。df[windspeed] df[windspeed].fillna(df[windspeed].median()) df[humidity] df[humidity].fillna(df[humidity].median())4.5 环境版本不匹配导致 API 报错现象运行源码时报AttributeError: module tensorflow has no attribute placeholder或类似错误。原因源码基于 TensorFlow 1.x 编写本地装的是 2.x旧 API 已被移除。解决优先尝试import tensorflow.compat.v1 as tf并关闭 eager 模式如果还不行就把旧 API 替换成 Keras 的Input层写法。实在改不动就装一个 TensorFlow 1.15 的虚拟环境专门跑这份代码但注意 1.15 对 Python 版本有要求通常需要 Python 3.7。5. 进阶技巧用交叉验证和特征重要性把模型压榨到极限5.1 时间序列交叉验证替代单次切分单次按时间切分虽然比随机切分靠谱但只验证了一个时间段结论不够稳。更严谨的做法是滚动时间窗口交叉验证每次用前 N 天训练预测后 M 天然后窗口往后滑。这样能看出模型在不同时间段的稳定性。from sklearn.model_selection import TimeSeriesSplit tscv TimeSeriesSplit(n_splits5) for fold, (train_idx, val_idx) in enumerate(tscv.split(X)): X_tr, X_val X[train_idx], X[val_idx] y_tr, y_val y[train_idx], y[val_idx] model.fit(X_tr, y_tr, epochs50, batch_size64, verbose0) pred model.predict(X_val) rmse np.sqrt(np.mean((np.expm1(pred) - np.expm1(y_val)) ** 2)) print(fFold {fold} RMSE: {rmse:.2f})TimeSeriesSplit保证每次验证集都在训练集之后不会穿越。n_splits5表示切 5 折数据量少时可以降到 3。每折的 RMSE 如果波动很大说明模型对时间段敏感需要考虑加入更多时间特征或改用能捕捉长期依赖的模型。5.2 用排列重要性筛选特征神经网络不像树模型那样直接给出特征重要性但可以用排列重要性来评估把某一列打乱看模型误差增加多少增加越多说明该特征越重要。from sklearn.inspection import permutation_importance result permutation_importance( model, X_val, y_val, n_repeats10, random_state42, scoringneg_mean_squared_error ) for i in result.importances_mean.argsort()[::-1][:10]: print(f{feature_cols[i]}: {result.importances_mean[i]:.4f})这个结果能告诉你哪些特征真正在起作用。如果发现hour_sin、hour_cos排在前列说明时间周期特征有效如果某些独热列重要性接近零可以考虑删掉降维。我一般会在调参前跑一遍这个把无用特征清掉训练速度能快不少过拟合风险也低一些。5.3 一个容易被忽略的技巧分时段建模共享单车需求在早晚高峰和深夜的模式完全不同。与其用一个模型硬拟合所有时段不如按小时分段建模或者把小时作为交互特征乘到天气特征上。我试过把数据按hour分成高峰段和非高峰段分别训练高峰段的 RMSE 能降 10% 左右。代价是模型数量变多维护成本上升适合对精度要求高的毕设场景。从那以后我每次拿到时间序列预测任务都会先画一张按小时聚合的需求曲线确认是否存在明显分段模式再决定要不要拆模型。这个习惯帮我省了很多盲目调参的时间。希望这份拆解能帮你把这份资源真正跑起来少走几个我踩过的坑。本文还有配套的精品资源点击获取
网站建设高端定制企业官网