Kaggle比赛系列: (3) Titanic-1

比赛介绍

Titanic被认为是Kaggle比赛的入门项目,简要概括这个竞赛: 根据Titanic上乘客的姓名, 年龄, 性别, 收入等特征, 预测乘客的存活.
数据集:链接: https://pan.baidu.com/s/1_a2fZ_QWIDq-G_j5mk1sgw 提取码: rcne
数据集描述: 乘客相关特征描述如下
总计10个特征

参赛大神比赛记录

原文地址: https://www.kaggle.com/startupsci/titanic-data-science-solutions

1 调包

#有关数据分析和处理的包
import pandas as pd
import numpy as np
import random as rnd
#绘图包
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
#抑制警告信息
import warnings
warnings.filterwarnings('ignore')
#机器学习算法
from sklearn.linear_model import LogisticRegression,Perceptron,SGDClassifier
from sklearn.svm import SVC,LinearSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.tree import DecisionTreeClassifier

2 数据加载与分析

train_df = pd.read_csv('/media/promise/mySpace/competition/kaggle/titanic/train.csv')
test_df = pd.read_csv('/media/promise/mySpace/competition/kaggle/titanic/test.csv')
combine = [train_df, test_df]

特别强调将训练集和测试集结合在一起成为列表的方法, 因为两集的特征字段在变化前后都应该保持一致,结合在一起,方便同时对两集进行处理,后面的程序也会多次使用这个技巧.

解读原始数据集
#1 根据数据集描述分析各字段含义和类型
#Categorical:Survived, Sex, Embarked   分类
#Ordinal:Pclass 分类且有顺序
#Continous:Age, Fare  连续数字
#Discrete: SibSp, Parch 离散数字
#2 查看字段数量
print(len(train_df.columns.values),len(test_df.columns.values))

12 11

#3 查看是否存在空值
train_df.info()#查看训练集和测试集每一列是否有空值
#Age, Cabin, Embarked存在空值

<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

test_df.info()
#Fare, Cabin存在空值

<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 418 entries, 0 to 417
Data columns (total 11 columns):
PassengerId 418 non-null int64
Pclass 418 non-null int64
Name 418 non-null object
Sex 418 non-null object
Age 332 non-null float64
SibSp 418 non-null int64
Parch 418 non-null int64
Ticket 418 non-null object
Fare 417 non-null float64
Cabin 91 non-null object
Embarked 418 non-null object
dtypes: float64(2), int64(4), object(5)
memory usage: 36.0+ KB

#4 查看数字类字段的分布
train_df.describe()

#1 通过Survived可以看出,存活率接近38.38%
#2 通过Pclass可以看出,大部分人买的是3等票
#3 通过Age可以看出, 平均年龄是29.7岁,且75%在38岁以下
#4 通过SibSp可以看出,平均兄弟姐妹有0.52个,应该绝大部分是1个或没有
#5 由Parch可见,平均父母或子女数有0.38个,绝大部分没有父母子女
#6 由Fare可见, 平均票价32元,且75%≤31元(与2相呼应)

#查看类别属性(字符串, 离散数字)的数量(分组)
train_df.Survived.value_counts()#有342个人存活
train_df.Pclass.value_counts()
#3等票 491; 2等票216;1等票184
train_df.Sex.value_counts()
#有男性577人, 女性314人
train_df.SibSp.value_counts()
#兄弟姐妹数量
train_df.Parch.value_counts()
#父母子女数量
train_df.Embarked.value_counts()
#登船口分布
分析各属性与存活结果的关系

先选择没有空值的分类(Sex, Pclass),和离散数值型(SibSp, Parch)数据进行统计分析
分组与生存人数进行关联

相当于Excel的数据透视表
SQL查询的 groupby

#属性筛选 分组,求均值, 排序
train_df[['Pclass','Survived']].groupby(['Pclass'], as_index=False).mean().sort_values(by= 'Survived',ascending = False)
*Pclass	Survived

0 1 0.629630
1 2 0.472826
2 3 0.242363*

train_df[['Sex','Survived']].groupby('Sex', as_index = False).mean().sort_values(by = 'Survived', ascending = False)

Sex Survived
0 female 0.742038
1 male 0.188908

train_df[["SibSp", "Survived"]].groupby(['SibSp']).mean().sort_values(by='Survived', ascending=False)
train_df[["Parch", "Survived"]].groupby(['Parch'], as_index=False).mean().sort_values(by='Survived', ascending=False)
根据图表分析各属性与存活结果的关系
#numerical features and our solution goal
g = sns.FacetGrid(train_df, col = 'Survived')
g.map(plt.hist, 'Age', bins = 20)#绘图类型是hist, 横坐标是Age,数量是纵坐标

survived属性有(0,1)两种情况

#Correlating numerical and ordinal features
grid = sns.FacetGrid(train_df, col = 'Survived', row = 'Pclass', size=2.2, aspect=1.6)
grid.map(plt.hist, 'Age', alpha=.5, bins=20)
grid.add_legend();

Pclass 包含3个属性, Survived包含两个属性,所以是6个图

#correlate categorical features with our solution goal.
grid = sns.FacetGrid(train_df, row='Embarked', size=2.2, aspect=1.6)
grid.map(sns.pointplot, 'Pclass', 'Survived', 'Sex', palette='deep')
grid.add_legend()

Sex, Pclass, Embarked三个属性与存活结果(数量)之间的关系

grid = sns.FacetGrid(train_df, row='Embarked', col='Survived', size=2.2, aspect=1.6)
grid.map(sns.barplot, 'Sex', 'Fare', alpha=.5, ci=None)
grid.add_legend()

3个属性与存活结果之间的关系

#筛选有价值的属性
train_df = train_df.drop(['Ticket', 'Cabin'], axis=1)
test_df = test_df.drop(['Ticket', 'Cabin'], axis=1)
combine = [train_df, test_df]#去掉Ticket和Cabin之后仍然将两集结合成列表
原始属性钻取

1. Name属性钻取

#处理有隐含价值的属性:Name,我们只关注称谓,不关注名字
for dataset in combine:
    dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\.', expand=False)#正则化
pd.crosstab(train_df['Title'], train_df['Sex'])#pd.crosstab(),根据Sex分隔Title

Sex female male
Title
Capt 0 1
Col 0 2
Countess 1 0
Don 0 1
Dr 1 6
Jonkheer 0 1
Lady 1 0
Major 0 2
Master 0 40
Miss 182 0
Mlle 2 0
Mme 1 0
Mr 0 517
Mrs 125 0
Ms 1 0
Rev 0 6
Sir 0 1

女士中Miss和Mrs数量最多,男士中Mr和Master称谓最多

# 统一称谓为5种形式,类似的统一在一起,不常出现的统一为rare(稀少的)
for dataset in combine:
    dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')

    dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss')
    dataset['Title'] = dataset['Title'].replace('Ms', 'Miss')
    dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs')
    
train_df[['Title', 'Survived']].groupby(['Title'], as_index=False).mean().sort_values(by= 'Survived', ascending = False)
*Title	Survived

3 Mrs 0.793651
1 Miss 0.702703
0 Master 0.575000
4 Rare 0.347826
2 Mr 0.156673*

#将字符类别转化为数字类别
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}
for dataset in combine:
    dataset['Title'] = dataset['Title'].map(title_mapping)
    dataset['Title'] = dataset['Title'].fillna(0)
train_df = train_df.drop(['Name', 'PassengerId'], axis=1)
test_df = test_df.drop(['Name'], axis=1)
combine = [train_df, test_df]

2. Sex属性钻取

# 将性别转化为(1, 0):字符类别转化为数字类别
for dataset in combine:
    dataset['Sex'] = dataset['Sex'].map( {'female': 1, 'male': 0} ).astype(int)

3. Age 属性填充
(程序没看明白,作用大概清楚)

guess_ages = np.zeros((2,3))
for dataset in combine:
    for i in range(0, 2):
        for j in range(0, 3):
        #因为两集中Age属性都有大量缺失值,这里采用类"聚类"方法填充缺失值.缺失的Age用相同性别相同Pclass的乘客的中值填充
            guess_df = dataset[(dataset['Sex'] == i) & \
                                  (dataset['Pclass'] == j+1)]['Age'].dropna()
            age_guess = guess_df.median()

            # Convert random age float to nearest .5 age
            guess_ages[i,j] = int( age_guess/0.5 + 0.5 ) * 0.5
            
    for i in range(0, 2):
        for j in range(0, 3):
            dataset.loc[ (dataset.Age.isnull()) & (dataset.Sex == i) & (dataset.Pclass == j+1),\
                    'Age'] = guess_ages[i,j]

    dataset['Age'] = dataset['Age'].astype(int)
train_df['AgeBand'] = pd.cut(train_df['Age'], 5)#pd.cut()分组函数
train_df[['AgeBand', 'Survived']].groupby(['AgeBand'], as_index=False).mean().sort_values(by='AgeBand', ascending=True)
*AgeBand	Survived

0 (-0.08, 16.0] 0.550000
1 (16.0, 32.0] 0.337374
2 (32.0, 48.0] 0.412037
3 (48.0, 64.0] 0.434783
4 (64.0, 80.0] 0.090909*

#将两集的Age属性按照分组转化为数字类别
for dataset in combine:    
    dataset.loc[ dataset['Age'] <= 16, 'Age'] = 0
    dataset.loc[(dataset['Age'] > 16) & (dataset['Age'] <= 32), 'Age'] = 1
    dataset.loc[(dataset['Age'] > 32) & (dataset['Age'] <= 48), 'Age'] = 2
    dataset.loc[(dataset['Age'] > 48) & (dataset['Age'] <= 64), 'Age'] = 3
    dataset.loc[ dataset['Age'] > 64, 'Age'] = 4 
train_df.head()
train_df = train_df.drop(['AgeBand'], axis=1)#去掉多余属性
combine = [train_df, test_df]

4. Embarked属性填充

freq_port = train_df.Embarked.dropna().mode()[0]
for dataset in combine:
    dataset['Embarked'] = dataset['Embarked'].fillna(freq_port)
    
train_df[['Embarked', 'Survived']].groupby(['Embarked'], as_index=False).mean().sort_values(by='Survived', ascending=False)
# 转化为数字类别
for dataset in combine:
    dataset['Embarked'] = dataset['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int)

5. Fare属性填充

test_df['Fare'].fillna(test_df['Fare'].dropna().median(), inplace=True)
for dataset in combine:
    dataset.loc[ dataset['Fare'] <= 7.91, 'Fare'] = 0
    dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1
    dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare']   = 2
    dataset.loc[ dataset['Fare'] > 31, 'Fare'] = 3
    dataset['Fare'] = dataset['Fare'].astype(int)

train_df = train_df.drop(['FareBand'], axis=1)
combine = [train_df, test_df]
# Fare属性分组
train_df['FareBand'] = pd.qcut(train_df['Fare'], 4)
train_df[['FareBand', 'Survived']].groupby(['FareBand'], as_index=False).mean().sort_values(by='FareBand', ascending=True)
建立新特征
#1 将兄弟姐妹和父母子女与乘客本身加在一起,构造Familysize的属性
for dataset in combine:
    dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1

train_df[['FamilySize', 'Survived']].groupby(['FamilySize'], as_index=False).mean().sort_values(by='Survived', ascending=False)
#2 构造没有任何其他家庭成员的特征IsAlone
for dataset in combine:
    dataset['IsAlone'] = 0
    dataset.loc[dataset['FamilySize'] == 1, 'IsAlone'] = 1

train_df[['IsAlone', 'Survived']].groupby(['IsAlone'], as_index=False).mean()
#3 构造Age*Class特征(WHY?)
for dataset in combine:
    dataset['Age*Class'] = dataset.Age * dataset.Pclass
X_train = train_df.drop("Survived", axis=1)
Y_train = train_df["Survived"]
X_test  = test_df.drop("PassengerId", axis=1).copy()

3. 建模与测试

LR模型

logreg = LogisticRegression()
logreg.fit(X_train, Y_train)
Y_pred = logreg.predict(X_test)
acc_log = round(logreg.score(X_train, Y_train) * 100, 2)
#特征相关度
coeff_df = pd.DataFrame(train_df.columns.delete(0))
coeff_df.columns = ['Feature']
coeff_df["Correlation"] = pd.Series(logreg.coef_[0])

coeff_df.sort_values(by='Correlation', ascending=False)

Feature Correlation
1 Sex 2.201527
5 Title 0.398234
2 Age 0.287165
4 Embarked 0.261762
6 IsAlone 0.129140
3 Fare -0.085150
7 Age
Class -0.311199
0 Pclass -0.749006*
SVC模型

svc = SVC()
svc.fit(X_train, Y_train)
Y_pred = svc.predict(X_test)
acc_svc = round(svc.score(X_train, Y_train) * 100, 2)

KNN模型

knn = KNeighborsClassifier(n_neighbors = 3)
knn.fit(X_train, Y_train)
Y_pred = knn.predict(X_test)
acc_knn = round(knn.score(X_train, Y_train) * 100, 2)

GaussianNB模型

gaussian = GaussianNB()
gaussian.fit(X_train, Y_train)
Y_pred = gaussian.predict(X_test)
acc_gaussian = round(gaussian.score(X_train, Y_train) * 100, 2)

感知机模型

perceptron = Perceptron()
perceptron.fit(X_train, Y_train)
Y_pred = perceptron.predict(X_test)
acc_perceptron = round(perceptron.score(X_train, Y_train) * 100, 2)

LinearSVC模型

linear_svc = LinearSVC()
linear_svc.fit(X_train, Y_train)
Y_pred = linear_svc.predict(X_test)
acc_linear_svc = round(linear_svc.score(X_train, Y_train) * 100, 2)

SGD模型

sgd = SGDClassifier()
sgd.fit(X_train, Y_train)
Y_pred = sgd.predict(X_test)
acc_sgd = round(sgd.score(X_train, Y_train) * 100, 2)

决策树模型

decision_tree = DecisionTreeClassifier()
decision_tree.fit(X_train, Y_train)
Y_pred = decision_tree.predict(X_test)
acc_decision_tree = round(decision_tree.score(X_train, Y_train) * 100, 2)

随机森林模型

random_forest = RandomForestClassifier(n_estimators=100)
random_forest.fit(X_train, Y_train)
Y_pred = random_forest.predict(X_test)
random_forest.score(X_train, Y_train)
acc_random_forest = round(random_forest.score(X_train, Y_train) * 100, 2)

4. 模型对比

models = pd.DataFrame({
    'Model': ['Support Vector Machines', 'KNN', 'Logistic Regression', 
              'Random Forest', 'Naive Bayes', 'Perceptron', 
              'Stochastic Gradient Decent', 'Linear SVC', 
              'Decision Tree'],
    'Score': [acc_svc, acc_knn, acc_log, 
              acc_random_forest, acc_gaussian, acc_perceptron, 
              acc_sgd, acc_linear_svc, acc_decision_tree]})
models.sort_values(by='Score', ascending=False)

Model Score
3 Random Forest 86.76
8 Decision Tree 86.76
1 KNN 84.74
0 Support Vector Machines 83.84
2 Logistic Regression 80.36
7 Linear SVC 79.12
5 Perceptron 78.34
6 Stochastic Gradient Decent 77.10
4 Naive Bayes 72.28

5. 预测提交

submission = pd.DataFrame({
        "PassengerId": test_df["PassengerId"],
        "Survived": Y_pred
    })
submission.to_csv('submission.csv', index=False)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值