泰坦尼克号幸存者预测
- 1、特征工程概述
- 2、数据预处理
- 3、特征选择与提取
- 4、建模与预测
1、特征工程概述
在上篇 泰坦尼克号幸存者数据分析 中,我们对泰坦尼克号的幸存者做了数据分析,通过性别、年龄、船舱等级等不同维度对幸存者进行了分类统计,回答了哪些人可能成为幸存者
本文我们将对泰坦尼克号数据集应用特征工程、训练分类模型并对幸存者进行预测
特征工程是机器学习工作流程中重要的组成部分,它是将原始数据转化成模型可理解的形式的过程。如何基于给定数据来发挥更大的数据价值就是特征工程要做的事情
在2016年的一项调查中发现,数据科学家的工作中,有超过80%的时间都在获取、清洗和组织数据;构造机器学习流水线的时间不到20%。可见特征工程的重要性
特征工程在机器学习流程中的位置如下:
特征工程处在原始数据和特征之间。它的任务就是将原始数据翻译成特征的过程,这个过程将数据转换为能更好的表示业务逻辑的特征,从而提高机器学习的性能
特征工程主要包括数据预处理、特征选择与提取等
2、数据预处理
对于泰坦尼克号数据集的预处理,包括缺失值处理和特征编码
2.1、缺失值处理
上篇中,我们查看了数据集的缺失情况:
- 训练集:Age(177)、Cabin(687)、Embarked(2)
- 测试集:Age(86)、Fare(1)、Cabin(327)
对于缺失值的处理,我们一般选择填充和删除:
# 年龄(Age)=> 均值填充
data['Age'].fillna(data['Age'].mean(), inplace=True)
# 船票价格(Fare)=> 均值填充
data['Fare'].fillna(data['Fare'].mean(), inplace=True)
# 座位号(Cabin)=> 缺失较多,删除
data.drop(columns='Cabin', inplace=True)
# 登船码头(Embarked)=> 众数填充
data['Embarked'].fillna(data['Embarked'].mode(), inplace=True)
2.2、特征编码
数值型数据我们可以直接使用;对于日期型数据,我们需要转换成单独的年月日;对于分类型数据,需要使用特征编码转换为数值
1)分类特征:Sex(male/female)、Embarked(C/Q/S)
编码方案如下:
# 性别(Sex)=> 男(male):1,女(female):0
sex_map = {'male': 1, 'female': 0}
data['Sex'] = data['Sex'].map(sex_map)
# 登船码头(Embarked)=> 独热编码
embarked_dum = pd.get_dummies(data['Embarked'], prefix='Embarked', dtype=int)
# 删除源数据中的Embarked列,添加编码后的Embarked
data.drop(columns='Embarked', axis=1, inplace=True)
data = pd.concat([data, embarked_dum], axis=1)
2)非分类特征:Fare、Age
对于非分类特征,我们一般进行分箱处理:
# 根据样本分位数进行分箱,等比例分箱
# 船票价格(Fare) => 分箱并序数编码
data['FareBand'] = pd.qcut(data['Fare'], 4, labels=[0, 1, 2, 3])
# 删除Fare特征
data.drop(columns='Fare', inplace=True)
# 年龄(Age) => 分箱并序数编码
data['AgeBand'] = pd.cut(data['Age'], bins=[0, 12, 18, 60, 140], labels=[0, 1, 2, 3])
# 删除Age特征
data.drop(columns='Age', inplace=True)
3、特征选择与提取
3.1、特征提取
1)头衔特征
通过观察数据,我们发现乘客姓名中包含头衔,例如Mrs表示已婚女性。这些头衔可以将乘客进一步细分
提取姓名中的头衔:
# 提取姓名中的头衔
def extract_title(name: str):
return name.split(',')[1].split('.')[0].strip()
添加头衔特征:
# 添加头衔特征
data['Title'] = data['Name'].apply(extract_title)
查看头衔及数量:
# 查看头衔及数量
print(data['Title'].value_counts().reset_index())
由于头衔类别较多,且部分不同写法但意思相同,需要整合
# 整合意思相同的头衔
data['Title'].replace(['Capt', 'Col', 'Major', 'Dr', 'Rev', 'Jonkheer', 'Don', 'Sir', 'the Countess', 'Dona', 'Lady'], 'Other', inplace=True)
data['Title'].replace(['Mme', 'Ms'], 'Mrs', inplace=True)
data['Title'].replace(['Mlle'], 'Miss', inplace=True)
print(data['Title'].value_counts().reset_index())
对头衔特征进行编码,转化为数值:
# 头衔特征编码:序数编码
title_map = {'Mr': 0, 'Miss': 1, 'Mrs': 2, 'Master': 3, 'Other': 4}
data['Title'] = data['Title'].map(title_map)
# 删除Name特征
data.drop(columns='Name', axis=1, inplace=True)
2)家庭规模特征
通过观察数据,我们发现我们可以通过乘客兄弟姐妹及配偶人数和乘客父母及子女人数计算得到本次出行的乘客家庭规模
# 家庭规模(FamilySize) = 兄弟姐妹及配偶人数(SibSp) + 父母及子女人数(Parch) + 乘客自己(1)
data['FamilySize'] = data['SibSp'] + data['Parch'] + 1
# 对家庭规模特征进行分箱:1人(Alone)、2-4人(Small)、>4人(Large)
data['FamilySize'] = pd.cut(data['FamilySize'], bins=[1, 2, 5, 12], labels=['A', 'S', 'L'], right=False, include_lowest=True)
# 家庭规模特征编码:序数编码
fs_map = {'A': 0, 'S': 1, 'L': 2}
data['FamilySize'] = data['FamilySize'].map(fs_map)
# 删除SibSp、Parch特征
data.drop(columns=['SibSp', 'Parch'], inplace=True)
3.2、特征选择
更多的数据优于更好的算法,而更好的数据优于更多的数据。删除无关特征,最大程度保留数据
# 删除其他无关特征
data.drop(columns=['PassengerId', 'Ticket'], inplace=True)
# 应用了特征工程的数据
print(data.head().to_string())
将非数值型的原始数据转化为数值型的特征,这就是特征工程所做的事情
4、建模与预测
保存特征工程处理后的数据,以方便进行训练和评估:
# 保存特征工程处理后的数据(训练集和测试集)
data.to_csv("new_train.csv", index=False, encoding='utf-8')
特征工程处理后的泰坦尼克号数据集下载(训练集和测试集):预留
需要注意的是,测试集不包含Survived
列。因此,我们将对处理后的训练集重新进行训练集与测试集的划分,并基于新的训练集与测试集建模和预测
# 训练集和测试集
train = pd.read_csv("new_train.csv")
# X_test = pd.read_csv("new_test.csv")
X_train = train.iloc[:, 1:]
y_train = train.iloc[:, 0]
from sklearn.model_selection import train_test_split
# 重新划分训练集(80%)和测试集(20%)
X_train, X_test, y_train, y_test = train_test_split(X_train, y_train, test_size=0.2, random_state=0)
3.1、逻辑回归(幸存者预测)
from sklearn.linear_model import LogisticRegression
# 逻辑回归分类器(二分类)(默认求解器lbfgs、分类方式OvR)
lr = LogisticRegression()
# 训练模型
lr.fit(X_train, y_train)
# 预测
y_pred = lr.predict(X_test)
# print(y_pred)
# 准确度评分
print(lr.score(X_test, y_test)) # 0.7821229050279329
3.2、K近邻分类(幸存者预测)
from sklearn.neighbors import KNeighborsClassifier
# KNN分类器(默认使用标准欧几里德度量标准)
knn_clf = KNeighborsClassifier(n_neighbors=2)
# 训练模型
knn_clf.fit(X_train, y_train)
# 预测
y_pred = knn_clf.predict(X_test)
# print(y_pred)
# 平均准确度
print(knn_clf.score(X_test, y_test)) # 0.8156424581005587
现在,只要给定一个新的乘客的数据,我们就能预测该乘客在此次泰坦尼克号事故中是否幸存了,而且,预测准确率约达80%