Titanic - Machine Learning from Disaster是主要针对机器学习初学者开展的比赛,数据格式比较简单,为结构化数据。数据的数量较少(训练集892条,测试集419条),因此,就算找到有效的特征有良好的准确度,但很有可能因为一些小变动就让准确度下降。事实上,Public Leaderboard
分数较高的notebook
,未必对未知数据有良好的预测能力,可能只是过度比对测试数据碰巧得到吻合的结果罢了。在泰坦尼克号公开资料集中,每个用户有如下特征:
Survived
: 是否存活(label)PassengerId
: (乘客ID)Pclass
(用户阶级):1 - 1st class,高等用户;2 - 2nd class,中等用户;3 - 3rd class,低等用户;Name
(名字)Sex
(性别)Age
(年龄)SibSp
:描述了泰坦尼克号上与乘客同行的兄弟姐妹(Siblings)和配偶(Spouse)数目;Parch
:描述了泰坦尼克号上与乘客同行的家长(Parents)和孩子(Children)数目;Ticket
(船票号)Fare
(乘客费用)Cabin
(船舱)Embarked
(港口):用户上船时的港口代码实现包含如下基本步骤:
#!usr/bin/env python
# -*- coding:utf-8 -*-
"""
@author: liujie
@file: titanic.py
@time: 2022/09/08
@desc:Kaggle案例——泰坦尼克号
"""
import numpy as np
import pandas as pd
from xgboost import XGBClassifier
from sklearn.model_selection import KFold
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import log_loss, accuracy_score
# TODO:1.构造训练集与测试集
train = pd.read_csv("data/train.csv", sep=",", header=0)
test = pd.read_csv("data/test.csv", sep=",", header=0)
x_train = train.drop(['Survived'], axis=1)
y_train = train['Survived']
x_test = test.copy()
# TODO:2.建立特征
# 去除 PassengerId,Name, Ticket, Cabin
x_train = x_train.drop(['PassengerId', 'Name', 'Ticket', 'Cabin'], axis=1)
x_test = x_test.drop(['PassengerId', 'Name', 'Ticket', 'Cabin'], axis=1)
# 对Sex、Embarked进行label encoding
for c in ["Sex", "Embarked"]:
le = LabelEncoder()
le.fit(x_train[c].fillna("NA"))
x_train[c] = le.transform(x_train[c].fillna("NA"))
x_test[c] = le.transform(x_test[c].fillna("NA"))
# TODO:3.建立模型
xgb = XGBClassifier(n_estimators=20, random_state=2022)
xgb.fit(x_train, y_train) # 训练
pred = xgb.predict_proba(x_test)[:, 1] # 预测
# 将结果进行转换
pred = np.where(pred > 0.5, 1, 0)
# TODO:4.K折交叉验证
# 用 List 保存各 fold 的 accuracy 与 logloss 分数
scores_accuracy = []
scores_logloss = []
kf = KFold(n_splits=4, shuffle=True, random_state=2022)
for tr_idx, va_idx in kf.split(x_train):
# 分为训练集与验证集
tr_x, va_x = x_train.iloc[tr_idx], x_train.iloc[va_idx]
tr_y, va_y = y_train.iloc[tr_idx], y_train.iloc[va_idx]
# 建立XGBoost模型
xgb = XGBClassifier(n_estimators=20, random_state=2022)
xgb.fit(tr_x, tr_y)
# 对验证集进行预测
va_pred = xgb.predict_proba(va_x)[:, 1]
# 评测logloss与acc
logloss = log_loss(va_y, va_pred)
acc = accuracy_score(va_y, va_pred > 0.5)
scores_accuracy.append(acc)
scores_logloss.append(logloss)
# 输出每折评价指标的平均值
logloss = np.mean(scores_logloss)
accuracy = np.mean(scores_accuracy)
print(f'logloss: {logloss:.4f}, accuracy: {accuracy:.4f}')
# logloss: 0.4300, accuracy: 0.8137
# TODO:5.调整超参数
import itertools
# 准备用于调整的超参数
param_space = {"max_depth": [3, 5, 7], "min_child_weight": [1.0, 2.0, 4.0]}
# 产生所有超参数组合
param_combinations = itertools.product(param_space["max_depth"], param_space["min_child_weight"])
# 用 List 保存各参数组合的logloss 分数
params = []
scores = []
for max_depth, min_child_weight in param_combinations:
# 保存每个fold的分数
scores_fold = []
kf = KFold(n_splits=4, shuffle=True, random_state=2022)
for tr_idx, va_idx in kf.split(x_train):
# 分为训练集与验证集
tr_x, va_x = x_train.iloc[tr_idx], x_train.iloc[va_idx]
tr_y, va_y = y_train.iloc[tr_idx], y_train.iloc[va_idx]
# 建立XGBoost模型
xgb = XGBClassifier(n_estimators=20, max_depth=max_depth, min_child_weight=min_child_weight, random_state=2022)
xgb.fit(tr_x, tr_y)
# 对验证集进行预测
va_pred = xgb.predict_proba(va_x)[:, 1]
# 评测logloss与acc
logloss = log_loss(va_y, va_pred)
scores_fold.append(logloss)
score_mean = np.mean(scores_fold)
params.append((max_depth, min_child_weight))
scores.append(score_mean)
# 找出评价指标最佳的组合
best_idx = np.argsort(scores)[0]
best_param = params[best_idx]
print(f'best_param={best_param},best_score={scores[best_idx]}')
# best_param=(7, 2.0),best_score=0.4212539335124341
# TODO:6.建立逻辑回归模型所需特征,为后续模型集成做准备
from sklearn.preprocessing import OneHotEncoder
x2_train = train.drop(['Survived'], axis=1)
y2_train = train['Survived']
x2_test = test.copy()
# 去除训练、测试资料中的PassengerId、Name、Ticket、Cabin
x2_train = x2_train.drop(['PassengerId', 'Name', 'Ticket', 'Cabin'], axis=1)
x2_test = x2_test.drop(['PassengerId', 'Name', 'Ticket', 'Cabin'], axis=1)
# 对类别特征进行oneHot编码
cat_cols = ['Sex', 'Embarked', 'Pclass']
ohe = OneHotEncoder(categories='auto', sparse=False)
ohe.fit(x2_train[cat_cols].fillna('NA'))
# 构建one_hot编码后的特征名
ohe_columns = []
for i, c in enumerate(cat_cols):
# .categories_:表示该特征包含哪些类别的值
ohe_columns += [f'{c}_{v}' for v in ohe.categories_[i]]
# 将one_hot编码后的结果保存到dataframe中
ohe_train_x2 = pd.DataFrame(ohe.transform(x2_train[cat_cols].fillna('NA')), columns=ohe_columns)
ohe_test_x2 = pd.DataFrame(ohe.transform(x2_test[cat_cols].fillna('NA')), columns=ohe_columns)
# 去除原数据中已经onehot编码的特征
x2_train = x2_train.drop(cat_cols, axis=1)
x2_test = x2_test.drop(cat_cols, axis=1)
# 将onehot编码后的dataframe与原数据合并
x2_train = pd.concat([x2_train, ohe_train_x2], axis=1)
x2_test = pd.concat([x2_test, ohe_test_x2], axis=1)
# 填充缺失值
num_cols = ['Age', 'SibSp', 'Parch', 'Fare']
for col in num_cols:
x2_train[col].fillna(x2_train[col].mean(), inplace=True)
x2_test[col].fillna(x2_train[col].mean(), inplace=True)
# 将Fare取对数,变为正态分布
x2_train['Fare'] = np.log1p(x2_train['Fare'])
x2_test['Fare'] = np.log1p(x2_test['Fare'])
# TODO:7.模型集成
from sklearn.linear_model import LogisticRegression
xgb_model = XGBClassifier(n_estimators=20, max_depth=7, min_child_weight=2.0, random_state=2022)
xgb_model.fit(x_train, y_train)
xgb_pred = xgb_model.predict_proba(x_test)[:, 1]
lr_model = LogisticRegression(solver='lbfgs', max_iter=300)
lr_model.fit(x2_train, y2_train)
lr_pred = lr_model.predict_proba(x2_test)[:, 1]
# 取多个模型预测结果的加权值
pred = xgb_pred * 0.8 + lr_pred * 0.2
label_pred = np.where(pred > 0.5, 1, 0)
# 将预测结果进行保存
submission = pd.DataFrame({"PassengerId": test['PassengerId'], "Survived": label_pred})
submission.to_csv("submission.csv", index=False)
How am I doing with my score?这个notebook将参赛者们使用了什么手法,出现了什么样的分数整合起来。可进行参考。
0.77990 Gender + Class + Embarked LightGBM in Python.
这个notebook仅使用Sex,Embarked,Pclass这三个特征来进行预测;使用的模型是LightGBM。
- 对Embarked进行缺失值填充
- 对Sex与Embarked进行标签编码
- 利用网格搜索对lgb模型进行10折交叉验证,寻找最佳模型,得到预测结果
0.78468 Name-only text vectorization and PCA with a 3D interactive plot.
这个notebook仅使用Name特征来进行预测,使用的模型是KNeighborsClassifier。
- 利用单词计数+PCA来矢量化名称特征,
- 使用 KNeighborsClassifier模型并使用 GridSearchCV 对其进行调整参数,最后得到预测结果
0.78947 Gender + Class + Embarked + Age using SVM
这个notebook仅使用Sex,Embarked,Pclass、Age这三个特征来进行预测;使用的模型是SVM。
- 读取数据,并处理Embarked特征中的缺失值
- 针对Age特征,只保留年轻人,以及给Age缺失的人创建一个指标标志
- 针对Embarked,Pclass特征,采用oneHot编码;针对Sex特征,采用Lable 编码
- 使用 SVC模型并使用 GridSearchCV 对其进行调整参数,最后得到预测结果
0.79904 Neural network (keras) by Rafael Vicente Leite.
这个notebook使用ANN模型
- 读取数据
- 提取姓名中的性别标志
- 丢弃不相关特征’Ticket’, ‘Cabin’
- 填充’Embarked’特征列中的缺失值
- 对Name特征中的性别标志进行标签编码
- 对Sex与Embarked进行标签编码
- 得到对应性别与用户等级的平均票价与年龄,用于缺失值填充
- 对’Embarked’, ‘Name’, 'Pclass’特征进行oneHot编码
- 对所有特征进行标准化
- 构建ANN模型
- 模型预测和评估
- 生成提交文件
0.79904 Using ethnicity feature by Frederik Hasecke.
这个notebook使用
- 数据准备
- 填充Embarkment、Fare、Age中的缺失值,Age填充规则比较复杂
- 从Name特征中分析出种族
- 将Sex、处理后Name标志、Embarked、Fare、Ethnicity、Age都进行标签编码
- 模型训练
Gauss、KNN、Log Reg、RandomF、SVM- 模型融合
0.80861 Simple stacking by Anisotropic stacking is ubiquitous in competitions.
这个notebook使用stacking集成方法,这种方法容易过拟合
- 数据准备
- 构造FamilySize与IsAlone的特征
- 填充Embarked(港口)的缺失值
- 填充Fare的缺失值
- 填充Age,并用其置信区间中的值(平均值加减标准差)
- 构造Name的Title特征
- 对Sex、Title、Embarked、Fare、Age进行分箱
- stacking
- RandomForestClassifier, AdaBoostClassifier, GradientBoostingClassifier, ExtraTreesClassifier与SVC模型都进行5折交叉验证,保留训练集与测试集的预测值
- 利用XGBClassifier模型,输入为预测值,输出为真实值来构建模型,得到预测结果(提交文件)
0.80861 Voting/ensembling by Nick Brooks An impressive number of models is packed in almost one hour of running time!
这个notebook使用stacking模型
- 数据加载,数据预处理及特征工程
- 构建FamilySize、Name_length、IsAlone、Title
- 利用姓名Title来填充Age中的缺失值
- 用Embarked的众数来填充Embarked(港口)的缺失值
- 用Fare的均值来填充Fare中的缺失值
- 对Sex特征进行标签编码,对Title特征进行标签编码,并用其众数来填充缺失值
- 对Embarked特征进行标签编码
- 丢弃不相关特征’Ticket’, 'Cabin
- 将连续变量缩放到-1到1之间
- 将数据集分为训练集与测试集
- 模型训练
- K-Nearest Neighbors
- SGDClassifier
- Decision Trees
- Random Forest
- AdaBoostClassifier
- GradientBoostingClassifier
- XGBClassifier
- CatBoost
- lgb
- LogisticRegression
- MLPClassifier
- SVC
- 将上述几种模型的结果进行stacking
- Logistic Regression
0.80861 Kaggle Titanic with Tensorflow by nme-42 It is quite an interesting kernel.
这个notebook使用DNN
- 数据加载
- 数据预处理
- 构造船舱级别特征deck level
- 丢弃船舱特征Cabin
- 填充Embarked特征中的缺失值,用’N’填充表示缺失
- 填充Fare中的缺失值,用对应Pclass的Fare的众数
- 填充Age中的缺失值
- 特征工程
- 构建Family Size特征
后续部分没咋见过,感兴趣自己看!
0.81339 Titanic Using Ticket Grouping by Jack Roberts.
基于规则进行预测
0.82775 Frank Sylla engineers several features.
- 数据加载
- 特征工程
- 从Name特征中构建surname与Title特征,并对Title特征进行标签编码-TitleCat
- 构建家庭人数(FamilySize)特征并切分后进行标签编码
- 构建Name长度特征-NameLength
- 填充Fare特征中的缺失值
- 将Sex特征进行哑编码
- 将Embarked特征与Cabin特征的第一位进行标签编码
- 针对Cabin特征的数字部分构建CabinType特征,表示船舱号是奇数、偶数还是空
- 构建person特征,用于区分CHILD/FEMALE ADULT/MALE ADULT,并对这个特征进行哑编码后再与元特征进行拼接
0.83253 Konstantin brings attention to feature scaling, which is essential when working with the kNN algorithm.
这个Notebook使用KNN算法,达到了非常好的效果
- 特征工程
- 基于Name特征中构建Title特征,基于Title特征来估算Age中的缺失值
- 构建Family_Size特征
- 构建姓氏特征Last_Name
- 对船票价格特征Fare中的缺失值用均值进行填充
- 基于Last_Name、Fare、Survived、Ticket特征构建Family_Survival特征
- 将Fare特征中的缺失值用Fare中的中位数进行填充,并先进行等位分桶,再进行标签编码
- 将Age特征先进行等位分桶,再进行标签编码
- 将性别特征进行标签编码
- 将特征缩放到-1到1之间
- 模型训练
利用Grid Search CV对KNN进行超参数调参找到KNN模型的最优参数来进行预测
参考: