入坑机器学习–kaggle泰坦尼克号

发布于 2023-07-08  367 次阅读


前言

Kaggle是一个旨在促进数据科学和机器学习发展的在线平台,它通过举办数据科学竞赛、提供公开数据集、分享学习资源和建立社区来吸引和连接全球的数据科学家和机器学习工程师。在Kaggle上,用户可以参与竞赛、解决实际问题、分享和学习最佳实践,并与其他用户交流和建立联系,从而推动数据科学的创新和发展。

Kaggle泰坦尼克号竞赛是Kaggle平台上最著名的竞赛之一。这个竞赛的目标是通过乘客的特征数据,如性别、年龄、船舱等级等,来预测乘客在泰坦尼克号沉船事故中的生存情况。参赛者需要使用训练数据集进行模型训练,并在测试数据集上进行预测。该竞赛不仅提供了一个实际问题的背景,还可以帮助参与者学习和应用数据处理、特征工程、模型选择和评估等数据科学技术。

数据处理

kaggle的官网提供了三个csv文件,一个是训练数据,
一个是测试数据,还有一个是样例答案,有趣的是样例答案有77%的正确率,我自己的逻辑回归第一次只有72%的正确率(

先来看一下测试数据train.csv,泰坦尼克号的train.csv文件是Kaggle泰坦尼克号竞赛中提供的训练数据集,包含了891名乘客的信息。

该数据集包含以下列:

PassengerId:乘客的唯一标识符。
Survived:乘客是否生存,0表示未生存,1表示生存(目标变量)。
Pclass:乘客的船舱等级,分为1、2和3等级。
Name:乘客的姓名。
Sex:乘客的性别。
Age:乘客的年龄。
SibSp:乘客在船上的兄弟姐妹/配偶数量。
Parch:乘客在船上的父母/子女数量。
Ticket:乘客的船票号码。
Fare:乘客支付的船票费用。
Cabin:乘客的船舱号码。
Embarked:乘客登船的港口,有三个选项:C表示Cherbourg,Q表示Queenstown,S表示Southampton。

接着我们看一下数据的具体情况

import pandas as pd

data = pd.read_csv("titanic/train.csv")
print(data.count())
PassengerId    891
Survived       891
Pclass         891
Name           891
Sex            891
Age            714
SibSp          891
Parch          891
Ticket         891
Fare           891
Cabin          204
Embarked       889
dtype: int64

然后发现Age,Cabin,Embarked有缺失。考虑到Name,Cabin啥的不好处理,我就直接把它扔了(但是高分的大佬似乎都从里面提取出了有用信息,可能这就是我菜的原因吧(

接下来补全缺失数据就行啦

先把要用的一堆模块导进来(

import torch
from torch.utils.data import *
import numpy as np
import torch.nn as nn
import torch.optim as optim
import pandas as pd

从csv中读入数据

# 数据预处理
titanic_train_data = pd.DataFrame(pd.read_csv("titanic/train.csv"))
titanic_test_data = pd.DataFrame(pd.read_csv("titanic/test.csv"))

由于有些数据是字符,因此我们要把它们映射成数字

titanic_train_data['Sex'] = titanic_train_data['Sex'].replace(
    {'male': 1, 'female': 2})
titanic_train_data['Embarked'] = titanic_train_data['Embarked'].replace({
    'S': 1,
    'C': 2,
    'Q': 3
})

titanic_test_data['Sex'] = titanic_test_data['Sex'].replace(
    {'male': 1, 'female': 2})
titanic_test_data['Embarked'] = titanic_test_data['Embarked'].replace({
    'S': 1,
    'C': 2,
    'Q': 3
})

之后就是填缺省数值,年龄填成了平均数,乘客登船的港口我用了众数

# 训练数据
titanic_train_data['Age'] = titanic_train_data['Age'].replace(
    np.nan, titanic_train_data['Age'].mean())
titanic_train_data['Embarked'] = titanic_train_data['Embarked'].replace(
    np.nan, titanic_train_data['Embarked'].mode()[0])
# 测试数据
titanic_test_data['Age'] = titanic_test_data['Age'].replace(
    np.nan, titanic_test_data['Age'].mean())
titanic_test_data['Embarked'] = titanic_test_data['Embarked'].replace(
    np.nan, titanic_test_data['Embarked'].mode()[0])

# 划分特征和目标
x = titanic_train_data[['Pclass', 'Sex', 'Age',
                        'SibSp', 'Parch', 'Embarked']]
y = titanic_train_data['Survived']

模型实现

我刚学几天,啥都不会(

因为还不太确定是不是逻辑回归,所以我照葫芦画瓢划分了训练集和测试集,80%的数据用于训练

indices = np.arange(len(titanic_train_data))
np.random.shuffle(indices)
train_indices = indices[:int(0.8 * len(titanic_train_data))]
test_indices = indices[int(0.8 * len(titanic_train_data)):]

x_train = torch.tensor(x.iloc[train_indices].values).float()
x_test = torch.tensor(x.iloc[test_indices].values).float()
y_train = torch.tensor(y.iloc[train_indices].values).float()
y_test = torch.tensor(y.iloc[test_indices].values).float()

之后定义一个输入特征维度为7,输出特征维度为1的神经网络,学习率不知道设什么,我设了0.01

# 定义模型
net = nn.Linear(7, 1)  # 输入特征维度为7,输出特征维度为1
# # 定义损失函数和优化器
loss = nn.BCEWithLogitsLoss()
optimizer = optim.SGD(net.parameters(), lr=0.01)

创建了一个训练数据加载器,可以在训练模型时使用它来批量读取数据。

train_dataset = TensorDataset(x_train, y_train)
train_loader = DataLoader(
    train_dataset, batch_size=10, shuffle=True)

这段代码的目的是将训练数据(输入特征和标签)打包成TensorDataset对象,并使用DataLoader创建一个训练数据加载器,以便在训练模型时方便地从数据加载器中获取批量数据。
batch_size参数表示每个批次的样本数量,这里设置为10,即每次加载10个样本。
shuffle参数表示是否在每个Epoch(训练迭代周期)之前对数据进行洗牌,即随机打乱数据的顺序。
之后循环500次,使用小批量随机梯度下降

num_epochs = 100
for epoch in range(num_epochs):
    # 前向传播
    for (x_batch, y_batch) in train_loader:
        y_batch = y_batch.reshape(-1, 1)
        y_pred = net(x_batch)
        l = loss(y_pred, y_batch)
        # 反向传播和优化
        optimizer.zero_grad()
        l.backward()
        optimizer.step()
    if (epoch+1) % 10 == 0
        print(f'Epoch: {epoch+1}, Loss: {l.item()}')

# 进行测试--written by ChatGPT
test_data = TensorDataset(x_test, y_test)
test_loader = DataLoader(test_data, batch_size=16)
total_correct = 0
total_samples = 0
with torch.no_grad():
    for (batch_X, batch_y) in test_loader:
        outputs = net(batch_X)
        predicted = torch.round(torch.sigmoid(outputs))
        total_correct += (predicted == batch_y.unsqueeze(1)).sum().item()
        total_samples += batch_y.size(0)
accuracy = total_correct / total_samples
print(f'Test Accuracy: {accuracy:.2f}')

准确率看玄学吧,73%上下跳动,就是训练的时候loss的值一直在反复横跳,不知道怎么回事。

行吧,之后对答案来一遍就行了

# 生成答案
test_data = titanic_test_data[['Pclass', 'Sex', 'Age',
                               'SibSp', 'Parch', 'Fare', 'Embarked']]
X_test_data = torch.Tensor(test_data.values).float()
number = []
survived = []
with torch.no_grad():
    for i in range(len(X_test_data)):
        output = net(X_test_data[i])
        predicted = torch.round(torch.sigmoid(output)).int()
        print(predicted.item())
        number.append(892 + i)
        survived.append(predicted.item())

answer = pd.DataFrame({'PassengerId': number, 'Survived': survived})
answer.to_csv("answer.csv", index=False, sep=',')