紐約市計程車價格預測

來自專欄猴子聊數據分析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名。


推薦閱讀:
查看原文 >>
相關文章