机器学习(十一)使用sklearn对kaggle的Titanic进行建模

时间:2021-08-12 20:06:41

转自寒老师的七月算法ML课程
数据集下载地址:https://www.kaggle.com/c/titanic

# -*- coding: utf-8 -*-
"""
Created on Tue Nov 01 09:04:12 2016

@author: Sirius

kaggle上的Titanic经典案例,建立一个模型,预测乘客是否获救,二分类问题
记:寒老师七月算法ML课程课后笔记
"""


import pandas as pd
import numpy as np

data_train=pd.read_csv('train.csv')
data_test=pd.read_csv('test.csv')

"""
trian数据集,11个属性+1获救情况
Index
PassengerId => 乘客ID --891
Pclass => 乘客等级(1/2/3等舱位) --891 --离散值
Name => 乘客姓名 --891 --文本特征
Sex => 性别 --891 --离散值
Age => 年龄 --714,不全 --连续值
SibSp => 堂兄弟/妹个数 --891 --离散值
Parch => 父母与小孩个数 --891 --离散值
Ticket => 船票信息 --891 --文本信息
Fare => 票价 --891 --连续值
Cabin => 客舱--204,不全
Embarked => 登船港口 --889 --离散值
"""


"""
通过对数据进行统计分析,Age和Cabin这两个属性对是否获救的影响很大,因此要设法不全
通常遇到缺值的情况,我们会有几种常见的处理方式:---
1.如果缺值的样本占总数比例极高,我们可能就直接舍弃了,作为特征加入的话,
可能反倒带入noise,影响最后的结果了。
2.如果缺值的样本适中,而该属性非连续值特征属性(比如说类目属性),
那就把NaN作为一个新类别,加到类别特征中。
3.如果缺值的样本适中,而该属性为连续值特征属性,有时候我们会考
虑给定一个step(比如这里的age,我们可以考虑每隔2/3岁为一个步长),
然后把它离散化,之后把NaN作为一个type加到属性类目中。
4.有些情况下,缺失的值个数并不是特别多,那我们也可以试着根据已有的值,拟合一下数据,补充上。
本例中,后两种处理方式应该都是可行的,我们先试试拟合补全吧(虽然说没有
特别多的背景可供我们拟合,这不一定是一个多么好的选择)
"""


#由于Cabin缺失的值较多,因此用方式2处理,有cabin信息则为1,没有则为0
def set_Cabin_type(df):
df.loc[(df.Cabin.notnull()),'Cabin']='Yes'
df.loc[(df.Cabin.isnull()),'Cabin']='No'
return df
data_train=set_Cabin_type(data_train)

#Age信息缺失适中,通过RandForest拟合
from sklearn.ensemble import RandomForestRegressor

def set_missing_ages(df):
#把已有数值型特征喂给RandomForestRegressor
age_df=df[['Age','Fare','Parch','SibSp','Pclass']]

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=2000,n_jobs=-1)
rfr.fit(X,y)

predictedAges=rfr.predict(unknown_age[:,1::])

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

return df,rfr

data_train,rfr=set_missing_ages(data_train)


"""
----------------------对离散值特征进行one-hot编码处理----------------------------

以Embarked为例,原本一个属性维度,因为其取值可以是[‘S’,’C’,’Q‘],而将其平展开为’Embarked_C’,’Embarked_S’, ‘Embarked_Q’三个属性
原本Embarked取值为S的,在此处的”Embarked_S”下取值为1,在’Embarked_C’, ‘Embarked_Q’下取值为0
原本Embarked取值为C的,在此处的”Embarked_C”下取值为1,在’Embarked_S’, ‘Embarked_Q’下取值为0
原本Embarked取值为Q的,在此处的”Embarked_Q”下取值为1,在’Embarked_C’, ‘Embarked_S’下取值为0

"""

#Cabin原本只有yes和no,现在扩展为Cabin_yes和Cabin_no两个属性
dummies_Cabin=pd.get_dummies(data_train['Cabin'],prefix='Cabin')

#Embarked由原来三个值S\C\Q扩展为Embarked_C、Embarked_S、Embarked_C三个属性
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')

df=pd.concat([data_train,dummies_Cabin,dummies_Embarked,dummies_Sex,dummies_Pclass],axis=1)

df.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)



"""
-------------------------对连续值特征进行标准化------------------------
"""

import sklearn.preprocessing as preprocessing
scaler=preprocessing.StandardScaler()
age_scaler_param=scaler.fit(df['Age'])
df['Age_scaled']=scaler.fit_transform(df['Age'],age_scaler_param)

fare_scale_param = scaler.fit(df['Fare'])
df['Fare_scaled'] = scaler.fit_transform(df['Fare'], fare_scale_param)



"""
-----------------------向量化,转为numpy格式矩阵---------------------------
"""

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=train_np[:,0]#survival的结果

X=train_np[:,1:]

clf=linear_model.LogisticRegression(C=1.0,penalty='l1',tol=1e-6) #L1正则,惩罚因子1,最终误差在1e-6下
clf.fit(X,y)
model_score=clf.score(X,y) #0.809

"""
------------------对测试集数据进行相同的处理和预测------------------------------

"""


data_test.loc[(data_test.Fare.isnull()),'Fare']=0

tmp_df=data_test[['Age','Fare','Parch','SibSp','Pclass']]
null_age=tmp_df[data_test.Age.isnull()].as_matrix()
X1=null_age[:,1:]
#用同样的特征属性X输入到RandomForestRegressor中,填补年龄空缺
predictedAge=rfr.predict(X1)
data_test.loc[(data_test.Age.isnull()),'Age']=predictedAge

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'], age_scaler_param)
df_test['Fare_scaled'] = scaler.fit_transform(df_test['Fare'], 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'].as_matrix(),'Survived':predictions.astype(np.int32)})
result.to_csv("logistic_regression_predictions1.csv",index=False)

da=pd.read_csv("logistic_regression_predictions1.csv")




"""
-------------------------通过交叉验证判断模型是否过拟合----------------------------------------
"""

import numpy as np
import matplotlib.pyplot as plt
from sklearn.learning_curve import learning_curve

# 用sklearn的learning_curve得到training_score和cv_score,使用matplotlib画出learning curve
def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None, n_jobs=1,
train_sizes=np.linspace(.05, 1., 20), verbose=0, plot=True)
:

"""
画出data在某模型上的learning curve.
参数解释
----------
estimator : 你用的分类器。
title : 表格的标题。
X : 输入的feature,numpy类型
y : 输入的target vector
ylim : tuple格式的(ymin, ymax), 设定图像中纵坐标的最低点和最高点
cv : 做cross-validation的时候,数据分成的份数,其中一份作为cv集,其余n-1份作为training(默认为3份)
n_jobs : 并行的的任务数(默认1)
"""

train_sizes, train_scores, test_scores = learning_curve(
estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes, verbose=verbose)

train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)

if plot:
plt.figure()
plt.title(title)
if ylim is not None:
plt.ylim(*ylim)
plt.xlabel(u"训练样本数")
plt.ylabel(u"得分")
plt.gca().invert_yaxis()
plt.grid()

plt.fill_between(train_sizes, train_scores_mean - train_scores_std, train_scores_mean + train_scores_std,
alpha=0.1, color="b")
plt.fill_between(train_sizes, test_scores_mean - test_scores_std, test_scores_mean + test_scores_std,
alpha=0.1, color="r")
plt.plot(train_sizes, train_scores_mean, 'o-', color="b", label=u"训练集上得分")
plt.plot(train_sizes, test_scores_mean, 'o-', color="r", label=u"交叉验证集上得分")

plt.legend(loc="best")

plt.draw()
plt.gca().invert_yaxis()
plt.show()

midpoint = ((train_scores_mean[-1] + train_scores_std[-1]) + (test_scores_mean[-1] - test_scores_std[-1])) / 2
diff = (train_scores_mean[-1] + train_scores_std[-1]) - (test_scores_mean[-1] - test_scores_std[-1])
return midpoint, diff

#plot_learning_curve(clf, u"学习曲线", X, y)

"""
从learning curve上没有发现过拟合现象(overfitting的表现一般是训练集上得分高,
而交叉验证集上要低很多,中间的gap比较大),因此可以再mining些feature来训练
"""


#通过模型系数theta来查看各个属性与结果的相关程度
pd.DataFrame({"columes":list(train_df.columns)[1:],"coef":list(clf.coef_.T)})
"""
正相关和负相关
coef columes
0 [-0.3442288083] SibSp
1 [-0.104931485646] Parch
2 [0.0] Cabin_No
3 [0.902141633979] Cabin_Yes 有cabin信息获救几率大
4 [0.0] Embarked_C
5 [0.0] Embarked_Q
6 [-0.417262701772] Embarked_S
7 [1.95657801471] Sex_female 女性获救几率大,正相关
8 [-0.677418530198] Sex_male 头等舱获救几率大
9 [0.341141757161] Pclass_1
10 [0.0] Pclass_2
11 [-1.19414131133] Pclass_3
12 [-0.523782222235] Age_scaled 年龄越小获救的几率越大,负相关
13 [0.0844327966037] Fare_scaled
"""




"""
-------------一般是把linearRegressor作为baseline,然后使用不同的分类器比如SVM、RadomForest、NN等--------

"""



"""
假设现在模型出现overfitting,那我们干脆就不要用全部的训练集,每次取训练集的一个subset,做训练,这样,
我们虽然用的是同一个机器学习算法,但是得到的模型却是不一样的;同时,因为我们没有任何一份子数据集是全的,因此即使出现过拟合,
也是在子训练集上出现过拟合,而不是全体数据上,这样做一个融合,可能对最后的结果有一定的帮助。对,这就是常用的Bagging。
"""


from sklearn.ensemble import BaggingRegressor

train_df=df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass.*|Mother|Child|Family|Title')
train_np=train_df.as_matrix()

y=train_np[:,0]
X=train_np[:,1:]

clf=linear_model.LogisticRegression(C=1.0,penalty='l1',tol=1e-6)
bagging_clf=BaggingRegressor(clf,n_estimators=10,max_samples=0.8,max_features=1.0,
bootstrap=True,bootstrap_features=False,n_jobs=1)
bagging_clf.fit(X,y)


test_df=df.filter(regex='Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass.*|Mother|Child|Family|Title')
predictions=bagging_clf.predict(test)
result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions.astype(np.int32)})
result.to_csv("logistic_regression_predictions2.csv", index=False)