文章目录
数据集介绍
1912年4月15日,泰坦尼克号在首次航行期间撞上冰山后沉没,船上共有2224名乘客和乘务人员,最终有1502人遇难。沉船导致大量伤亡的重要原因之一是,没有足够的救生艇给乘客和船员。虽然从这样的悲剧性事故中幸存下来有一定的运气因素,但还是有一定规律可循的,一些人,比如妇女、儿童和上层人士,比其他人有更高的存活可能性。泰坦尼克号事件留下了“弥足珍贵”的数据记录。如前所述,乘客的幸存率存在一定的规律,因此这些数据记录集成了Kaggle上流行的入门机器学习的数据集。同时,又由于该数据集中的记录不完整,存在缺失值、异常值等,因此也成了很典型的练习数据分析的数据集。
数据集共有891行、12列。每条数据有12个特征,含义如下:
PassengerId
乘客IDSurvived
获救情况(1为获救,0为未获救)Pclass
乘客等级(1/2/3等舱位)Name
乘客姓名Sex
性别Age
年龄SibSp
堂兄弟/妹个数Parch
父母与小孩个数Ticket
船票信息Fare
票价Cabin
客舱Embarked
登船港口
数据处理
加载数据集
import torch
import torch.nn as nn
import pandas as pd
import matplotlib.pyplot as plt
from torch.utils.data import Dataset, DataLoader
# 加载CSV文件
train_df = pd.read_csv(r"D:\kaggle\Titanic\train.csv")
test_df = pd.read_csv(r"D:\kaggle\Titanic\test.csv")
PassengerId = test_df['PassengerId']
查看数据信息
通过查看数据集信息,分析如何对数据集进行处理。
train_df.info()
从信息中我们可以看出哪些特征有缺失值,哪些特征是非数值型特征,这样我们就能对相应的特征进行处理。
数据集合并
将训练集和测试集合并,方便后面的数据处理。
full_df = pd.concat([train_df, test_df], ignore_index=True, sort=False)
缺失值处理
full_df['Embarked'] = full_df['Embarked'].fillna(full_df['Embarked'].mode()[0])
full_df['Age'] = full_df['Age'].fillna(full_df['Age'].mean())
因为 Embarked
是非数值型特征,而 Age
是数值型特征,我们用 Embarked
的众数,Age
的平均值来填充缺失值。
特征工程
我们可以将SibSp
(船上直系兄弟姐妹和配偶的数量)和 Parch
(船上父母和子女的数量)相加,并加上1(代表乘客本人),以得到每个乘客的家庭规模,作为一个新的特征。
full_df['Family'] = full_df['SibSp'] + full_df['Parch'] + 1
删除多余数据列
full_df.drop(['PassengerId', 'Name', 'Ticket', 'Cabin','SibSp','Parch'], axis=1, inplace=True)
数据标准化
为了确保所有特征都在相同的尺度上,我们需要对数据进行标准化
full_df['Age'] = (full_df['Age'] - full_df['Age'].mean()) / full_df['Age'].std()
full_df['Fare'] = (full_df['Fare'] - full_df['Fare'].mean()) / full_df['Fare'].std()
特征转换
我们需要对非数值型特征进行编码,将其转换为数值型特征
full_df['Sex'] = full_df['Sex'].map({'male': 1, 'female': 0})
full_data = pd.get_dummies(full_df).astype(float)
分离数据集
train_data = full_data[full_data['Survived'].notnull()]
test_data = full_data[full_data['Survived'].isnull()]
经过数据处理后的数据集是这样的。
构建数据集
定义超参数
batch_size = 32
learning_rate = 0.05
epochs = range(1,1001)
构建数据集
class TitanicDataset(Dataset):
def __init__(self, data):
self.data = data
self.len = len(data)
# 将数据转换为张量
self.x_data = torch.tensor(data.iloc[:, 1:].values, dtype=torch.float32)
self.y_data = torch.tensor(data['Survived'].values, dtype=torch.float32).view(-1, 1)
def __getitem__(self, index):
return self.x_data[index], self.y_data[index]
def __len__(self):
return self.len
创建数据加载器
train_dataset = TitanicDataset(train_data)
dataloader = DataLoader(dataset=train_dataset, shuffle=True, batch_size=batch_size)
模型训练
定义模型
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.model = nn.Sequential(
nn.Linear(train_dataset.x_data.shape[1], 16),
nn.Sigmoid(),
nn.Linear(16, 4),
nn.Sigmoid(),
nn.Linear(4, 1),
nn.Sigmoid(),
)
def forward(self, x):
return self.model(x)
# 实例化模型
model = Model()
定义损失函数和优化器
criterion = nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
其中 BCELoss 主要用于二分类问题
模型训练
losses = [] # 用于保存损失值
for epoch in epochs:
total_loss = 0
for inputs, labels in dataloader:
optimizer.zero_grad() # 清除梯度
outputs = model(inputs)
loss = criterion(outputs, labels) # 计算损失
total_loss += loss.item()
loss.backward()
optimizer.step() # 更新模型参数
if epoch % 10 == 0:
print(f'Epoch: 【{epoch}/{max(epochs)}】, Loss: {total_loss}')
losses.append(total_loss)
# 可视化损失
plt.plot(epochs, losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss Over Epochs')
plt.show()
# 计算训练集准确率
with torch.no_grad():
outputs = (model(train_dataset.x_data) > 0.5).float()
accuracy = (outputs == train_dataset.y_data.float()).float().mean().item()
print(f'Training Accuracy: {accuracy:.4f}')
训练的可视化结果如下 :
结果预测
# 预测测试集
test_dataset = TitanicDataset(test_data)
predictions = (model(test_dataset.x_data).detach().numpy() > 0.5).astype(int)
# 输出预测结果
output_df = pd.DataFrame({'PassengerId': PassengerId, 'Survived': predictions.flatten()})
output_df.to_csv("D:\kaggle\Titanic\predict.csv", index=False)
将结果在kaggle上提交后的score是0.78468