kaggle入门--泰坦尼克号之灾(手把手教你)

@作者:炼己者

本博客所有内容以学习、研究和分享为主,如需转载,请联系本人,标明作者和出处,并且是非商业用途,谢谢!

大家也可以去我的github上看,最近刚更新,用jupyter notebook写的,视觉效果上感觉会更棒
https://github.com/lianjizhe/kaggle_tiantic_code,有帮助的话给个星呀。


摘要

本文主要是带你入门kaggle最基础的比赛——泰坦尼克号之灾,里面有各种可视化为你展示做的过程,并非只有一大段代码,希望能带大家真正地去入门

这是我二月份参加的kaggle大赛,当时参考了很多大佬的代码,也算是完整的把这个流程走了一遍,取得了前%2的成绩。这个比赛对我很重要,因为排名靠前了,才让自己有信心一直前行。在这里呈现给大家,之前有发到CSDN博客,后来弃号了,现在正式地放到这里来,以后还会多多参加比赛。

现在如果还按这个代码去跑,排名估计会下降不少了,毕竟这么久了,大家也可以在这个基础上多多改善

排名

正文

一. 导入数据包与数据集

%matplotlib inline
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')

train=pd.read_csv(r'H:\kaggle\train.csv')
test=pd.read_csv(r'H:\kaggle\test.csv')
PassengerId=test['PassengerId']
all_data = pd.concat([train, test], ignore_index = True)

二. 数据分析

1.总体预览

train.head()
output

•PassengerID(ID)
•Survived(存活与否)
•Pclass(客舱等级,较为重要)
•Name(姓名,可提取出更多信息)
•Sex(性别,较为重要)
•Age(年龄,较为重要)
•Parch(直系亲友)
•SibSp(旁系)
•Ticket(票编号)
•Fare(票价)
•Cabin(客舱编号)
•Embarked(上船的港口编号)

[input]:
train.info()

[output]:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            714 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          204 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB

从上面的数据我们可以发现有的特征是有空值的


2.数据初步分析(使用统计学与绘图)

  • 目的:初步了解数据之间的相关性,为构造特征工程以及模型建立做准备
[input]:
train['Survived'].value_counts()

[output]:
0    549
1    342
Name: Survived, dtype: int64

1)Sex Feature:女性幸存率远高于男性

sns.barplot(x="Sex", y="Survived", data=train)
SEX Feature

2)Pclass Feature:乘客社会等级越高,幸存率越高

sns.barplot(x="Pclass", y="Survived", data=train)
Pclass Feature

3)SibSp Feature:配偶及兄弟姐妹数适中的乘客幸存率更高

sns.barplot(x="SibSp", y="Survived", data=train)
SibSp Feature

4)Parch Feature:父母与子女数适中的乘客幸存率更高

sns.barplot(x="Parch", y="Survived", data=train)![5.png](https://upload-
Parch Feature

5)从不同生还情况的密度图可以看出,在年龄15岁的左侧,生还率有明显差别,密度图非交叉区域面积非常大,但在其他年龄段,则差别不是很明显,认为是随机所致,因此可以考虑将此年龄偏小的区域分离出来。

facet = sns.FacetGrid(train, hue="Survived",aspect=2)
facet.map(sns.kdeplot,'Age',shade= True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
plt.xlabel('Age') 
plt.ylabel('density') 
密度图

6)Embarked登港港口与生存情况的分析
结果分析:C地的生存率更高,这个也应该保留为模型特征.

sns.countplot('Embarked',hue='Survived',data=train)
Embarked

7)Title Feature(New):不同称呼的乘客幸存率不同
新增Title特征,从姓名中提取乘客的称呼,归纳为六类。

all_data['Title'] = all_data['Name'].apply(lambda x:x.split(',')[1].split('.')[0].strip())
Title_Dict = {}
Title_Dict.update(dict.fromkeys(['Capt', 'Col', 'Major', 'Dr', 'Rev'], 'Officer'))
Title_Dict.update(dict.fromkeys(['Don', 'Sir', 'the Countess', 'Dona', 'Lady'], 'Royalty'))
Title_Dict.update(dict.fromkeys(['Mme', 'Ms', 'Mrs'], 'Mrs'))
Title_Dict.update(dict.fromkeys(['Mlle', 'Miss'], 'Miss'))
Title_Dict.update(dict.fromkeys(['Mr'], 'Mr'))
Title_Dict.update(dict.fromkeys(['Master','Jonkheer'], 'Master'))

all_data['Title'] = all_data['Title'].map(Title_Dict)
sns.barplot(x="Title", y="Survived", data=all_data)
Title Feature

8)FamilyLabel Feature(New):家庭人数为2到4的乘客幸存率较高
新增FamilyLabel特征,先计算FamilySize=Parch+SibSp+1,然后把FamilySize分为三类。

all_data['FamilySize']=all_data['SibSp']+all_data['Parch']+1
sns.barplot(x="FamilySize", y="Survived", data=all_data)
FamilyLabel Feature

按生存率把FamilySize分为三类,构成FamilyLabel特征。

def Fam_label(s):
    if (s >= 2) & (s <= 4):
        return 2
    elif ((s > 4) & (s <= 7)) | (s == 1):
        return 1
    elif (s > 7):
        return 0
all_data['FamilyLabel']=all_data['FamilySize'].apply(Fam_label)
sns.barplot(x="FamilyLabel", y="Survived", data=all_data)
FamilyLabel Feature

9)Deck Feature(New):不同甲板的乘客幸存率不同
新增Deck特征,先把Cabin空缺值填充为'Unknown',再提取Cabin中的首字母构成乘客的甲板号。

all_data['Cabin'] = all_data['Cabin'].fillna('Unknown')
all_data['Deck']=all_data['Cabin'].str.get(0)
sns.barplot(x="Deck", y="Survived", data=all_data)
Deck Feature

10)TicketGroup Feature(New):与2至4人共票号的乘客幸存率较高
新增TicketGroup特征,统计每个乘客的共票号数。

Ticket_Count = dict(all_data['Ticket'].value_counts())
all_data['TicketGroup'] = all_data['Ticket'].apply(lambda x:Ticket_Count[x])
sns.barplot(x='TicketGroup', y='Survived', data=all_data)
TicketGroup Feature

按生存率把TicketGroup分为三类。

def Ticket_Label(s):
    if (s >= 2) & (s <= 4):
        return 2
    elif ((s > 4) & (s <= 8)) | (s == 1):
        return 1
    elif (s > 8):
        return 0

all_data['TicketGroup'] = all_data['TicketGroup'].apply(Ticket_Label)
sns.barplot(x='TicketGroup', y='Survived', data=all_data)
TicketGroup Feature

3.数据清洗

1)缺失值填充
Age Feature:Age缺失量为263,缺失量较大,用Sex, Title, Pclass三个特征构建随机森林模型,填充年龄缺失值。

from sklearn.ensemble import RandomForestRegressor
age_df = all_data[['Age', 'Pclass','Sex','Title']]
age_df=pd.get_dummies(age_df)
known_age = age_df[age_df.Age.notnull()].as_matrix()
unknown_age = age_df[age_df.Age.isnull()].as_matrix()
y = known_age[:, 0]
X = known_age[:, 1:]
rfr = RandomForestRegressor(random_state=0, n_estimators=100, n_jobs=-1)
rfr.fit(X, y)
predictedAges = rfr.predict(unknown_age[:, 1::])
all_data.loc[ (all_data.Age.isnull()), 'Age' ] = predictedAges 

Embarked Feature:Embarked缺失量为2,缺失Embarked信息的乘客的Pclass均为1,且Fare均为80,因为Embarked为C且Pclass为1的乘客的Fare中位数为80,所以缺失值填充为C。

all_data[all_data['Embarked'].isnull()]
NaN
[input]:
all_data.groupby(by=["Pclass","Embarked"]).Fare.median()

[Output]:
Pclass  Embarked
1       C           78.2667
        Q           90.0000
        S           52.0000
2       C           15.3146
        Q           12.3500
        S           15.3750
3       C            7.8958
        Q            7.7500
        S            8.0500
Name: Fare, dtype: float64
all_data['Embarked'] = all_data['Embarked'].fillna('C')

Fare Feature:Fare缺失量为1,缺失Fare信息的乘客的Embarked为S,Pclass为3,所以用Embarked为S,Pclass为3的乘客的Fare中位数填充。

all_data[all_data['Fare'].isnull()]
NaN
fare=all_data[(all_data['Embarked'] == "S") & (all_data['Pclass'] == 3)].Fare.median()
all_data['Fare']=all_data['Fare'].fillna(fare)

2)同组识别
把姓氏相同的乘客划分为同一组,从人数大于一的组中分别提取出每组的妇女儿童和成年男性。

all_data['Surname']=all_data['Name'].apply(lambda x:x.split(',')[0].strip())
Surname_Count = dict(all_data['Surname'].value_counts())
all_data['FamilyGroup'] = all_data['Surname'].apply(lambda x:Surname_Count[x])
Female_Child_Group=all_data.loc[(all_data['FamilyGroup']>=2) & ((all_data['Age']<=12) | (all_data['Sex']=='female'))]
Male_Adult_Group=all_data.loc[(all_data['FamilyGroup']>=2) & (all_data['Age']>12) & (all_data['Sex']=='male')]

发现绝大部分女性和儿童组的平均存活率都为1或0,即同组的女性和儿童要么全部幸存,要么全部遇难。

Female_Child=pd.DataFrame(Female_Child_Group.groupby('Surname')['Survived'].mean().value_counts())
Female_Child.columns=['GroupCount']
Female_Child
GroupCount
sns.barplot(x=Female_Child.index, y=Female_Child["GroupCount"]).set_xlabel('AverageSurvived')
AverageSurvived

绝大部分成年男性组的平均存活率也为1或0。

Male_Adult=pd.DataFrame(Male_Adult_Group.groupby('Surname')['Survived'].mean().value_counts())
Male_Adult.columns=['GroupCount']
Male_Adult
GroupCount

因为普遍规律是女性和儿童幸存率高,成年男性幸存较低,所以我们把不符合普遍规律的反常组选出来单独处理。把女性和儿童组中幸存率为0的组设置为遇难组,把成年男性组中存活率为1的设置为幸存组,推测处于遇难组的女性和儿童幸存的可能性较低,处于幸存组的成年男性幸存的可能性较高。

[Input]:
Female_Child_Group=Female_Child_Group.groupby('Surname')['Survived'].mean()
Dead_List=set(Female_Child_Group[Female_Child_Group.apply(lambda x:x==0)].index)
print(Dead_List)
Male_Adult_List=Male_Adult_Group.groupby('Surname')['Survived'].mean()
Survived_List=set(Male_Adult_List[Male_Adult_List.apply(lambda x:x==1)].index)
print(Survived_List)

[Output]:
{'Panula', 'Lefebre', 'Lobb', 'Johnston', 'Robins', 'Ilmakangas', 'Turpin', 'Arnold-Franchi', 'Lahtinen', 'Barbara', 'Goodwin', 'Oreskovic', 'Van Impe', 'Strom', 'Rosblom', 'Cacic', 'Attalah', 'Caram', 'Vander Planke', 'Palsson', 'Skoog', 'Danbom', 'Rice', 'Canavan', 'Bourke', 'Jussila', 'Olsson', 'Boulos', 'Zabour', 'Sage', 'Ford'}
{'Beane', 'Frauenthal', 'Harder', 'Nakid', 'Bishop', 'Beckwith', 'Bradley', 'Chambers', 'Cardeza', 'Daly', 'Goldenberg', 'Kimball', 'McCoy', 'Jussila', 'Frolicher-Stehli', 'Duff Gordon', 'Greenfield', 'Dick', 'Jonsson', 'Taylor'}

为了使处于这两种反常组中的样本能够被正确分类,对测试集中处于反常组中的样本的Age,Title,Sex进行惩罚修改。

train=all_data.loc[all_data['Survived'].notnull()]
test=all_data.loc[all_data['Survived'].isnull()]
test.loc[(test['Surname'].apply(lambda x:x in Dead_List)),'Sex'] = 'male'
test.loc[(test['Surname'].apply(lambda x:x in Dead_List)),'Age'] = 60
test.loc[(test['Surname'].apply(lambda x:x in Dead_List)),'Title'] = 'Mr'
test.loc[(test['Surname'].apply(lambda x:x in Survived_List)),'Sex'] = 'female'
test.loc[(test['Surname'].apply(lambda x:x in Survived_List)),'Age'] = 5
test.loc[(test['Surname'].apply(lambda x:x in Survived_List)),'Title'] = 'Miss'

3)特征转换
选取特征,转换为数值变量,划分训练集和测试集。

all_data=pd.concat([train, test])
all_data=all_data[['Survived','Pclass','Sex','Age','Fare','Embarked','Title','FamilyLabel','Deck','TicketGroup']]
all_data=pd.get_dummies(all_data)
train=all_data[all_data['Survived'].notnull()]
test=all_data[all_data['Survived'].isnull()].drop('Survived',axis=1)
X = train.as_matrix()[:,1:]
y = train.as_matrix()[:,0]

4.建模和优化

1)参数优化
用网格搜索自动化选取最优参数,事实上我用网格搜索得到的最优参数是n_estimators = 28,max_depth = 6。但是参考另一篇Kernel把参数改为n_estimators = 26,max_depth = 6之后交叉验证分数和kaggle评分都有略微提升。

[Input]:
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.feature_selection import SelectKBest

pipe=Pipeline([('select',SelectKBest(k=20)), 
               ('classify', RandomForestClassifier(random_state = 10, max_features = 'sqrt'))])

param_test = {'classify__n_estimators':list(range(20,50,2)), 
              'classify__max_depth':list(range(3,60,3))}
gsearch = GridSearchCV(estimator = pipe, param_grid = param_test, scoring='roc_auc', cv=10)
gsearch.fit(X,y)
print(gsearch.best_params_, gsearch.best_score_)

[Output]:
{'classify__max_depth': 6, 'classify__n_estimators': 42} 0.88109635084

2)训练模型

[Input]:
from sklearn.pipeline import make_pipeline
select = SelectKBest(k = 20)
clf = RandomForestClassifier(random_state = 10, warm_start = True, 
                                  n_estimators = 26,
                                  max_depth = 6, 
                                  max_features = 'sqrt')
pipeline = make_pipeline(select, clf)
pipeline.fit(X, y)

[Output]:

Out[40]:
Pipeline(memory=None,
     steps=[('selectkbest', SelectKBest(k=20, score_func=<function f_classif at 0x000000000C8AE048>)), ('randomforestclassifier', RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=6, max_features='sqrt', max_leaf_nodes=None,
            min_impurity_decreas...estimators=26, n_jobs=1,
            oob_score=False, random_state=10, verbose=0, warm_start=True))])

3)交叉验证

[input]:
from sklearn import cross_validation, metrics
cv_score = cross_validation.cross_val_score(pipeline, X, y, cv= 10)
print("CV Score : Mean - %.7g | Std - %.7g " % (np.mean(cv_score), np.std(cv_score)))

[Output]:
CV Score : Mean - 0.8451402 | Std - 0.03276752 

5.预测

predictions = pipeline.predict(test)
submission = pd.DataFrame({"PassengerId": PassengerId, "Survived": predictions.astype(np.int32)})
submission.to_csv(r"h:\kaggle\submission1.csv", index=False)

以下是我所有文章的目录,大家如果感兴趣,也可以前往查看
👉戳右边:打开它,也许会看到很多对你有帮助的文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容

  • 侵删。 Kaggle入门,看这一篇就够了 1 年前 这次酝酿了很久想给大家讲一些关于Kaggle那点儿事,帮助对数...
    程序猪小羊阅读 14,003评论 3 70
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,035评论 25 707
  • 愿你是阳光 明媚不忧伤 陌时 光阴似弹起的轻羽 居无定所 随风漂泊 熟识 我总是抓不住时间的尾巴 刚好相遇又刚好分...
    叶可君阅读 460评论 1 5
  • 她,是一位无忧无虑的精灵小公主;他,是一位天赋极强的小皇子。 上天安排他们相遇,并许下诺言 为了配得上他,她拼了命...
    请设置名称阅读 285评论 0 0
  • 梦里的三爸还是壮年时候那样强健的身体,大踏步走来说,国家政策要求平坟或者迁坟。没有明说,似乎也没有对我说。而我听得...
    绿萝宝贝阅读 228评论 8 7