纽约出租车计费问题:一个简单的线性模型

机器学习案例详解的直播互动平台——
机器学习训练营(qq群号:696721295)
下期直播案例预告:大数据预测商品的销售量波动趋势

案例背景

该案例是一个美国纽约市出租车的行程计费问题。给定乘客上、下车的位置信息,你要根据行程距离,建立模型预测出租车的车费。该模型可以扩展应用于出租车车费定价、阶梯价格设定等问题。

  • 案例来源: Google云课程

  • 代码实现: Python

数据描述

ID

  • key 行识别符字符串。

特征

  • pickup_datetime 出租车行程开始时间

  • pickup_longitude 出租车行程开始经度坐标

  • pickup_latitude 出租车行程开始纬度坐标

  • dropoff_longitude 出租车行程结束经度坐标

  • dropoff_latitude 出租车行程结束纬度坐标

  • passenger_count 乘客数

目标变量

  • fare_amount 车费

数据准备

我们想在训练集train.csv上建立预测模型,所以首先加载训练数据。由于整个训练集特别庞大,共有55M行。根据内存容量大小,我们选择加载100万行的数据子集。

# Initial Python environment setup...
import numpy as np # linear algebra
import pandas as pd # CSV file I/O (e.g. pd.read_csv)
import os # reading the input files we have access to

train_df =  pd.read_csv('../input/train.csv', nrows = 10_000_000)
print(train_df.dtypes)

纽约出租车计费问题:一个简单的线性模型
我们想使用经度、纬度坐标定义一个行程向量。为此,我们产生两个新的特征,分别表示经度、纬度的距离。

# Given a dataframe, add two new features 'abs_diff_longitude' and
# 'abs_diff_latitude' reprensenting the "Manhattan vector" from
# the pickup location to the dropoff location.
def add_travel_vector_features(df):
    df['abs_diff_longitude'] = (df.dropoff_longitude - df.pickup_longitude).abs()
    df['abs_diff_latitude'] = (df.dropoff_latitude - df.pickup_latitude).abs()

add_travel_vector_features(train_df)
print(train_df.head())

纽约出租车计费问题:一个简单的线性模型

删除缺失行

我们看一看训练集里是否有缺失项(NaN)

print(train_df.isnull().sum())

纽约出租车计费问题:一个简单的线性模型
由于缺失项很少,我们直接删除它们所在的数据行。

print('Old size: %d' % len(train_df))
train_df = train_df.dropna(how = 'any', axis = 'rows')
print('New size: %d' % len(train_df))

纽约出租车计费问题:一个简单的线性模型
纽约出租车计费问题:一个简单的线性模型

线性模型

我们在训练集上建立一个简单的线性模型预测车费。模型定义为

y=Xwy=X \cdot w

其中,XX是输入特征矩阵,由两个GPS坐标差和1向量组成。yy是目标变量fare_amount, ww是估计向量。我们写一个函数组建这些。

# Construct and return an Nx3 input matrix for our linear model
# using the travel vector, plus a 1.0 for a constant bias term.
def get_input_matrix(df):
    return np.column_stack((df.abs_diff_longitude, df.abs_diff_latitude, np.ones(len(df))))

train_X = get_input_matrix(train_df)
train_y = np.array(train_df['fare_amount'])

print(train_X.shape)
print(train_y.shape)

纽约出租车计费问题:一个简单的线性模型
纽约出租车计费问题:一个简单的线性模型
现在,我们使用numpy的lstsq库函数找到最优的权向量ww.

# The lstsq function returns several things, and we only care about the actual weight vector w.
(w, _, _, _) = np.linalg.lstsq(train_X, train_y, rcond = None)
print(w)

它实际上等价于ww的最小二乘估计:

w=(XX)1Xyw=(X'X)^{-1}X'y

w_OLS = np.matmul(np.matmul(np.linalg.inv(np.matmul(train_X.T, train_X)), train_X.T), train_y)
print(w_OLS)

纽约出租车计费问题:一个简单的线性模型
现在,我们可以加载检验集,并将该模型用于检验集上预测车费。

改善的想法

  • 使用输入数据里的更多特征。

这里,我们仅使用了开始/结束的GPS坐标。可以尝试加入乘车时间、乘客数等特征改善模型。

  • 使用绝对坐标而不是相对坐标。

这里,我们仅使用了开始到结束点的距离。可以考虑上、下车的GPS坐标作为预测变量。

  • 排除离群点。

  • 使用完整的数据集。