机器学习案例(1)之Kaggle泰坦尼克之灾

1. 环境

  • Mac OS
  • python 3.7
  • anaconda
  • PyCharm 教育版

2. 数据

3. 认识数据

train.csv中的数据用Mac自带的“Numbers 表格”打开后,部分数据截图如下:
在这里插入图片描述

  • PassengerId:乘客ID,从1到891
  • Survived:是否生存下来,1表示最终生存下来了,0表示最终没有生存下来
  • Pclass:乘客的舱位等级,包括一等舱、二等舱、三等舱
  • Name:乘客姓名
  • Sex:乘客性别,male为男性,female为女性
  • Age:乘客年龄,有缺失值
  • SibSp:兄弟/兄妹的个数
  • Parch:父母与小孩的个数
  • Ticket:船票
  • Fare:票价
  • Cabin:客舱,有缺失值
  • Embarked:登船的港口,包含S港口、C港口、Q港口

以下为test.csv打开后的部分数据截图,与训练数据相比,少了“Survived”这一列,也就是需要我们通过前面的训练数据来预测测试数据中少的这一列的值。
在这里插入图片描述

4. 数据分析

只是在表格里看数据之间的关系,一是分析得不够全面;二是没有一个很好的可视化结果显示数据之间的关系。因此使用pandas来读取相应的数据,使用matplotlib来画相应的关系图。

既然是预测乘客是否获救,则先看一下训练数据中乘客的获救情况;然后按照猜想,获救的人数是否与船舱的等级有关、是否与乘客的年龄有关等等。
在这里插入图片描述
从上表可以看出,获救的人是要少于没有获救的人;三等舱的人数是最多的;获救与没有获救的人在年龄上分布比较均匀,各个年龄阶段的人都有;舱位等级与年龄大致符合正态分布;在S港口登舱的人最多。。。 在这里插入图片描述
从上表可以看出,三等舱的乘客未获救的人数最多,但是获救的人数一、二、三等舱的人数差别不多,而获救的比例则是一等舱大于二等舱大于三等舱。
在这里插入图片描述
从上表可以看出,无论是高级舱还是低级舱,女性获救的人数都要远远多于男性。
在这里插入图片描述
从上表可以看出,S港由于基数大,所以获救的人数也是最多的,但是从获救的比例上来看,又是最少的。

数据分析代码如下:

import pandas as pd
import numpy as np


data_train = pd.read_csv("/Users/chentingxuan/Downloads/Kaggle_Titanic-master/train.csv")

import matplotlib.pyplot as plt
fig = plt.figure()
fig.set(alpha=0.2)  # 设定图表颜色alpha参数
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False


plt.subplot2grid((2,3),(0,0))             # 在一张大图里分列几个小图,(2,3)表示分成2行3列,(0,0)表示从第1行第一列开始
data_train.Survived.value_counts().plot(kind='bar')# 柱状图
plt.title(u"获救情况 (1为获救)") # 标题
plt.ylabel(u"人数")

plt.subplot2grid((2,3),(0,1))
data_train.Pclass.value_counts().plot(kind="bar")
plt.ylabel(u"人数")
plt.title(u"乘客等级分布")

plt.subplot2grid((2,3),(0,2))
plt.scatter(data_train.Survived, data_train.Age)
plt.ylabel(u"年龄")                         # 设定纵坐标名称
plt.grid(b=True, which='major', axis='y')
plt.title(u"按年龄看获救分布 (1为获救)")

plt.subplot2grid((2,3),(1,0), colspan=2)
data_train.Age[data_train.Pclass == 1].plot(kind='kde')
data_train.Age[data_train.Pclass == 2].plot(kind='kde')
data_train.Age[data_train.Pclass == 3].plot(kind='kde')
plt.xlabel(u"年龄")# plots an axis lable
plt.ylabel(u"密度")
plt.title(u"各等级的乘客年龄分布")
plt.legend((u'头等舱', u'2等舱',u'3等舱'),loc='best') # sets our legend for our graph.

plt.subplot2grid((2,3),(1,2))
data_train.Embarked.value_counts().plot(kind='bar')
plt.title(u"各登船口岸上船人数")
plt.ylabel(u"人数")
plt.show()

#看看各乘客等级的获救情况
fig = plt.figure()
fig.set(alpha=0.2)  # 设定图表颜色alpha参数

Survived_0 = data_train.Pclass[data_train.Survived == 0].value_counts()
Survived_1 = data_train.Pclass[data_train.Survived == 1].value_counts()
df=pd.DataFrame({u'获救':Survived_1, u'未获救':Survived_0})
df.plot(kind='bar', stacked=True)
plt.title(u"各乘客等级的获救情况")
plt.xlabel(u"乘客等级")
plt.ylabel(u"人数")
plt.show()


 #然后我们再来看看各种舱级别情况下各性别的获救情况
fig=plt.figure()
fig.set(alpha=0.65) # 设置图像透明度,无所谓
plt.title(u"根据舱等级和性别的获救情况")

ax1=fig.add_subplot(141)
data_train.Survived[data_train.Sex == 'female'][data_train.Pclass != 3].value_counts().plot(kind='bar', label="female highclass", color='#FA2479')
ax1.set_xticklabels([u"获救", u"未获救"], rotation=0)
ax1.legend([u"女性/高级舱"], loc='best')

ax2=fig.add_subplot(142, sharey=ax1)
data_train.Survived[data_train.Sex == 'female'][data_train.Pclass == 3].value_counts().plot(kind='bar', label='female, low class', color='pink')
ax2.set_xticklabels([u"未获救", u"获救"], rotation=0)
plt.legend([u"女性/低级舱"], loc='best')

ax3=fig.add_subplot(143, sharey=ax1)
data_train.Survived[data_train.Sex == 'male'][data_train.Pclass != 3].value_counts().plot(kind='bar', label='male, high class',color='lightblue')
ax3.set_xticklabels([u"未获救", u"获救"], rotation=0)
plt.legend([u"男性/高级舱"], loc='best')

ax4=fig.add_subplot(144, sharey=ax1)
data_train.Survived[data_train.Sex == 'male'][data_train.Pclass == 3].value_counts().plot(kind='bar', label='male low class', color='steelblue')
ax4.set_xticklabels([u"未获救", u"获救"], rotation=0)
plt.legend([u"男性/低级舱"], loc='best')
plt.show()

fig = plt.figure()
fig.set(alpha=0.2)  # 设定图表颜色alpha参数

Survived_0 = data_train.Embarked[data_train.Survived == 0].value_counts()
Survived_1 = data_train.Embarked[data_train.Survived == 1].value_counts()
df=pd.DataFrame({u'获救':Survived_1, u'未获救':Survived_0})
df.plot(kind='bar', stacked=True)
plt.title(u"各登录港口乘客的获救情况")
plt.xlabel(u"登录港口")
plt.ylabel(u"人数")
plt.show()

5. 数据处理

首先,我们需要将所有非数值类型的数据要么转换成数值型数据,要么就去掉。比如说,性别就可以转换成0、1的数值型。再者,对于缺失型数据,如果对我们的后面的模型预测有一定影响,那就需要先将相应的缺失数据进行补充,也就是用已有的数据进行预测这个缺失的数据,比如说年龄。

g = data_train.groupby(['SibSp','Survived'])
df = pd.DataFrame(g.count()['PassengerId'])

g = data_train.groupby(['Parch','Survived'])
df = pd.DataFrame(g.count()['PassengerId'])


from sklearn.ensemble import RandomForestRegressor

### 使用 RandomForestClassifier 填补缺失的年龄属性
def set_missing_ages(df):

    # 把已有的数值型特征取出来丢进Random Forest Regressor中
    age_df = df[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]

    # 乘客分成已知年龄和未知年龄两部分
    known_age = age_df[age_df.Age.notnull()].values
    unknown_age = age_df[age_df.Age.isnull()].values

    # y即目标年龄,所有行的第一列,对应的是年龄值
    y = known_age[:, 0]

    # X即特征属性值,除了年龄外所有的特征值提取出来
    X = known_age[:, 1:]

    # fit到RandomForestRegressor之中
    # n_estimators: 也就是弱学习器的最大迭代次数,或者说最大的弱学习器的个数,默认是10。
    # 一般来说n_estimators太小,容易欠拟合,n_estimators太大,又容易过拟合,一般选择一个适中的数值。
    # 对Random Forest来说,增加“子模型数”(n_estimators)可以明显降低整体模型的方差,且不会对子模型的偏差和方差有任何影响。
    # 模型的准确度会随着“子模型数”的增加而提高,由于减少的是整体模型方差公式的第二项,故准确度的提高有一个上限。
    # 在实际应用中,可以以10为单位,考察取值范围在1至201的调参情况。
    # n_jobs:这个参数告诉引擎有多少处理器是它可以使用。 “-1”意味着没有限制,而“1”值意味着它只能使用一个处理器。
    # random_state:此参数让结果容易复现。 一个确定的随机值将会产生相同的结果,在参数和训练数据不变的情况下
    rfr = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)

    # 使用随机森林拟合数据,返回模型
    rfr.fit(X, y)

    # 用得到的模型进行未知年龄结果预测
    predictedAges = rfr.predict(unknown_age[:, 1::]) # 取下标为1的值,即取所有样本的未知年龄值

    # 用得到的预测结果填补原缺失数据
    df.loc[ (df.Age.isnull()), 'Age' ] = predictedAges

    return df, rfr

def set_Cabin_type(df):
    df.loc[ (df.Cabin.notnull()), 'Cabin' ] = "Yes"
    df.loc[ (df.Cabin.isnull()), 'Cabin' ] = "No"
    return df

data_train, rfr = set_missing_ages(data_train)
data_train = set_Cabin_type(data_train)

# 将类目型的特征使用get_dummies()转换成one-hot编码
# one-hot编码保证了每一个取值只会使得一种状态处于“激活态”,也就是说这N种状态中只有一个状态位值为1,其他状态位都是0。
# dummy encoding 哑变量编码直观的解释就是任意的将一个状态位去除。
# 还是拿上面的例子来说,我们用4个状态位就足够反应上述5个类别的信息,也就是我们仅仅使用前四个状态位 [0,0,0,0] 就可以表达博士了。
# get_dummies 是利用pandas实现one hot encode的方式
dummies_Cabin = pd.get_dummies(data_train['Cabin'], prefix= 'Cabin')

dummies_Embarked = pd.get_dummies(data_train['Embarked'], prefix= 'Embarked')

dummies_Sex = pd.get_dummies(data_train['Sex'], prefix= 'Sex')

dummies_Pclass = pd.get_dummies(data_train['Pclass'], prefix= 'Pclass')

# 将编码后的特征列横向拼接到原数据集上,axis: 需要合并链接的轴,0是行,1是列
df = pd.concat([data_train, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
# 删除掉原来的列,inplace,表明可对原数组作出修改并返回一个新数组
# 默认为False,表明原数组内容并不改变
# 如果将inplace值设定为True,则原数组内容直接被改变。
df.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)

6. 模型训练

import sklearn.preprocessing as preprocessing
# 对于特征值较大的特征,为了保证同等影响最终的分类结果,需要进行标准化
scaler = preprocessing.StandardScaler() #定义标准化的对象

# fit_transform 不仅计算训练数据的均值和方差,还会基于计算出来的均值和方差来转换训练数据,从而把数据转换成标准的正太分布
# fit 用于计算训练数据的均值和方差, 后面就会用均值和方差来转换训练数据
age_scale_param = scaler.fit(df['Age'].values.reshape(-1,1))
df['Age_scaled'] = scaler.fit_transform(df['Age'].values.reshape(-1,1), age_scale_param)
fare_scale_param = scaler.fit(df['Fare'].values.reshape(-1,1))
df['Fare_scaled'] = scaler.fit_transform(df['Fare'].values.reshape(-1,1), fare_scale_param)

from sklearn import linear_model
# 用正则取出我们要的属性值
train_df = df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
train_np = train_df.values

# y即Survival结果
y = train_np[:, 0]

# X即特征属性值
X = train_np[:, 1:]

# fit到RandomForestRegressor之中
clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6, solver='liblinear')
clf.fit(X, y)

7. 模型预测

在预测之前,也是需要将测试数据按照之前训练数据相同的数据处理步骤进行处理。

# 测试数据的数据处理
data_test = pd.read_csv("/Users/chentingxuan/Downloads/Kaggle_Titanic-master/test.csv")
# 将Fare为空的设置为0
data_test.loc[(data_test.Fare.isnull()), 'Fare'] = 0
# 接着我们对test_data做和train_data中一致的特征变换
# 首先用同样的RandomForestRegressor模型填上丢失的年龄
tmp_df = data_test[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]
null_age = tmp_df[data_test.Age.isnull()].values
# 根据特征属性X预测年龄并补上
X = null_age[:, 1:]
predictedAges = rfr.predict(X)
data_test.loc[(data_test.Age.isnull()), 'Age'] = predictedAges

data_test = set_Cabin_type(data_test)
dummies_Cabin = pd.get_dummies(data_test['Cabin'], prefix= 'Cabin')
dummies_Embarked = pd.get_dummies(data_test['Embarked'], prefix= 'Embarked')
dummies_Sex = pd.get_dummies(data_test['Sex'], prefix= 'Sex')
dummies_Pclass = pd.get_dummies(data_test['Pclass'], prefix= 'Pclass')

df_test = pd.concat([data_test, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
df_test.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)
df_test['Age_scaled'] = scaler.fit_transform(df_test['Age'].values.reshape(-1,1), age_scale_param)
df_test['Fare_scaled'] = scaler.fit_transform(df_test['Fare'].values.reshape(-1,1), fare_scale_param)

接下来就是模型预测了,并将预测的结果进行保存

#预测
test = df_test.filter(regex='Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
predictions = clf.predict(test)
result = pd.DataFrame({'PassengerId':data_test['PassengerId'].values, 'Survived':predictions.astype(np.int32)})
result.to_csv("/Users/chentingxuan/Downloads/Kaggle_Titanic-master/logistic_regression_predictions.csv", index=False)

预测的结果如下
在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值