又到了假期,忙碌了一个学期,终于可以休息一下了。
一直想再Kaggle上参加一次比赛,在学校要上课,还跟老师做个项目,现在有时间了,就马上用Kaggle的入门比赛试试手。
一场比赛,总的来说收获不小,平时学习的时候总是眼高手低,结果中间出现令人吐血的失误 >_<
Kaggle比赛介绍
简而言之,Kaggle 是玩数据、ML 的开发者们展示功力、扬名立万的江湖,网址:https://www.kaggle.com/
Kaggle虽然高手云集,但是对于萌新们来说也是非常友好的,这次的Titanic问题就是适合萌新Getting Started的入门题。
Kaggle 是当今最大的数据科学家、机器学习开发者社区,其行业地位独一无二。
(此话引用自谷歌收购 Kaggle 为什么会震动三界(AI、机器学习、数据科学界)? )
Titanic问题概述
Titanic: Machine Learning from Disaster
比赛说明 RMS泰坦尼克号的沉没是历史上最臭名昭着的沉船之一。 1912年4月15日,在首航期间,泰坦尼克号撞上一座冰山后沉没,2224名乘客和机组人员中有1502人遇难。这一耸人听闻的悲剧震撼了国际社会,导致了更好的船舶安全条例。
沉船导致生命损失的原因之一是乘客和船员没有足够的救生艇。虽然幸存下来的运气有一些因素,但一些人比其他人更有可能生存,比如妇女,儿童和上层阶级。
在这个挑战中,我们要求你完成对什么样的人可能生存的分析。特别是,我们要求你运用机器学习的工具来预测哪些乘客幸存下来的悲剧。
目标 这是你的工作,以预测是否有乘客幸存下来的泰坦尼克号或不。 对于测试集中的每个PassengerId,您必须预测Survived变量的0或1值。
度量值 您的分数是您正确预测的乘客的百分比。这被称为“准确性”。
提交文档格式 你应该提交一个csv文档,正好有418个条目和一个标题行。如果您有额外的列(超出PassengerId和Survived)或行,您的提交将会显示错误。
该文档应该有2列:
PassengerId(按任意顺序排序) 生存(包含你的二元预测:1存活,0死亡)
数据总览
首先,我们先把一些库和训练数据导入
1 2 3 4 5 6 7
import osimport numpy as npimport pandas as pdimport tensorflow as tftrain_data = pd.read_csv('train.csv' ) print(train_data.info())
简单的看一下训练数据的信息,其中Embarked有两个缺失值,Age缺失值较多,Cabin有效值太少了跟本没什么用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
> <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 > None >
数据清洗
在我们开始搭建神经网络进行训练之前,数据清洗是必要的。这一步可以简单一些,不过如果想要得到更好的效果,清洗之前的数据分析还是不可少的。这里的数据分析,我就不再赘述了,给大家推荐一篇博客,上面有很详细的分析过程——Kaggle_Titanic生存预测
我们用随机森林算法,对’Age’的缺失值进行预测,当然这里也可以用其他回归算法,来进行预测
1 2 3 4 5 6 7 8 9 10
from sklearn.ensemble import RandomForestRegressorage = train_data[['Age' ,'Survived' ,'Fare' ,'Parch' ,'SibSp' ,'Pclass' ]] age_notnull = age.loc[(train_data.Age.notnull())] age_isnull = age.loc[(train_data.Age.isnull())] X = age_notnull.values[:,1 :] Y = age_notnull.values[:,0 ] rfr = RandomForestRegressor(n_estimators=1000 ,n_jobs=-1 ) rfr.fit(X,Y) predictAges = rfr.predict(age_isnull.values[:,1 :]) train_data.loc[(train_data.Age.isnull()),'Age' ] = predictAges
如果对上一步觉得太麻烦,或不喜欢的话,可以更简单一点,直接把缺失值都给0
1
train_data = train_data.fillna(0 )
然后,对于性别’Sex’,我们将其二值化’male’为0,’female’为1
1 2
train_data.loc[train_data['Sex' ]=='male' ,'Sex' ] = 0 train_data.loc[train_data['Sex' ]=='female' ,'Sex' ] = 1
我们把’Embarked’也填补下缺失值,因为缺失值较少,所以我们直接给它填补上它的众数’S’,把’S’,’C’,’Q’定性转换为0,1,2,这样便于机器进行学习
1 2 3 4
train_data['Embarked' ] = train_data['Embarked' ].fillna('S' ) train_data.loc[train_data['Embarked' ] == 'S' ,'Embarked' ] = 0 train_data.loc[train_data['Embarked' ] == 'C' ,'Embarked' ] = 1 train_data.loc[train_data['Embarked' ] == 'Q' ,'Embarked' ] = 2
最后,把’Cabin’这个与生存关系不重要而且有效数据极少的标签丢掉,再加上一个’Deceased’,代表的是是否遇难,这一步很重要,很重要,很重要!我在做的时候没加这个,后面网络的y的标签我也只设了1,训练出的模型跟没训练一样,所有的都是0。发现的时候,死的心都有了╥﹏╥…(希望不会有初学者和我犯一样的错误 ToT )
1 2
train_data.drop(['Cabin' ],axis=1 ,inplace=True ) train_data['Deceased' ] = train_data['Survived' ].apply(lambda s: 1 - s)
然后,我们再查看一下数据信息
这次信息就整齐多了
模型搭建
现在我们把数据的X,Y进行分离,这里我们只选取了6个标签作为X,如果想让结果尽可能准确,请读者自行完善。
1 2
dataset_X = train_data[['Sex' ,'Age' ,'Pclass' ,'SibSp' ,'Parch' ,'Fare' ]] dataset_Y = train_data[['Deceased' ,'Survived' ]]
这里,我们进行训练集和验证集的划分,在训练过程中,我们可以更好的观察训练情况,避免过拟合
1 2 3 4 5
from sklearn.model_selection import train_test_splitX_train,X_val,Y_train,Y_val = train_test_split(dataset_X.as_matrix(), dataset_Y.as_matrix(), test_size = 0.2 , random_state = 42 )
做完以上工作,我们就可以开始搭建神经网络了,这里,我搭建的是一个简单两层的神经网络,激活函数使用的是线性整流函数Relu,并使用了交叉验证和Adam优化器(也可以使用梯度下降进行优化),设置学习率为0.001
1 2 3 4 5 6 7 8 9 10 11 12 13
x = tf.placeholder(tf.float32,shape = [None ,6 ],name = 'input' ) y = tf.placeholder(tf.float32,shape = [None ,2 ],name = 'label' ) weights1 = tf.Variable(tf.random_normal([6 ,6 ]),name = 'weights1' ) bias1 = tf.Variable(tf.zeros([6 ]),name = 'bias1' ) a = tf.nn.relu(tf.matmul(x,weights1) + bias1) weights2 = tf.Variable(tf.random_normal([6 ,2 ]),name = 'weights2' ) bias2 = tf.Variable(tf.zeros([2 ]),name = 'bias2' ) z = tf.matmul(a,weights2) + bias2 y_pred = tf.nn.softmax(z) cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=z)) correct_pred = tf.equal(tf.argmax(y,1 ),tf.argmax(y_pred,1 )) acc_op = tf.reduce_mean(tf.cast(correct_pred,tf.float32)) train_op = tf.train.AdamOptimizer(0.001 ).minimize(cost)
下面开始训练,训练之前我先定义了个Saver,epoch为30次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
saver = tf.train.Saver() ckpt_dir = './ckpt_dir' if not os.path.exists(ckpt_dir): os.makedirs(ckpt_dir) with tf.Session() as sess: tf.global_variables_initializer().run() ckpt = tf.train.latest_checkpoint(ckpt_dir) if ckpt: print('Restoring from checkpoint: %s' % ckpt) saver.restore(sess, ckpt) for epoch in range(30 ): total_loss = 0. for i in range(len(X_train)): feed_dict = {x: [X_train[i]],y:[Y_train[i]]} _,loss = sess.run([train_op,cost],feed_dict=feed_dict) total_loss +=loss print('Epoch: %4d, total loss = %.12f' % (epoch,total_loss)) if epoch % 10 == 0 : accuracy = sess.run(acc_op,feed_dict={x:X_val,y:Y_val}) print("Accuracy on validation set: %.9f" % accuracy) saver.save(sess, ckpt_dir + '/logistic.ckpt' ) print('training complete!' ) accuracy = sess.run(acc_op,feed_dict={x:X_val,y:Y_val}) print("Accuracy on validation set: %.9f" % accuracy) pred = sess.run(y_pred,feed_dict={x:X_val}) correct = np.equal(np.argmax(pred,1 ),np.argmax(Y_val,1 )) numpy_accuracy = np.mean(correct.astype(np.float32)) print("Accuracy on validation set (numpy): %.9f" % numpy_accuracy) saver.save(sess, ckpt_dir + '/logistic.ckpt' ) ''' 测试数据的清洗和训练数据一样,两者可以共同完成 ''' test_data = pd.read_csv('test.csv' ) test_data.loc[test_data['Sex' ]=='male' ,'Sex' ] = 0 test_data.loc[test_data['Sex' ]=='female' ,'Sex' ] = 1 age = test_data[['Age' ,'Sex' ,'Parch' ,'SibSp' ,'Pclass' ]] age_notnull = age.loc[(test_data.Age.notnull())] age_isnull = age.loc[(test_data.Age.isnull())] X = age_notnull.values[:,1 :] Y = age_notnull.values[:,0 ] rfr = RandomForestRegressor(n_estimators=1000 ,n_jobs=-1 ) rfr.fit(X,Y) predictAges = rfr.predict(age_isnull.values[:,1 :]) test_data.loc[(test_data.Age.isnull()),'Age' ] = predictAges test_data['Embarked' ] = test_data['Embarked' ].fillna('S' ) test_data.loc[test_data['Embarked' ] == 'S' ,'Embarked' ] = 0 test_data.loc[test_data['Embarked' ] == 'C' ,'Embarked' ] = 1 test_data.loc[test_data['Embarked' ] == 'Q' ,'Embarked' ] = 2 test_data.drop(['Cabin' ],axis=1 ,inplace=True ) X_test = test_data[['Sex' , 'Age' , 'Pclass' , 'SibSp' , 'Parch' , 'Fare' ]] predictions = np.argmax(sess.run(y_pred, feed_dict={x: X_test}), 1 ) submission = pd.DataFrame({ "PassengerId" : test_data["PassengerId" ], "Survived" : predictions }) submission.to_csv("titanic-submission.csv" , index=False )
我们把生成的提交文档在Kaggle官网上进行提交,Score为0.79425,效果还可以,不过还有很多需要改进的地方
参考文章
Kaggle_Titanic生存预测 — 详细流程吐血梳理
谷歌收购 Kaggle 为什么会震动三界(AI、机器学习、数据科学界)?
《深度学习原理与TensorFlow实践》课程代码
原文链接 大专栏 https://www.dazhuanlan.com/2019/08/22/5d5e12350518e/