纽约市计程车价格预测

来自专栏猴子聊数据分析7 人赞了文章

在开始之前,对项目做个简单的了解。这是kaggle在2个月前推出的项目,数据栏位不多,但是数据量蛮大。项目目的是根据时间和距离预测计程车车费。

下图为本次项目的步骤和思路

一、提出问题

目标很明确,就是预测乘坐计程车的费用。

二、理解数据

key - 唯一的ID栏位

pickup_datetime - 表示计程车开始的时间。

pickup_longitude - 计程车开始的经度坐标。

pickup_latitude - 计程车开始的纬度坐标。

dropoff_longitude - 计程车行程结束的经度坐标。

dropoff_latitude - 计程车行程结束的纬度坐标。

passenger_count - 表示乘坐计程车的乘客数量。

fare_amount - 需要预测的车费。

三、数据清洗

1、导入数据

import numpy as npimport pandas as pdtrain = pd.read_csv("D://train.csv",nrows=1000000)test = pd.read_csv("D://test.csv")

2、查看数据基本情况

训练集有100万行数据,8个栏位。预测集有9914行数据,7个栏位。

train.head()

训练集train的描述性分析

train.describe()

从中我们可以发现,fare_amout存在小于0的异常值。经纬度都有特别大和特别小的异常值。乘车人数passenger_count存在极大值208的异常。

3、处理缺失值

分别对train和test缺失值求和并降序排列。

train.isnull().sum().sort_values(ascending=False)

test.isnull().sum().sort_values(ascending=False)

可以发现在train里存在10条缺失经纬度的数据,我们作删除处理。

train = train.drop(train[train[dropoff_latitude].isnull()].index,axis=0) #删除10条含缺失值的数据

4、处理异常值

1)fare_amount(车费)

首先,对向量fare_amount异常值处理。车费少于0的删掉,因为司机不可能倒贴你钱。

train = train.drop(train[train[fare_amount]<0].index,axis=0)

再看看,fare_amount总体情况。

train[fare_amount].describe()

可以发现,车费最高价格为500美元。

2)passenger_count(乘客数)

之前,训练集的描述性分析里,我们已经看出passenger_count没有负值。由于限载等因素的影响,超过6人的属异常值。

train[train[passenger_count]>6]

显然载客数208,是不符合实际的,我把它作删除处理。

train = train.drop(train[train[passenger_count]>6].index,axis=0)

再次确认一下,passenger_count数据

train[passenger_count].describe()

这时passenger_count最大值为6,最小值为0,符合实际情况。

3)经纬度

再来看一下,乘客上车地点的经纬度和乘客下车地点的经纬度是否存在异常。

train[pickup_latitude].describe()

train[pickup_longitude].describe()

查看经纬度的最大、最小值发现,经纬度数据存在极端值。

根据实际情况,我把经纬度范围限制在,纬度在(-90,90)度之间,经度在(-180,180)度之间。超过范围的,作删除处理。

train = train.drop(((train[train[pickup_latitude]<-90])|(train[train[pickup_latitude]>90])) .index,axis=0)train = train.drop(((train[train[pickup_longitude]<-180])|(train[train[pickup_longitude]>180])) .index,axis=0)train = train.drop(((train[train[dropoff_latitude]<-90])|(train[train[dropoff_latitude]>90])) .index,axis=0)train = train.drop(((train[train[dropoff_longitude]<-180])|(train[train[dropoff_longitude]>180]) ).index,axis=0)train.shape

5、数据类型转化

首先,检查一下数据类型是否有问题,主要是查看是否影响建模。

train.dtypes

发现,key、pickup_datetime是字元串型,我们需要转化成时间类型。

train[key]=pd.to_datetime(train[key])train[pickup_datetime]=pd.to_datetime(train[pickup_datetime])

test数据集一同转化

test[key]=pd.to_datetime(test[key])test[pickup_datetime]=pd.to_datetime(test[pickup_datetime])

查看转化结果:

6、特征工程

特征工程,目的是最大限度地从原始数据中提取特征以供演算法和模型使用。

特征一:

数据集里只有乘客上车地的经纬度,和下车地的经纬度。我们知道计程车走的不可能都是直线,所以两点经纬度相减得到的直线距离,并不是很准确。但我们也不知道计程车走过的实际路程,只能尽可能的靠近实际,所以我的想法是计算两点间的球面距离。

自定义一个计算函数:

def haversine_distance(lat1, long1, lat2, long2): data = [train, test] for i in data: R = 6371 #radius of earth in kilometers 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 = sin2((φB - φA)/2) + cos φA . cos φB . sin2((λ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) #in kilometers i[H_Distance] = d return d

然后带入四个参数

haversine_distance(pickup_latitude, pickup_longitude, dropoff_latitude, dropoff_longitude)

再查看一下新构建的特征向量情况

train[H_Distance].describe()

通过H_Distance的描述性统计值,可以看出H_Distance存在异常值。最大值太大了。

让我们通过探索性分析,处理H_Distance向量的异常值。

H_Distance,异常值处理:

  • 删除车费为0,起点经纬度为零的数据

train.loc[((train[pickup_latitude]==0)&(train[pickup_longitude]==0))&((train[dropoff_latitude] !=0) & (train[dropoff_longitude]!=0))& (train[fare_amount]==0)]

删除这条数据

train = train.drop(train.loc[((train[pickup_latitude]==0) & (train[pickup_longitude]==0))&((train[dropoff_latitude]!=0)& (train[dropoff_longitude]!=0)) & (train[fare_amount]==0)].index, axis=0)

  • 车费为0,下车地经纬度是0的数据

train.loc[((train[pickup_latitude]!=0) & (train[pickup_longitude]!=0))&((train[dropoff_latitude]==0) & (train[dropoff_longitude]==0))&(train[fare_amount]==0)]

删除这3条数据

train = train.drop(train.loc[((train[pickup_latitude]!=0) & (train[pickup_longitude]!=0))&((train[dropoff_latitude]==0)&(train[dropoff_longitude]==0)) & (train[fare_amount]==0)].index, axis=0)

我们以200为标量,距离大于200的,作删除处理。

train = train.drop(train.loc[(train[H_Distance]>200)&(train[fare_amount]!=0)].index,axis=0)

  • 距离为0,车费小于2.5(起步价)

train.loc[(train[H_Distance]==0) & (train[fare_amount] < 2.5)]

距离为0,车费小于2.5,我们无法得到有价值的数据,所以删除。

train = train.drop(train.loc[(train[H_Distance]==0) & (train[fare_amount] < 2.5)].index,axis=0)

  • 距离为0,车费大于3。距离为0却产生费用,可能距离数据缺失了,我们需要通过车费来计算距离。

F3h0 = train.loc[(train[fare_amount]>3)&(train[H_Distance]==0)]

F3h0[H_Distance] = F3h0.apply(lambda row: ((row[fare_amount]-2.50)/1.56), axis=1)train.update(F3h0)

  • 反过来,距离不等于0,但是车费等于0,我们需要用公式计算车费。

H1f0 = train.loc[(train[H_Distance]!=0) & (train[fare_amount]==0)]H1f0[fare_amount] = H1f0.apply(lambda row: (row[H_Distance]*1.56+2.5),axis=1)train.update(H1f0)

特征二:

观察发现pickup_datetime是乘客上车时间,里面包含了年、月、日、小时。可以从里面提取出年、月、日、小时、星期几。

data = [train,test]for i in data: i[Year] = i[pickup_datetime].dt.year i[Month] = i[pickup_datetime].dt.month i[Date] = i[pickup_datetime].dt.day i[Day of week] = i[pickup_datetime].dt.dayofweek i[Hour] = i[pickup_datetime].dt.hour

我们把已经提取出特征工程的key和pickup_datetime删除掉。

train = train.drop([key,pickup_datetime], axis = 1)test = test.drop([key,pickup_datetime], axis = 1)

#导入包import seaborn as snsimport matplotlib.pyplot as plt

用散点图查看,乘车人数与价格关系。

plt.figure(figsize=(15,7))plt.scatter(x=train[passenger_count],y=train[fare_amount],s=1.5)plt.title(乘车人数与价格关系)plt.xlabel(乘车人数)plt.ylabel(价格)plt.show()

用散点图查看,日期与价格关系。

plt.figure(figsize=(15,7))plt.scatter(x=train[Date],y=train[fare_amount],s=1.5)plt.title(日期与价格关系)plt.xlabel(日期)plt.ylabel(价格)plt.show()

用散点图查看,时间与价格关系。

plt.figure(figsize=(15,7))plt.scatter(x=train[Hour],y=train[fare_amount],s=1.5)plt.title(时间与价格关系)plt.xlabel(时间)plt.ylabel(价格)plt.show()

用散点图查看,星期与价格关系。

plt.figure(figsize=(15,7))plt.scatter(x=train[Day of week],y=train[fare_amount],s=1.5)plt.title(星期与价格关系)plt.xlabel(星期)plt.ylabel(价格)plt.show()

四、构建模型

x_train = train.iloc[:,train.columns!=fare_amount] #测试集 xy_train = train[fare_amount].values #测试集 yx_test = test #预测数据

导入机器学习模型

from sklearn.ensemble import RandomForestRegressorrf = RandomForestRegressor()

训练数据

rf.fit(x_train, y_train)

预测数据

rf_predict = rf.predict(x_test)

保存预测数据,csv格式

submission = pd.read_csv(D://sample_submission.csv)submission[fare_amount] = rf_predictsubmission.to_csv(submission_1.csv, index=False)

五、提交数据

提交数据获取排名,425名。


推荐阅读:
查看原文 >>
相关文章