机器学习kaggle比赛—泰坦尼克号获救预测 二

介绍

上篇文章建立了Base model,准确率76.555%,今天要做的是提升预测准确率,主要是两个方面:

1. 交叉验证:在给定的训练集中,拿出大部分样本进行建模,留小部分样本用刚建立的模型进行预测,并求这小部分样本的预测误差,记录它们的平方加和。

2. 模型融合:通过对多个单模型融合以提升整体性能

交叉验证

通常做交叉验证,我们把训练集的数据分成两部分,一部分用于训练我们需要的模型,另外一部分数据上看我们预测算法的效果。用scikit-learn的cross_validation来完成这个工作。

我们这次还要把验证失败的item都拿出来,分析一下为什么预测错了,然后再改进。代码如下:

split_train, split_cv = cross_validation.train_test_split(df, test_size=0.3, random_state=0)

train_df = split_train.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')

clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)

clf.fit(train_df.as_matrix()[:,1:], train_df.as_matrix()[:,0])

cv_df = split_cv.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')

predictions = clf.predict(cv_df.as_matrix()[:,1:])

origin_data_train = pd.read_csv("Train.csv")

bad_cases = origin_data_train.loc[origin_data_train['PassengerId'].isin(split_cv[predictions != cv_df.as_matrix()[:,0]]['PassengerId'].values)]

bad_cases

得到这样的错误数据,更深一些的分析特征:

可以添加字段来表示是否是小孩,条件是age<10

Parch表示父母和小孩个数,如果名字中有Mrs,并且Parch>1,可以判断是一名母亲

Embarked登船口这个属性好像作用不大,先去掉

对年龄按步长做离散化处理,形成单独的特征

过拟合 欠拟合

有一种情况是在做机器学习经常发生的,就是在用训练集数据去做预测的时候,准确率很高,一切看起来都很美好,但是当用测试集数据去做预测的时候,发现效果不好,这种情况就是过拟合。

过拟合更通俗一点讲就是,比如小智考驾照天天练倒车,练的非常好,教练的口诀记得很清楚“向左方向打一圈,走两秒,打死,走3秒,回正,走到底,完成”,但是拿到驾照后在自己家的车库里倒车的时候,刮的,擦的掉漆。因为实际车库没有那么标准,旁边的车停的位置有时候也不正,靠墙的车位和中间的车位倒法都不一样,最重要的是,缺少一位老司机在旁边。

欠拟合就像是这样,小智太懒考驾照的时候没有怎么练习,教练说“开车一定多练才能开好,开好了才能拿到驾照”,小智一听急了,从包里掏出了两万块钱,说“这样能拿到驾照吗”,教练说“再加两万,就可以”,小智毫不犹豫从包里再拿出两万甩在了副驾驶座上。等小智拿到驾照后,回到自己家车库去倒车,结果更悲剧,因为根本就没怎么练。

而在机器学习的问题上,对于过拟合和欠拟合两种情形。我们优化的方式是不同的:

对过拟合而言,通常以下策略对结果优化是有用的:

做一下feature selection,挑出较好的feature的subset来做training

提供更多的数据,从而弥补原始数据的bias问题,学习到的model也会更准确

而对于欠拟合而言,我们通常需要更多的feature,更复杂的模型来提高准确度。

模型融合

模型融合可以比较好地缓解,训练过程中产生的过拟合问题,从而对于结果的准确度提升有一定的帮助。比如分类问题,当我们手头上有一堆在同一份数据集上训练得到的分类器(比如logistic regression,SVM,KNN,random forest,神经网络),那我们让他们都分别去做判定,然后对结果做投票统计,取票数最多的结果为最后结果。

我们来做一个bagging,就是说不要用全部的训练集,每次取训练集的一个子集,做训练,这样,我们虽然用的是同一个机器学习算法,但是得到的模型却是不一样的;同时,因为我们没有任何一份子数据集是全的,因此即使出现过拟合,也是在子训练集上出现过拟合,而不是全体数据上,这样做一个融合。

使用sk-learn中的bagging方法,代码如下:

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=20, max_samples=0.8, max_features=1.0, bootstrap=True, bootstrap_features=False, n_jobs=-1)

bagging_clf.fit(X, y)

test = df_test.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_bagging_predictions.csv", index=False)

上传kaggle验证后,得出结果是从7000多名上升到1206名,准确率80.382%

总结

介绍了交叉验证,过拟合,欠拟合,模型融合的概念,优化了base model,提升了准确率。

同学们可以从sk-learn这个框架开始学习机器学习,很全面,使用起来方便,还有一个非常简单易懂的使用指南,地址:http://scikit-learn.org/stable/user_guide.html

建议还是稳扎稳打,不建议刚开始就学深度学习,去用Tensorflow;在微积分线性代数,标量向量张量都弄不清楚的情况下,即使按照教程做出来一些小demo,作用也不大,而且还有可能会养成知其然,不知其所以然的坏习惯,会有种假象是我会用就行了,不需要知道原理;千万不要有这种想法,非常坑人,尤其是程序员,如果只停留在会用的层面上,不去看源码,不去探求底层原理的话,则水平会很有限。