【Kaggle】纽约市出租车费预测(经典)

【参考:New York City Taxi Fare Prediction | Kaggle

【参考:美国纽约市出租车大数据探索-基于kaggle比赛_@Irene的博客-CSDN博客】这个参考较多
代码【参考:2 机器学习实战 纽约出租车车费预测_哔哩哔哩_bilibili

【参考:Kaggle-纽约市出租车费预测_qq_28584559的博客-CSDN博客

代码:【参考:机器学习/Kaggle/出租车车费预测/版本一车费预测实战.ipynb · myaijarvis/AI - 码云 - 开源中国

这篇也不错 【参考:Cleansing+EDA+Modelling(LGBM + XGBoost starters) | Kaggle
在这里插入图片描述

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import sklearn

1. 数据导入

train = pd.read_csv("data/train.csv", nrows=1000000) # 加载训练集
test = pd.read_csv("data/test.csv") # 加载测试集

2. 数据审查与处理

边审查边处理

2.1 整体情况

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
从上面两个表看出来有异常值(min,max),后面需要处理

2.2 缺失值

train.isnull().sum().sort_values(ascending=False) # 统计空值的数量,根据数量大小排序

在这里插入图片描述

test.isnull().sum().sort_values(ascending=False) # 统计空值的数量,根据数量大小排序

在这里插入图片描述

# 处理缺失值

# 删除掉train中为空的数据(10行)
train.drop(train[train.isnull().any(1)].index, axis=0, inplace=True)

# 由于缺失值占比非常小,这里直接将缺失值删除。删除缺失值之后还剩下999990条数据。
train.shape # 比原始数据少了10行

(999990, 8)

2.3 异常值

检查车费fare_amount

# 最小值为负数,这是不合理。计算’fare_amount’小于0的,一共有38个,全部将其删除。
# 查看车费这列数据(车费不可能为负数)
train['fare_amount'].describe()

在这里插入图片描述

# 统计train中车费小于0的数据有多少
from collections import Counter

Counter(train['fare_amount']<0) # 有38行数据,车费小于0

Counter({False: 999952, True: 38})

# 删除掉车费小于0的数据
train.drop(train[train['fare_amount']<0].index, axis=0, inplace=True)
# 可视化(直方图):0 < 票价 < 100
train[train.fare_amount<100].fare_amount.hist(bins=100, figsize=(14,3))
plt.xlabel('fare $USD')
plt.title("Histogram")

在这里插入图片描述

检查乘客passenger_count

# 下面查看坐车人数。max是208位乘客。 假设公交车是纽约市的“出租车”,我们认为公交车不能载208名乘客.
# 检查乘客列的数据
train['passenger_count'].describe() # max异常

在这里插入图片描述

# 查看乘客人数大于6的数据
train[train['passenger_count']>6]

在这里插入图片描述

# 删除掉这个离异值
train.drop(train[train['passenger_count']>6].index, axis=0, inplace=True)

检查上车点的经度和纬度

  1. 纬度范围:-90 ~ 90
  2. 经度范围:-180 ~ 180

快速谷歌搜索可以知道:纬度范围是-90至90,经度的范围是-180至180.下面的描述明显地显示了一些异常值。 让我们删除它们。
删除之后的训练集还有999928条记录。

train['pickup_latitude'].describe() # 查看上车点纬度数据(min和max的值异常)

在这里插入图片描述

# 纬度小于-90的数据 ( 有3行 )
train[train['pickup_latitude']<-90]

在这里插入图片描述

# 经度大于90的数据 (有9行)
train[train['pickup_latitude']>90]

在这里插入图片描述

# 删除掉这些离异值数据

train.drop(train[(train['pickup_latitude']<-90) | (train['pickup_latitude']>90)].index, axis=0, inplace=True)
# 查看上车点经度数据(min的值异常)
train['pickup_longitude'].describe()

在这里插入图片描述

# 查看经度小于-180的数据

train[train['pickup_longitude']<-180]

在这里插入图片描述

# 删除掉这些离异值

train.drop(train[train['pickup_longitude']<-180].index, axis=0, inplace=True)

检查下车点的经度和纬度

# 删除掉那些纬度小于-90,大于90的数据

train.drop(train[(train['dropoff_latitude']<-90) | (train['dropoff_latitude']>90)].index, axis=0, inplace=True)

# 删除掉那些经度小于-180, 大于180的数据

train.drop(train[(train['dropoff_longitude']<-180) | (train['dropoff_longitude']>180)].index, axis=0, inplace=True)

2.3 数据类型

train.dtypes # key和pickup_datetime似乎是对象格式的datetime列。我们将它们转换为日期时间。

在这里插入图片描述

# 日期类型转换:key, pickup_datetime

for dataset in [train, test]:
    dataset['key'] = pd.to_datetime(dataset['key']) # pandas 自带处理日期类型函数
    dataset['pickup_datetime'] = pd.to_datetime(dataset['pickup_datetime'])

处理日期数据

现在,对于EDA。以下是我的考虑 -
乘客人数会影响票价吗?
取车日期和时间会影响票价吗?
星期几会影响票价吗?
行驶距离会影响票价吗?

将日期分隔为:

  1. year
  2. month
  3. day
  4. hour
  5. day of week
dataset.shape # ??? 行数怎么变少了

(9914, 7)

dataset.head() # pickup_datetime

在这里插入图片描述

type(dataset['pickup_datetime'][0])

pandas._libs.tslibs.timestamps.Timestamp

# 增加5列,分别是:year, month, day, hour, day of week

for dataset in [train, test]:
    dataset['year'] = dataset['pickup_datetime'].dt.year
    dataset['month'] = dataset['pickup_datetime'].dt.month
    dataset['day'] = dataset['pickup_datetime'].dt.day
    dataset['hour'] = dataset['pickup_datetime'].dt.hour
    dataset['day of week'] = dataset['pickup_datetime'].dt.dayofweek

在这里插入图片描述

根据经纬度计算距离

首先,让我们将接到乘客的日期时间字段“ pickup_datetime”拆分为年、月、日期、小时、星期几。
下面再计算接到乘客的地点和乘客下车地点的距离。利用Haversine公式算得。Haversine公式表示给出纬度和经度时,我们可以计算球体中的距离(网址https://en.wikipedia.org/wiki/Haversine_formula )Haversine(θ)=sin²(θ/ 2)。利用纬度经度,地球半径R(平均半径= 6,371 km)来计算。得到结果如图所示.

# 计算公式
'''

'''
def distance(lat1, long1, lat2, long2):
    '''
    :param lat1:  字段名 str 下同
    :param long1:
    :param lat2:
    :param long2:
    :return: 距离 float
    '''
    global d
    data = [train, test] # 同时操作训练集和测试集
    for i in data:
        R = 6371  # 地球半径(单位:千米)
        phi1 = np.radians(i[lat1])
        phi2 = np.radians(i[lat2])
    
        delta_phi = np.radians(i[lat2]-i[lat1])
        delta_lambda = np.radians(i[long2]-i[long1])
    
        #a = sin²((φB - φA)/2) + cos φA . cos φB . sin²((λB - λA)/2)
        a = np.sin(delta_phi / 2.0) ** 2 + np.cos(phi1) * np.cos(phi2) * np.sin(delta_lambda / 2.0) ** 2
    
        #c = 2 * atan2( √a, √(1−a) )
        c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1-a))
    
        #d = R*c
        d = (R * c) # 单位:千米
        i['H_Distance'] = d # 给数据添加H_Distance字段
    return d

distance('pickup_latitude','pickup_longitude','dropoff_latitude','dropoff_longitude')

在这里插入图片描述

# 统计距离为0,票价为0的数据 全部为0 对模型来说没有用处

train[(train['H_Distance']==0) & (train['fare_amount']==0)]

在这里插入图片描述

# 删除
train.drop(train[(train['H_Distance']==0) & (train['fare_amount']==0)].index, axis=0, inplace=True)
# 统计距离为0,票价不为0的数据

# 原因1:司机等待乘客很长时间,乘客最终取消了订单,乘客依然支付了等待的费用;
# 原因2:车辆的经纬度没有被准确录入或缺失;

len(train[(train['H_Distance']==0) & (train['fare_amount']!=0)])

28477

# 删除
train.drop(train[(train['H_Distance']==0) & (train['fare_amount']!=0)].index, axis=0, inplace=True)

改进

【参考:Cleansing+EDA+Modelling(LGBM + XGBoost starters) | Kaggle
在这里插入图片描述

新的字段:每公里车费

根据距离、车费,计算每公里的车费

train['fare_per_mile'] = train.fare_amount / train.H_Distance

train.fare_per_mile.describe()

在这里插入图片描述

# 统计每一年的不同时间段的每小时车费

train.pivot_table('fare_per_mile', index='hour', columns='year').plot(figsize=(14, 6))
plt.ylabel('Fare $USD/mile')

在这里插入图片描述

3.模型训练和数据预测

3.1 特征选择

选择特征列,构建数据
在这里插入图片描述

X_train = train.iloc[:, [3,4,5,6,7,8,9,10,11,12,13]] # 选取某些列

在这里插入图片描述

y_train = train.iloc[:, [1]] # are_amount 车费

在这里插入图片描述

3.2 选择模型、训练、预测、评估

# 随机森林实现

from sklearn.ensemble import RandomForestRegressor

rf = RandomForestRegressor()

rf.fit(X_train, y_train)

在这里插入图片描述

rf_predict = rf.predict(test.iloc[:, [2,3,4,5,6,7,8,9,10,11,12]]) # 要和训练集选择一样的列

在这里插入图片描述

3.3 生成结果并提交

submission = pd.read_csv("data/sample_submission.csv")

submission.head()

在这里插入图片描述

# 提交

submission['fare_amount'] = rf_predict

submission.to_csv("submission_1.csv", index=False) # 成绩: 4.49170

submission.head()

在这里插入图片描述
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值