基于Python的人工智能应用案例系列(7):纽约市出租车费预测(分类)
通过这个案例,我们学习了如何基于分类问题构建深度学习模型,预测纽约市出租车费是否超过10美元。我们通过特征工程生成了重要的特征,并利用嵌入层对分类变量进行了处理。最终,我们构建了一个深度神经网络,并对模型进行了训练和评估。这个案例展示了如何将深度学习应用于实际问题中,并且提供了未来可扩展的模型保存和加载方式,便于对新数据进行推理。欢迎关注我的后续博文,我将分享更多关于人工智能、自然语言处理和计算机
在本篇文章中,我们将使用Kaggle提供的纽约市出租车费数据,构建一个基于深度学习的分类模型,预测出租车费是否超过10美元。我们将结合数据探索、特征工程、深度学习模型构建与优化,并对模型进行测试和评估。
1. 数据加载与预处理
我们从数据集中加载纽约市出租车费数据,数据包括了乘客的上车和下车的经纬度、乘车时间、乘客人数等字段。我们需要基于这些输入来预测出租车费用的分类:低于10美元或等于/高于10美元。
import pandas as pd
# 加载数据集
df = pd.read_csv('../data/NYCTaxiFares.csv')
df.head()
数据概览
数据集共有120,000条记录,包含了以下字段:
- pickup_datetime:上车时间
- pickup_latitude:上车地点纬度
- pickup_longitude:上车地点经度
- dropoff_latitude:下车地点纬度
- dropoff_longitude:下车地点经度
- passenger_count:乘客人数
- fare_class:目标变量,表示费用类别,0表示低于10美元,1表示等于或高于10美元
# 查看分类的分布
df['fare_class'].value_counts()
数据分类说明
- Class 0: 费用低于10美元
- Class 1: 费用等于或高于10美元
约有2/3的数据属于Class 0,1/3的数据属于Class 1。这个数据不算严重的类别不平衡,但我们在建模时仍需注意平衡性。
2. 特征工程
在开始建模之前,我们需要对原始数据进行一些处理,提取出有用的特征。例如,我们可以通过上车和下车的经纬度来计算出行距离,同时提取时间相关的特征(例如小时、星期几等)。
计算两点之间的距离
我们可以使用haversine公式来计算两组经纬度之间的距离,该公式适用于球面距离计算,地球可以近似看作一个球体。
import numpy as np
def haversine_distance(df, lat1, long1, lat2, long2):
"""
计算两组经纬度之间的球面距离
"""
r = 6371 # 地球平均半径,单位为千米
phi1 = np.radians(df[lat1])
phi2 = np.radians(df[lat2])
delta_phi = np.radians(df[lat2] - df[lat1])
delta_lambda = np.radians(df[long2] - df[long1])
a = np.sin(delta_phi / 2)**2 + np.cos(phi1) * np.cos(phi2) * np.sin(delta_lambda / 2)**2
c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a))
return r * c # 返回距离,单位为千米
# 应用公式,生成距离特征
df['dist_km'] = haversine_distance(df, 'pickup_latitude', 'pickup_longitude', 'dropoff_latitude', 'dropoff_longitude')
提取时间特征
通过将字符串形式的pickup_datetime
转换为时间对象,我们可以提取出时间相关的特征,如小时、上午/下午以及星期几。
df['EDTdate'] = pd.to_datetime(df['pickup_datetime'].str[:19]) - pd.Timedelta(hours=4) # 转换为美国东部时间
df['Hour'] = df['EDTdate'].dt.hour
df['AMorPM'] = np.where(df['Hour'] < 12, 'am', 'pm')
df['Weekday'] = df['EDTdate'].dt.strftime("%a")
提取时间信息后,我们的数据框将包含以下特征:
dist_km
: 乘车的行驶距离Hour
: 上车时间的小时AMorPM
: 上午或下午Weekday
: 星期几
3. 数据预处理
在进行建模前,我们还需要对分类特征进行编码,将字符串类别转换为数字表示。我们使用pandas
中的category
数据类型来转换这些列。
for col in ['Hour', 'AMorPM', 'Weekday']:
df[col] = df[col].astype('category')
# 检查转换后的数据类型
df.dtypes
通过这种转换方式,我们将会为每个分类特征分配一个整数编码,用以表示不同的类别。
4. 模型构建
嵌入层处理
我们将为分类特征构建嵌入层,通过将类别变量转换为嵌入向量,模型能够更好地学习到不同类别的相似性。
import torch
import torch.nn as nn
class TaxiFareModel(nn.Module):
def __init__(self, emb_szs, n_cont, out_sz, layers, p=0.5):
super().__init__()
self.embeds = nn.ModuleList([nn.Embedding(ni, nf) for ni,nf in emb_szs])
self.emb_drop = nn.Dropout(p)
self.bn_cont = nn.BatchNorm1d(n_cont)
layers_list = []
n_emb = sum((nf for ni, nf in emb_szs))
n_in = n_emb + n_cont
for i in layers:
layers_list.append(nn.Linear(n_in, i))
layers_list.append(nn.ReLU(inplace=True))
layers_list.append(nn.BatchNorm1d(i))
layers_list.append(nn.Dropout(p))
n_in = i
layers_list.append(nn.Linear(layers[-1], out_sz))
self.layers = nn.Sequential(*layers_list)
def forward(self, x_cat, x_cont):
embeddings = [e(x_cat[:, i]) for i, e in enumerate(self.embeds)]
x = torch.cat(embeddings, 1)
x = self.emb_drop(x)
x_cont = self.bn_cont(x_cont)
x = torch.cat([x, x_cont], 1)
return self.layers(x)
模型训练
我们使用交叉熵损失函数进行模型的训练,优化器选用Adam优化器。
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 模型训练
epochs = 300
losses = []
for epoch in range(epochs):
y_pred = model(cat_train, con_train)
loss = criterion(y_pred, y_train)
losses.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
5. 模型测试与评估
我们使用测试集进行模型评估,并计算模型的准确率。
with torch.no_grad():
y_val = model(cat_test, con_test)
loss = criterion(y_val, y_test)
print(f'测试集上的交叉熵损失: {loss.item()}')
我们还可以打印前50个预测值及其对应的实际值,来直观地检查模型的表现。
rows = 50
correct = 0
for i in range(rows):
pred_label = y_val[i].argmax().item()
true_label = y_test[i].item()
if pred_label == true_label:
correct += 1
print(f'{correct} out of {rows} = {100 * correct / rows:.2f}% correct')
6. 模型保存与加载
为了方便后续的推理和应用,我们可以将训练好的模型保存到文件中。
torch.save(model.state_dict(), 'TaxiFareClssModel.pt')
在需要时,我们可以重新加载模型并进行推理。
model2 = TaxiFareModel(emb_szs, conts.shape[1], 2, [200, 100], p=0.4)
model2.load_state_dict(torch.load('TaxiFareClssModel.pt'))
model2.eval() # 设置为评估模式
结语
通过这个案例,我们学习了如何基于分类问题构建深度学习模型,预测纽约市出租车费是否超过10美元。我们通过特征工程生成了重要的特征,并利用嵌入层对分类变量进行了处理。最终,我们构建了一个深度神经网络,并对模型进行了训练和评估。
这个案例展示了如何将深度学习应用于实际问题中,并且提供了未来可扩展的模型保存和加载方式,便于对新数据进行推理。
如果你觉得这篇博文对你有帮助,请点赞、收藏、关注我,并且可以打赏支持我!
欢迎关注我的后续博文,我将分享更多关于人工智能、自然语言处理和计算机视觉的精彩内容。
谢谢大家的支持!
更多推荐
所有评论(0)