紐約市計程車價格預測
紐約市計程車價格預測
來自專欄猴子聊數據分析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名。
推薦閱讀: