Titanic生存预测1

背景音乐:Toca Toca - Fly Project
背景音乐有毒……

8888511-a5c08349226a4ae3.png

前言

前段时间玩了一下Kaggle平台上的Titanic号生存预测竞赛,这是一个非常适合入门机器学习的项目。

这场竞赛的内容是,通过一部分乘客的数据及其存活率,来预测另一部分乘客的存活率,目标是预测的准确率尽可能高。

我的最好分数是0.81339,在9606支队伍中排名300+~500+,也就是说有差不多200人拿到了这个成绩噗。对于我投入的时间而言,这个成绩还算满意,而且我相信还有一定的提升空间。

这里假设,看这篇文章的人已经参加过,但是没有拿到较好的成绩(我认为拿到0.8以上就不错了)。


我的建议

拿到0.8以上的分数后,就不要再追求排名了,而是需要看看别人的kernel学习他们的特征处理方式,理由是:

包括我在内,很多参赛选手发现,自己在测试集上有0.85左右的分数,但是一提交结果却发现只有0.78左右,这说明模型已经过拟合了。

不是你的问题,因为该项目的数据量太少,噪音也很多,因此做好模型不如做好特征工程来得重要,更不如发现数据背后的规律并善加利用重要。后者要求你对数据有敏锐的观察力,同时利用这些规律来修正你的模型的预测结果,不然我敢保证你的模型极限只会是0.83。

为什么有一些人的准确率会有0.9甚至1.0呢?理由很简单,他们在现有模型的基础上,加了很多认为设定的规则,故意让结果“过拟合”。理论上,除非数据集有问题,否则模型的准确率不可能会达到100%的。他们中的有些人可能确实发现了一个牛逼的特征,但我相信一部分人是存在作弊嫌疑的……

废话不多说,上干货。


环境:python 3.6.2
系统:macOS 10.13.1

1. 数据探索

EDA很重要,很重要,很重要!!!

但我同样假设你已经发现了一部分规律,比如:
1)女性存活率要远高于男性;
2)Embarked为S的乘客幸存率较低;
……

所以我这里跳过该部分。不了解的童鞋看这里:EDA To Prediction(DieTanic)

from sklearn.preprocessing import LabelEncoder
from sklearn import model_selection
from xgboost import XGBRegressor
import pandas as pd

path_data = '../../data/titanic/'
df_train = pd.read_csv(path_data + 'train.csv')
df_test = pd.read_csv(path_data + 'test.csv')
df_data = pd.concat([df_train, df_test])

2. 特征工程

所谓特征工程,最重要的就是通过已有的特征,去构建有预测能力的新特征。
而有预测能力的新特征,有三条基本特性(瞎掰的哈):可解释性、相关性、易获得性。

我做了4方面内容——数据清洗、构造新特征、特征选择、特征转换:

2.1 数据清洗

缺少数据的主要有4个变量,其中:

  • Cabin:缺太多了,提取头字母,将缺失值和头字母数少于10的归为一类
  • Embarked和Fare:都缺很少,可以用众数填补
  • Age:有部分缺失,但EDA结果显示它很重要,因此我决定构造模型来预测Age。不过该部分放在最后。
df_data['Embarked'].fillna(df_data['Embarked'].mode()[0], inplace=True)
df_data['Fare'].fillna(df_data['Fare'].median(), inplace=True)
df_data['Cabin'] = df_data['Cabin'].apply(lambda x:x[0] if x is not np.nan else 'X')
cabin_counts = df_data['Cabin'].value_counts()
df_data['Cabin'] = df_data['Cabin'].apply((lambda x:'X' if cabin_counts[x] < 10 else x))

2.2 构造新特征

构造新特征其实是一件特别蛋疼的事……因为这个完全靠经验+尝试, 别无他法。

常常是拍脑瓜想出一个新特征,然后看这个特征和结果的相关性,如果还不错的话,说明有一定的预测能力,然后代入到模型中,看测试集的表现是否有提高。如果有提高,高兴啦;如果没什么变化甚至降低了,就要考虑是暂时保留还是剔除掉……

下面直接列出我用的、对结果有一定帮助的特征。

FamilySize

df_data['FamilySize'] = df_data['SibSp'] + df_data['Parch'] + 1

IsAlone

df_data['IsAlone'] = 1
df_data['IsAlone'].loc[df_data['FamilySize'] > 1] = 0

Title

拥有人数少于10的title都改成Rare

df_data['Title'] = df_data['Name'].str.split(", ", expand=True)[1].str.split(".", expand=True)[0]
title_counts = df_data['Title'].value_counts()
df_data['Title'] = list(map(lambda x:'Rare' if title_counts[x] < 10 else x, df_data['Title'])) 

Family_Name

部分西方国家中人名的重复度较高,而姓氏重复度较低,姓氏具有一定辨识度。
姓氏相同的乘客,可能是一家人,而一家人同时幸存或遇难的可能性较高。

df_data['Family_Name'] = df_data['Name'].apply(lambda x: str.split(x, ",")[0])

Family_Survival

此处逻辑是:

  • 一个人的家庭存活率为0.5
  • 再将Family_Name和Fare进行组合,认为同一姓氏且有着同一票价的人们组成一个家庭,对于一个家庭(大于1人)而言,设如果有人存活则家庭存活率为1,否则为0
  • 再将Family_Name和Ticket进行组合,认为同一姓氏且有着共享一张票的人们组成一个家庭,对于一个家庭(大于1人)而言,设如果有人存活则家庭存活率为1,否则为0
DEFAULT_SURVIVAL_VALUE = 0.5
df_data['Family_Survival'] = DEFAULT_SURVIVAL_VALUE

for grp, grp_df in df_data.groupby(['Family_Name', 'Fare']):
    if (len(grp_df) != 1):
        for ind, row in grp_df.iterrows():
            smax = grp_df.drop(ind)['Survived'].max()
            smin = grp_df.drop(ind)['Survived'].min()
            passID = row['PassengerId']
            if (smax == 1.0):
                df_data.loc[df_data['PassengerId'] == passID, 'Family_Survival'] = 1
            elif (smin==0.0):
                df_data.loc[df_data['PassengerId'] == passID, 'Family_Survival'] = 0

for _, grp_df in df_data.groupby('Ticket'):
    if (len(grp_df) != 1):
        for ind, row in grp_df.iterrows():
            if (row['Family_Survival'] == 0) | (row['Family_Survival']== 0.5):
                smax = grp_df.drop(ind)['Survived'].max()
                smin = grp_df.drop(ind)['Survived'].min()
                passID = row['PassengerId']
                if (smax == 1.0):
                    df_data.loc[df_data['PassengerId'] == passID, 'Family_Survival'] = 1
                elif (smin==0.0):
                    df_data.loc[df_data['PassengerId'] == passID, 'Family_Survival'] = 0

2.3 预测年龄

这一部分也属于数据清洗,但是比较高级。

在这里我用交叉验证和GridSearchCV的方式训练出一个较好的xgboost回归模型来预测年龄。

def predict_age(x_train, y_train, x_test):
    param_grid = {
        'learning_rate':[.001, .005, .01, .05, .1],
        'max_depth':[2, 4, 6, 8],
        'n_estimators':[50, 100, 300, 500, 1000],
        'seed':[2018]
    }
    cv_split = model_selection.ShuffleSplit(n_splits = 10, test_size = .3, train_size = .6, random_state = 0) 
    tune_model = model_selection.GridSearchCV(XGBRegressor(nthread=-1), param_grid=param_grid, 
                                              scoring = 'neg_mean_squared_error', cv = cv_split)
    tune_model.fit(x_train, y_train)
    print(tune_model.best_params_)
    y_test = tune_model.best_estimator_.predict(x_test)

    return y_test

data_p = df_data.drop(['Cabin', 'Embarked', 'FareBin', 'Name', 'PassengerId',
                       'Sex', 'Survived', 'Ticket', 'Title', 'Family_Name'], 1)
x_train = data_p.loc[~data_p['Age'].isnull(), :].drop('Age', 1)
y_train = data_p.loc[~data_p['Age'].isnull(), :]['Age']
x_test = data_p.loc[data_p['Age'].isnull(), :].drop('Age', 1)
df_data.loc[df_data['Age'].isnull(), 'Age'] = predict_age(x_train, y_train, x_test)

2.4 特征转换

该部分要做的就是将分类变量处理成哑变量,因为模型只认识数字不认识字符。

要转换的特征有Sex、Embarked、Title、Cabin这4个,其中Sex属于二分类,可以用LabelEncoder处理。

label = LabelEncoder()
df_data['Sex_Code'] = label.fit_transform(df_data['Sex'])  # female为0, male为1

df_data = pd.concat([df_data, pd.get_dummies(df_data[['Embarked', 'Title', 'Cabin']])], axis=1)

2.5 剔除特征

经历了上面几个部分的特征处理,最后剔除掉没用的特征,并将结果保留下来,用以训练。

drop_columns = ['Sex', 'Name', 'Embarked', 'Cabin', 'Ticket', 'Title', 'Family_Name']
df_data = df_data.drop(drop_columns, 1)
df_data.to_csv(path_data + 'fe_data.csv', index=False)

得到一份有着1309行,26列的数据集

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.m或d论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值