一、背景
泰坦尼克号的沉没是历史上最臭名昭著的沉船事件之一。
1912年4月15日,在其处女航期间,这艘被广泛认为“永不沉没”的RMS泰坦尼克号与冰山相撞后沉没。不幸的是,没有足够的救生艇供船上所有人使用,导致2224名乘客和船员中有1502人死亡。
虽然幸存下来有一些运气的因素,但似乎有些群体比其他群体更可能幸存下来。
在这个挑战中,我们要求你建立一个预测模型来回答这个问题:“什么样的人更有可能生存?”使用乘客数据(如姓名、年龄、性别、社会经济阶层等)。
二、数据
在本次比赛中,您将获得两个类似的数据集,其中包括乘客姓名、年龄、性别、社会经济地位等信息。一个训练数据集另一个为测试数据集。
训练集上将包含所有乘客(准确说是891)的详细信息,重要的是它揭露了乘客是否生存。
测试集上包含了类似的信息,但是并没有说明乘客是否生存,你的任务就是进行预测。
三、数据处理
Pclass(船舱等级):
“1”头等舱,“2”二等舱,“3”三等舱。
Cabin(船舱)
Sex(性别):
“male”男性,"female"女性。
Age(年龄)
SibSp(兄弟姐妹配偶个数)
Parch(父母小孩个数)
Ticket(船票)
Fare(船票价格)
Embarked(上船港口)
我们可以从数据中看到,有利于分类的数据是Pclass,Sex,Age,SlbSp,Parch,Fare。因为Age缺失了部分数据量,暂时先不考虑对缺失值进行填充。也就是说我们只考虑Pclass,Sex,SlbSp,Parch,Fare这五个变量对最后结果的影响。
四、加载数据
使用Dataset加载数据
从filepath路径将数据读取为pd,再通过pd->numpy-torch的转换,分割数据,将需要的feature保留下来,再单独保留下是否生存作为y_data的值。
先使用Dataset读取文件信息,再通过DataLoader装载数据,这里选择一个batch_size为32,打乱顺序的方式。
class TitanicDataset(Dataset):
def __init__(self, filepath):
xy = pd.read_csv(filepath)
self.len = xy.shape[0]
feature = ["Pclass", "Sex", "SibSp", "Parch", "Fare"]
self.x_data = torch.from_numpy(np.array(pd.get_dummies(xy[feature])))
self.y_data = torch.from_numpy(np.array(xy["Survived"]))
def __getitem__(self, index):
return self.x_data[index], self.y_data[index]
def __len__(self):
return self.len
dataset = TitanicDataset('titanic/train.csv')
train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True, num_workers=0)
五、构建模型
使用两层线性层将(x.shape[0],6)的数据依次映射为(6,3),(3,1)的数据,其中采用sigmoid作为激活层,对数据进行非线性处理。在测试函数中,将最后通过激活函数输出的值,根据sigmoid函数的特性,做一个判断,即>0.5的值判为1,<0.5的值判为0.
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear1 = torch.nn.Linear(6, 3)
self.linear2 = torch.nn.Linear(3, 1)
self.sigmoid = torch.nn.Sigmoid()
def forward(self, x):
x = self.sigmoid(self.linear1(x))
x = self.sigmoid(self.linear2(x))
return x
def test(self, x):
with torch.no_grad():
x = self.sigmoid(self.linear1(x))
x = self.sigmoid(self.linear2(x))
y = []
for i in x:
if i > 0.5:
y.append(1)
else:
y.append(0)
return y
六、选择损失和梯度下降的方法
采用BCE(二分类交叉熵损失)作为损失函数,SGD作为梯度下降的方法。
model = Model()
criterion = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
七、训练
定义训练的次数epoch,在循环内,每次都从DataLoader中按照batch_size读取训练的数据x和测试标签y,再根据一般模式的运行规律,进行前馈,损失,反馈,梯度下降。
if __name__ == '__main__':
loss_list = []
for epoch in range(1000):
for i, (inputs, labels) in enumerate(train_loader, 0):
inputs = inputs.float()
labels = labels.float()
y_pred = model(inputs)
y_pred = y_pred.squeeze(-1)
loss = criterion(y_pred, labels)
print(epoch, i, loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
loss_list.append(loss.item())
plt.plot(range(1000), loss_list)
plt.xlabel('Epoch')
plt.ylabel('Cost')
plt.show()
八、测试
依次进行读取数据,分割特征,测试。在测试中也就是根据之前写的测试函数,通过两个;隐藏层,再根据sigmoid函数的输出特性,判定最后需要赋予的标签。
test_data = pd.read_csv('titanic/test.csv')
feature = ["Pclass", "Sex", "SibSp", "Parch", "Fare"]
test = torch.from_numpy(np.array(pd.get_dummies(test_data[feature])))
y = model.test(test.float())
九、输出
output = pd.DataFrame({'PassengerId': test_data.PassengerId, 'Survived': y})
output.to_csv('my_predict.csv', index=False)
十、上传测试文件,获取分数
最后的正确率大概在0.75598左右
十一、优化思考
在后续的任务工作中,想要提高正确率一般有两种办法。
第一个是通过数据分析。因为有些数据是明显不符合“大众”,这些数据要考虑是否进行删除,同时如“Age”这一个数据,因为它有很多缺失值,我们并没有在本次建模中考虑纳入选择,但它也是不可以省略的一个数据。如何填补缺失值也是我们要考虑的。
第二个办法就是优化模型,寻找合适的超参数。