使用深度学习对kaggle上的titanic项目,使用乘客数据(如姓名、年龄、性别、社会经济阶层等),建立一个模型预测泰坦尼克号沉船上哪些乘客能够幸存。
该项目的训练集与测试集在官网下载即可:https://www.kaggle.com/c/titanic,在完成后还可以上传你的预测文件参与全世界排名。
我们本次编程使用pytorch进行。本次将搭建一个三层神经网络,relu->relu->sigmoid,使用batch优化。
下面是本次编程使用的模块:
import numpy as np
import matplotlib.pyplot as plt
import torch
import pandas as pd
import csv
我们第一步先进行数据处理,先导入数据集
# 导入数据集
train_filepath = r"train.csv"
train_data = pd.read_csv(train_filepath)
test_filepath = r"test.csv"
test_data = pd.read_csv(test_filepath)
在训练集train.csv中我们有很多特征,并且数据不全我们需要对其进行处理:
(1)PassengerID:乘客的ID,是无关信息。
(2)Survived:乘客是否幸存,取值为0或1,是我们预测/分类的目标。
(3)Pclass:客舱等级,可能蕴含着乘客的阶层、乘客客舱的位置等信息,比较重要。
(4)Name: 姓名,是无关信息。
(5)Sex:性别,灾难来临时常让妇女儿童先走,而同等条件女性体力普遍弱于男性,这些因素都会影响到一名乘客幸存的可能性,因此比较重要。
(6)Age:年龄,较为重要,理由同上。
(7)Parch:直系亲友数目,比较重要。
(8)SibSp:旁系亲友数目,比较重要。
(9)Ticket:票编号,是无关信息。
(10)Fare:票价,可能会反映乘客的社会阶层等。
(11)Cabin:客舱编号,可能会反映客舱位置等,但由于缺省太多,数据量很小不具有代表性,可以视为噪音剔除。
(12)Embarked:上船的港口编号。
在剔除了一些数据后,是否会因信息损失而降低模型的准确度?例如乘客的姓名可能暗含船上乘客之间家庭的关系。实际上我们的模型本来就是建立在不完全观测上(比如我们不知道船上的一对男女乘客有没有发生像Jack和Rose那样的故事),不确定性是必然存在的,把握主要矛盾,舍弃噪音信息是建立模型的一个好思路。
不了解one-hot的同学看这里:机器学习:数据预处理之独热编码(One-Hot)
# 训练数据预处理
def PreprocessTrainData(all_pf):
# 预处理1:去掉无关特征
cols = ["Survived", "Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]
all_pf = all_pf[cols]
# 预处理2:填充确实特征并标准化
age_mean = all_pf["Age"].mean()
all_pf["Age"] = all_pf["Age"].fillna(age_mean)
fare_mean = all_pf["Fare"].mean()
all_pf["Fare"] = all_pf["Fare"].fillna(fare_mean)
# 预处理3:性别编码
all_pf["Sex"] = all_pf["Sex"].map({"female": 0, "male": 1}).astype(int)
# 预处理4:登港地点转换为one-hot编码
x_OneHot_df = pd.get_dummies(data=all_pf, columns=["Embarked"])
ndarray = x_OneHot_df.values
# 预处理5:全体特征标准化,标签向量化
label = ndarray[:, 0]
label = label.reshape(label.shape[0], 1)
features = ndarray[:, 1:]
mean = features.mean(axis=0)
features -= mean
std = features.std(axis=0)
features /= std
return label, features
# 测试数据预处理
def PreprocessTestData(all_df):
# 预处理1:筛除无关特征
cols = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]
all_df = all_df[cols]
# 预处理2:填充缺失特征并标准化特征
age_mean = all_df["Age"].mean()
all_df["Age"] = all_df["Age"].fillna(age_mean)
fare_mean = all_df["Fare"].mean()
all_df["Fare"] = all_df["Fare"].fillna(fare_mean)
# 预处理3:性别编码0-1
all_df["Sex"] = all_df["Sex"].map({"female": 0, "male": 1}).astype(int)
# 预处理4:登港地点转换为one-hot编码
x_OneHot_df = pd.get_dummies(data=all_df, columns=["Embarked"])
ndarray = x_OneHot_df.values
# 预处理5:全体特征标准化,标签向量化
features = ndarray
mean = features.mean(axis=0)
features -= mean
std = features.std(axis=0)
features /= std
return features
# 转换为张量
y_train, x_train = PreprocessTrainData(train_data)
x_train_tenser = torch.from_numpy(x_train)
y_train_tenser = torch.from_numpy(y_train)
x_test = PreprocessTestData(test_data)
x_test_tenser = torch.from_numpy(x_test)
# 构造网络模型
class model(torch.nn.Module):
def __init__(self):
super(model, self).__init__()
self.linear1 = torch.nn.Linear(9, 6)
self.linear2 = torch.nn.Linear(6, 3)
self.linear3 = torch.nn.Linear(3, 1)
self.sigmoid = torch.nn.Sigmoid()
self.relu = torch.nn.ReLU()
def forward(self, x):
x = self.relu(self.linear1(x))
x = self.relu(self.linear2(x))
x = self.sigmoid(self.linear3(x))
return x
model = model()
# 构造优化器和损失函数
criterion = torch.nn.BCELoss(reduction="mean")
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
cost_list = []
# 开始训练
for epoch in range(1000):
# 正向传播
y_pred = model(x_train_tenser.float())
loss = criterion(y_pred, y_train_tenser.float())
cost_list.append(loss.item())
print("epoch:", epoch, "cost:", loss.item())
# 反向传播
optimizer.zero_grad()
loss.backward()
# 更新参数
optimizer.step()
y_pred = model(x_test_tenser.float())
y_pred = np.array(y_pred.data)
for i in range(y_pred.shape[0]):
if y_pred[i, 0] > 0.5:
y_pred[i, 0] = 1
else:
y_pred[i, 0] = 0
with open(r"gender_submission.csv", 'w+', newline='') as f:
csv_file = csv.writer(f)
csv_file.writerows(y_pred)
plt.plot(cost_list)
plt.xlabel("epoch")
plt.ylabel("cost")
plt.show()
epoch: 1 cost: 0.672267496585846
epoch: 2 cost: 0.6718555688858032
epoch: 3 cost: 0.6714616417884827
...
epoch: 997 cost: 0.39888277649879456
epoch: 998 cost: 0.39885351061820984
epoch: 999 cost: 0.39881929755210876
本次结果在kaggle上取得前23%的结果,总体来说还不错,毕竟使用的是未经任何优化的梯度下降法。
此外可以留一部分验证集,测试模型的泛化能力。
源码在此
kaggle泰坦尼克号深度学习实战