4. 机器学习实战 之 泰坦尼克号生存预测问题

学习机器学习的小伙伴,在入门的时候可以通过相对赶紧简单和干净的数据入门。 最常用的数据集就是我在之前写的MNIST,波士顿房价,还有今天要给大家介绍的泰坦尼克号生存预测问题。

泰坦尼克号的故事背景大家一定都非常熟悉了,下面我们一起来探索一下相关数据,以及看看如何用机器学习的方法进行分类预测。

数据加载

本数据也是Kaggle平台的入门数据之一,可以同Kaggle平台下载训练数据和测试数据,这个竞赛项目也是长年开放的,大家也可以将自己的预测结果上传到Kaggle上。
https://www.kaggle.com/c/titanic/data

import pandas as pd
train_data = pd.read_csv("train.csv")

#预览一下数据
train_data.head()
PassengerId	Survived	Pclass	Name	Sex	Age	SibSp	Parch	Ticket	Fare	Cabin	Embarked
0	1	0	3	Braund, Mr. Owen Harris	male	22.0	1	0	A/5 21171	7.2500	NaN	S
1	2	1	1	Cumings, Mrs. John Bradley (Florence Briggs Th...	female	38.0	1	0	PC 17599	71.2833	C85	C
2	3	1	3	Heikkinen, Miss. Laina	female	26.0	0	0	STON/O2. 3101282	7.9250	NaN	S
3	4	1	1	Futrelle, Mrs. Jacques Heath (Lily May Peel)	female	35.0	1	0	113803	53.1000	C123	S
4	5	0	3	Allen, Mr. William Henry	male	35.0	0	0	373450	8.0500	NaN	S

print(train_data.shape)
(891, 12)

train_data.info()
<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.7+ KB

#可以看到有一些列 比如Cabin,Age有非常多的缺失值

缺失值处理

泰坦尼克号的数据预处理有两点非常值得大家练手,首先就是缺失值处理,可以看到Cabin和Age是有相当多的缺失值的。

缺失值常见处理方式:

  1. 如果缺值的样本占总数比例极高,可以直接舍弃了,否则作为特征可能会有带来噪声,影响结果
  2. 如果缺值的样本数适中,且该特征是非连续值(离散),可以把NaN作为一个类别Category,加到类别特征中
  3. 如果缺值的样本数适中,且该属性为连续值,可以考虑给定一个step(比如这里的age,可以考虑每隔2/3岁为一个步长),然后把它离散化,之后把NaN作为一个category加类别特征中
  4. 有些情况下,缺失的值个数并不是特别多,那我们也可以试着根据已有的值,拟合一下数据,补充上

处理Cabin缺失值
在决定处理之前不妨先看一下Cabin分布情况。

Cabin = train_data['Cabin']
Cabin.value_counts()

B96 B98        4
C23 C25 C27    4
G6             4
E101           3
D              3
              ..
F38            1
C50            1
A5             1
C91            1
E63            1
Name: Cabin, Length: 147, dtype: int64

可以看到Cabin的值比较分散,Cabin值基本出现不大于4次,很多都只出现一次。
下面看一下Cabin的有无对Survive与否的影响。

import matplotlib.pyplot as plt
%matplotlib inline

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

Survived_nocabin = train_data.Survived[pd.isnull(train_data.Cabin)].value_counts()
Survived_cabine = train_data.Survived[pd.notnull(train_data.Cabin)].value_counts()
df=pd.DataFrame({u'with Cabin':Survived_cabin, u'without Cabin':Survived_nocabin}).transpose()
df.plot(kind='bar', stacked=True)
plt.title(u"Cabin and Survived Situation")
plt.xlabel(u"with Cabin or not ") 
plt.ylabel(u"Number of people")
plt.show()

有Cabin记录的乘客survival 比例稍高, 可以采用缺失值处理的第二种方法,把这个值分成两个特征,有cabin和无cabin。
4. 机器学习实战 之 泰坦尼克号生存预测问题_第1张图片
处理Age缺失值
Age属性有177个乘客没有记录, 可以用方法3或者方法4, 下面我们一起来试一下方法4.
用随机森林拟合一下缺失的年龄数据

### 使用 RandomForestClassifier 填补缺失的年龄属性
def set_missing_ages(df):
 
    # 把已有的数值型特征取出来丢进RandomForestRegressor中
    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之中
    rfr = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)
    rfr.fit(X, y)
    
    # 用得到的模型进行未知年龄结果预测
    predictedAges = rfr.predict(unknown_age[:, 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


train_data, rfr = set_missing_ages(train_data)
train_data = set_Cabin_type(train_data)

然后再看一下数据概况

train_data.info()

<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            891 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          891 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB

最后一步准备数据特征

# 因为逻辑回归建模时,需要输入的特征都是数值型特征
# 我们先对类目型的特征离散/因子化
# 以Cabin为例,原本一个属性维度,因为其取值可以是['yes','no'],而将其平展开为'Cabin_yes','Cabin_no'两个属性
# 原本Cabin取值为yes的,在此处的'Cabin_yes'下取值为1,在'Cabin_no'下取值为0
# 原本Cabin取值为no的,在此处的'Cabin_yes'下取值为0,在'Cabin_no'下取值为1
# 我们使用pandas的get_dummies来完成这个工作,并拼接在原来的data_train之上,如下所示
dummies_Cabin = pd.get_dummies(train_data['Cabin'], prefix= 'Cabin')
dummies_Embarked = pd.get_dummies(train_data['Embarked'], prefix= 'Embarked')
dummies_Sex = pd.get_dummies(train_data['Sex'], prefix= 'Sex')
dummies_Pclass = pd.get_dummies(train_data['Pclass'], prefix= 'Pclass')
df = pd.concat([train_data, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
df.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)
df


PassengerId	Survived	Age	SibSp	Parch	Fare	Cabin_No	Cabin_Yes	Embarked_C	Embarked_Q	Embarked_S	Sex_female	Sex_male	Pclass_1	Pclass_2	Pclass_3
0	1	0	22.00000	1	0	7.2500	1	0	0	0	1	0	1	0	0	1
1	2	1	38.00000	1	0	71.2833	0	1	1	0	0	1	0	1	0	0
2	3	1	26.00000	0	0	7.9250	1	0	0	0	1	1	0	0	0	1
3	4	1	35.00000	1	0	53.1000	0	1	0	0	1	1	0	1	0	0
4	5	0	35.00000	0	0	8.0500	1	0	0	0	1	0	1	0	0	1
...	...	...	...	...	...	...	...	...	...	...	...	...	...	...	...	...
886	887	0	27.00000	0	0	13.0000	1	0	0	0	1	0	1	0	1	0
887	888	1	19.00000	0	0	30.0000	0	1	0	0	1	1	0	1	0	0
888	889	0	16.19395	1	2	23.4500	1	0	0	0	1	1	0	0	0	1
889	890	1	26.00000	0	0	30.0000	0	1	1	0	0	0	1	1	0	0
890	891	0	32.00000	0	0	7.7500	1	0	0	1	0	0	1	0	0	1
891 rows × 16 columns

看一下协方差

correlation_matrix = df.corr().round(2)
sns.heatmap(data=correlation_matrix,annot=True)

数据预处理

# 接下来我们要接着做一些数据预处理的工作,比如scaling,将一些变化幅度较大的特征化到[-1,1]之内
# 这样可以加速logistic regression的收敛
import sklearn.preprocessing as preprocessing
scaler = preprocessing.StandardScaler()
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)
df
# 我们把需要的feature字段取出来,转成numpy格式,使用scikit-learn中的LogisticRegression建模
from sklearn import linear_model

train_df = df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
train_np = train_df.as_matrix()
# 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)
clf.fit(X, y)   
clf

你可能感兴趣的:(机器学习)