kaggle竞赛:纽约出租车行程时间NYC Taxi Trip Duration

1.引言

作为一名(坦白说有点懒的)图像处理方向的研究生,说实话最近新开一个坑,可能是因为要寒假了比较无聊,这次带来的系列是kaggle数据处理竞赛的经典例题:纽约出租车行程时间问题。希望大家多多支持:)

1.1 问题背景

纽约充满了单行道、狭窄的街道,以及随时存在的无数行人。更不用说那些堵塞街道的汽车、摩托车和自行车了。再加上人们急于从A点赶到B点的情绪,结果就是你很可能会迟到,错过你需要准时参加的活动。

生活在像纽约这样的城市中,解决从A点到B点的问题(而不至于让自己抓狂)其实很简单:打车(或者使用Uber、Lyft等)。你不需要担心交通堵塞或行人问题,而且你还有时间做点别的事情,比如查看邮件。虽然听起来简单,但这并不意味着你一定能准时到达目的地。所以,你需要让司机走最短的路线。这里说的最短指时间最短。如果某条路线A比路线B长X公里,但能比路线B快Y分钟到达,那么你应该选择路线A。

要知道哪条路线是最佳路线,我们需要能够预测当选择某条路线时,行程会持续多长时间。因此,这场竞赛的目标是预测测试数据集中每个行程的持续时间,给定起始和结束坐标

1.2 使用的库与函数

在这个项目中,我们使用了 Python 3.6.1 和以下库来处理数据、构建模型和可视化结果:

  • Scikit-Learn:用于执行机器学习操作(如数据预处理、模型训练等)。
  • Pandas:用于数据操作和处理,方便加载、清洗和转换数据。
  • Numpy:Python中进行科学计算的基础包,支持高效的数值运算。
  • XGBoost:用于构建预测模型的梯度提升算法,常用于回归和分类任务。
  • Seaborn:基于Matplotlib构建的高级数据可视化工具,简化了绘图操作。
# 导入必需的库
import numpy as np                # 数值计算
import pandas as pd               # 数据处理
import seaborn as sns             # 数据可视化
import matplotlib.pyplot as plt    # 可视化
import xgboost as xgb             # XGBoost 模型
from sklearn.model_selection import train_test_split  # 数据划分
from sklearn.metrics import mean_squared_log_error    # RMSLE 计算
from sklearn.preprocessing import StandardScaler      # 标准化
from math import radians, cos, sin, asin, sqrt
import matplotlib
plt.rcParams['figure.figsize'] = [16, 10]

1.3 数据加载

train = pd.read_csv('new-york-city-taxi-with-osrm/train.csv')
test = pd.read_csv('new-york-city-taxi-with-osrm/test.csv')
X_train = train.drop(columns=['trip_duration'])
y_train = train['trip_duration']
X_test = test.drop(columns=['trip_duration'])
y_test = test['trip_duration']

2. 数据准备处理

2.1  Trip Duration Clean-up

# 设置显示样式
sns.set(style="whitegrid")
# 绘制 trip_duration 分布图(对数变换以更好显示分布)
plt.figure(figsize=(10, 6))
sns.histplot(train['trip_duration'], bins=100, kde=False, color='blue', log_scale=True)
plt.title('Distribution of Trip Duration (Log Scale)', fontsize=16)
plt.xlabel('Trip Duration (seconds, log scale)', fontsize=12)
plt.ylabel('Frequency', fontsize=12)
plt.show()

从上图中可以看到,trip_duration 变量存在一些异常值,例如,最大行程时长高达 980 小时,而最小行程时长仅为 1 秒。这些异常值可能会扭曲数据分布,并对模型性能产生负面影响。

清理方法:
决定排除超出平均值 2 个标准差范围的数据。这是因为,在正态分布的假设下,大多数数据(约 95%)应位于 2 个标准差范围内。此外,也可以尝试将范围扩大到 4 个标准差,观察其对最终结果的影响。
m = np.mean(train['trip_duration'])
s = np.std(train['trip_duration'])
train = train[train['trip_duration'] <= m + 2*s]
train = train[train['trip_duration'] >= m - 2*s]

2.2 Latitude and Longitude Clean-up

限制纽约市边界范围内的坐标点

纽约市的边界(以经纬度表示)为:

  • 经度范围:city_long_border = (-74.03, -73.75)
  • 纬度范围:city_lat_border = (40.63, 40.85)

通过与 train.describe() 的输出进行比较,可以发现某些坐标点(如 pickup_longitude, pickup_latitude, dropoff_longitude, dropoff_latitude)超出了这些边界范围。这些点可能是异常值或数据错误。

train = train[train['pickup_longitude'] <= -73.75]
train = train[train['pickup_longitude'] >= -74.03]
train = train[train['pickup_latitude'] <= 40.85]
train = train[train['pickup_latitude'] >= 40.63]
train = train[train['dropoff_longitude'] <= -73.75]
train = train[train['dropoff_longitude'] >= -74.03]
train = train[train['dropoff_latitude'] <= 40.85]
train = train[train['dropoff_latitude'] >= 40.63]

2.3 Passenger_Count Clean-up

异常值:0,7,8,9
由于test中也有异常值,不能直接删除,考虑用最近的值替代:0–>1,7、8、9–>6

train['passenger_count'] = train['passenger_count'].replace({0: 1, 7: 6, 8: 6, 9: 6})
test['passenger_count'] = test['passenger_count'].replace({0: 1, 7: 6, 8: 6, 9: 6})

2.4 Date Clean-up

在数据准备的最后一步,我们需要将日期变量(pickup_datetimedropoff_datetime)的格式转换为 datetime 类型。这一步将极大地简化后续的时间特征提取操作,例如:提取年、月、日、小时、分钟、星期、日期、其中加上“time”,用hour+minute/60,为了区分7:01与7:59;是否工作日、是否节假日 24小时切分为不同时段;早高峰、晚高峰、白天、夜晚 划分方式需要区分是否节假日,节假日没有早/晚高峰;

# 提取基本时间特征
train['year'] = train['pickup_datetime'].dt.year
train['month'] = train['pickup_datetime'].dt.month
train['day'] = train['pickup_datetime'].dt.day
train['hour'] = train['pickup_datetime'].dt.hour
train['minute'] = train['pickup_datetime'].dt.minute
train['weekday'] = train['pickup_datetime'].dt.weekday  # 0=Monday, 6=Sunday
train['date'] = train['pickup_datetime'].dt.date  # 仅日期部分
# 创建 time 特征 (hour + minute / 60)
train['time'] = train['hour'] + train['minute'] / 60
# 是否工作日 (0=周末, 1=工作日)
train['is_workday'] = train['weekday'].apply(lambda x: 1 if x < 5 else 0)
# 是否节假日
train['is_holiday'] = train['date'].apply(lambda x: 1 if x in holidays else 0)
# 时间段划分函数
def assign_time_period(hour, is_holiday):
    if is_holiday:  # 节假日
        if 7 <= hour < 21:
            return 'day'  # 白天
        else:
            return 'night'  # 夜晚
    else:  # 非节假日
        if 7 <= hour <= 9:
            return 'morning_rush'  # 早高峰
        elif 17 <= hour <= 21:
            return 'evening_rush'  # 晚高峰
        elif 9 < hour < 17:
            return 'daytime'  # 白天
        else:
            return 'night'  # 夜晚
# 应用时间段划分
train['time_period'] = train.apply(lambda row: assign_time_period(row['hour'], row['is_holiday']), axis=1)
# 查看结果
print(train[['year', 'month', 'day', 'hour', 'minute', 'weekday', 'time', 'is_workday', 'is_holiday', 'time_period']].head())

懒得更新了,明天继续吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值