首页 > 搜索 > 泰坦尼克之灾算法,kaggle——泰坦尼克之灾(基于LGBM)

泰坦尼克之灾算法,kaggle——泰坦尼克之灾(基于LGBM)

互联网 2020-10-21 12:13:31
在线算命,八字测算命理
流程观察数据,我们要对数据有所了解,可以参考简书特征工程以及数据清洗介绍模型跑模型修改第二层模型总结1.代码分析

首先,导入我们需要用到的库

import pandas as pdimport numpy as npfrom sklearn.cross_validation import KFoldimport reimport plotly.graph_objs as goimport plotly.offline as pyfrom sklearn.ensemble import (RandomForestClassifier, AdaBoostClassifier,GradientBoostingClassifier, ExtraTreesClassifier)from sklearn.svm import SVCimport xgboost as xgbimport warningswarnings.filterwarnings('ignore')# 忽略warningpd.set_option('display.max_columns', None)# 输出结果显示全部列

然后,导入数据

train = pd.read_csv('train.csv')test = pd.read_csv('test.csv')PassengerId = test['PassengerId']full_data = [train, test]

接下来,我们可以查看我们的数据

# 查看train集的数据print(train.describe())# 查看描述性统计,只能看数值型数据。print(train.info())# 查看数据的信息# print(train.head())# 查看train的前n行数据,默认为前5行1.11.2

从图上我们可以看到,其中有5列不是数值型的,我们需要对其进行转换成数值,而且Age、Cabin这两列是有缺失值的,我们要对其进行填充或者丢弃。

2.特征工程以及数据清洗添加一些新的特征# 添加新的特征,名字的长度train['Name_length'] = train['Name'].apply(len)test['Name_length'] = test['Name'].apply(len)# 乘客在船上是否有船舱train['Has_Cabin'] = train["Cabin"].apply(lambda x: 0 if type(x) == float else 1)test['Has_Cabin'] = test["Cabin"].apply(lambda x: 0 if type(x) == float else 1)# 结合SibSp和Parch创建新的特性FamilySizefor dataset in full_data:dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1

基于特征FamilySize创建新的特征IsAlone,因为一个人的话,顾虑没有那么多,只需要管好自己,生存的几率会大点,其中又分‘male’和‘female’,因为我记得电影中是有这样的一句台词“让女人和小孩先走”,所以,我们有理由相信,女性的生存率会比男性的要高。

for dataset in full_data:dataset['IsAlone'] = 0dataset.loc[dataset['FamilySize'] == 1), 'IsAlone'] = 1

通过name,添加特征Title

# 定义从乘客名中提取新的特征[Title]的函数def get_title(name):title_search = re.search(' ([A-Za-z]+)\.', name)# 如果title存在,提取并返回它。if title_search:return title_search.group(1)return ""# 创建一个新的特征[Title]for dataset in full_data:dataset['Title'] = dataset['Name'].apply(get_title)# 将所有不常见的Title分组为一个“Rare”组for dataset in full_data:dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess', 'Capt', 'Col', 'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss')dataset['Title'] = dataset['Title'].replace('Ms', 'Miss')dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs')缺失值填充Embarked只缺了两个,所以通过统计三个登船地点,选出了登船人数最多的登船地点(s)来填充。Test集的Fare只有一个缺失,所以用了中位数来填充Age缺失的比较多,所以在[age_avg - age_std, age_avg + age_std]这个范围取值来填充(其中age_avg是Age的平均值,age_std是Age的标准差)# 通过统计三个登船地点人数最多的填充缺失值for dataset in full_data:dataset['Embarked'] = dataset['Embarked'].fillna('S')# 缺失值填充,Test集的Fare有一个缺失,按中位数来填充,以及创建一个新的特征[CategoricalFare]for dataset in full_data:dataset['Fare'] = dataset['Fare'].fillna(train['Fare'].median())train['CategoricalFare'] = pd.qcut(train['Fare'], 4)# 缺失值填充,以及创建新的特征[CategoricalAge]for dataset in full_data:age_avg = dataset['Age'].mean()age_std = dataset['Age'].std()age_null_count = dataset['Age'].isnull().sum()age_null_random_list = np.random.randint(age_avg - age_std, age_avg + age_std, size=age_null_count)dataset['Age'][np.isnan(dataset['Age'])] = age_null_random_listdataset['Age'] = dataset['Age'].astype(int)

通过Age,创建新的特征,一会用来给Age分组

train['CategoricalAge'] = pd.cut(train['Age'], 5)print(train['CategoricalAge'])2.1

从图片可以看出,年龄分为了5个范围,所以一会把年龄分为5组(0-4)。

分组以及转换数值

Sex:把性别转为0和1.Embarked:把登船地点转为0、1、2.Fare:把费用分为4组Age:把年龄分为5组

for dataset in full_data:dataset['Sex'] = dataset['Sex'].map({'female': 0, 'male': 1}).astype(int)title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}dataset['Title'] = dataset['Title'].map(title_mapping)dataset['Title'] = dataset['Title'].fillna(0)dataset['Embarked'] = dataset['Embarked'].map({'S': 0, 'C': 1, 'Q': 2}).astype(int)dataset.loc[dataset['Fare']7.91) & (dataset['Fare']14.454) & (dataset['Fare']31, 'Fare'] = 3dataset['Fare'] = dataset['Fare'].astype(int)dataset.loc[dataset['Age']16) & (dataset['Age']32) & (dataset['Age']48) & (dataset['Age']64, 'Age'] = 4特征选择,丢弃一些不必要的特征

PassengerID、Name、Ticket、Cabin、Sibsp等特征丢弃的原因是都已组合成新的特征,所以给予丢弃CategorcalAge、CategoricalFare这些特征创建时是用来查看Age、Fare的分组区间,已使用,所以给予丢弃

drop_elements = ['PassengerId', 'Name', 'Ticket', 'Cabin', 'SibSp']train = train.drop(drop_elements, axis=1)train = train.drop(['CategoricalAge', 'CategoricalFare'], axis=1)test = test.drop(drop_elements, axis=1)# print(train.head())print(train.describe())# print(train.head())2.23.模型介绍

在跑模型之前,先提及一下本次kernels的基础知识,本次使用的是Stacking融合模型,stacking集成模型与《机器学习》提及Bagging与Boosting不同,Bagging与Boosting是用弱模型的结果经过投票加权等方法集成一个新的强模型。而stacking翻译成中文叫做模型堆叠,接下来我们将对stacking进行介绍,是如何将模型堆叠在一起的。

stacking定义

stacking是一种分层模型集成框架。以两层为例,第一层由多个基学习器组成,其输入为原始训练集,第二层的模型则是以第一层基学习器的输出作为训练集进行再训练,从而得到完整的stacking模型。

首先,我们来看一下下面这个图(两层基础),并进行步骤分解

3.1

步骤:

首先将数据分为5份,在stacking的第一层定义5个基模型,其中每个模型选择做一下5折的交叉验证的预测,这样就相当于每个模型将所有数据预测了一遍将第一层5个基模型的输出预测向量,作为第二层模型的特征做训练,做test时,直接将test的数据喂给之前第一层训练好的5个基模型,5个模型预测出的至平均后作为第二层模型的输入第二层使用一个分类器,将前面得出的特征,进行一次分类,因为主要结果在第一层已经预测完成,第二层要求不大(xgboost、LGBM等)即可。Stacking注意事项

第一层的基模型最好是强模型,而第二层的基模型可以放一个简单的分类器,防止过拟合。

第一层基模型的个数不能太小,因为一层模型个数等于第二层分类器的特征维度。大家可以把勉强将其想象成神经网络的第一层神经元的个数,当然这个值也不是越多越好。

第一层的基模型必须“准而不同”,如果有一个性能很差的模型出现在第一层,将会严重影响整个模型融合的效果

本次比赛中部分模型的准确率:- 朴素贝叶斯(Gaussian Naive Bays):72.2%- 随机梯度下降(Stochastic Gradient Descent):76.8%- 感知器(Perceptron):78%- Linear SVC:79.12%- 逻辑回归(Ligistic Regression):80.3%- SVC(support Vector Machines):83.4%- ExtraTreesClassifie: 84.5%- AdaBoostClassifier: 85.6%- 决策树(Decision tree):86.7%- 随机森林(Random Forest):86.7%4. 跑模型

这部分是这个kernels的重点,用的是Stacking。Stacking使用第一级分类器的预测作为对第二级模型的训练输入。我们使用了(RandomForestClassifier, AdaBoostClassifier,GradientBoostingClassifier, ExtraTreesClassifier,Support Vector Classifier)这5个分类器的预测作为下一个分类器(xgboost)的特征。

为什么使用的是这5个模型,其他需求还是这5个模型吗?为什么不用其他如神经网络等强模型呢?这5个模型是当前比赛排名准度率最好的5个强模型,而其他的模型准度较低如逻辑回归(准确率0.80左右,而强模型均在0.83以上),这样会影响堆叠后的准确率,决策树准确率虽然达到86%,但是和随机森林相关性过高,且属于单树模型,容易过拟合,所以选取随机森林。

注意:当碰到其他需求的时候,不一定还是这5个模型,需要进行对其他模型的准确率测试,相关性确认等。

不使用神经网络原因:神经网络不太可控,调参困难,容易出现过拟合等问题较好的神经网络计算量较大,需要很大的数据量,而本次的比赛中Data只有890行,学习速度调整困难,收敛可能发生过快等问题,无法工作

在下面的代码中,我们编写了一个类SklearnHelper,它允许扩展所有Sklearn分类器所共有的内置方法(如train、predict和fit)。这消除了冗余,因为如果我们想调用5个不同的分类器,就不需要编写相同的方法5次。

# 一些有用的参数,下面会用到ntrain = train.shape[0]ntest = test.shape[0]SEED = 0NFOLDS = 5kf = KFold(ntrain, n_folds=NFOLDS, random_state=SEED)class SklearnHelper(object):def __init__(self, clf, seed=0, params=None):params['random_state'] = seedself.clf = clf(**params)def train(self, x_train, y_train):self.clf.fit(x_train, y_train)def predict(self, x):return self.clf.predict(x)def fit(self, x, y):return self.clf.fit(x, y)def feature_importances(self, x, y):return self.clf.fit(x, y).feature_importances_def get_oof(clf, x_train, y_train, x_test):oof_train = np.zeros((ntrain,))oof_test = np.zeros((ntest,))oof_test_skf = np.empty((NFOLDS, ntest))for i, (train_index, test_index) in enumerate(kf):x_tr = x_train[train_index]y_tr = y_train[train_index]x_te = x_train[test_index]clf.train(x_tr, y_tr)oof_train[test_index] = clf.predict(x_te)oof_test_skf[i, :] = clf.predict(x_test)oof_test[:] = oof_test_skf.mean(axis=0)return oof_train.reshape(-1, 1), oof_test.reshape(-1, 1)

现在让我们准备五个学习模型作为我们的第一级分类。这些模型都可以通过Sklearn库方便地调用,如下所示

1.Random Forest classifier2.Extra Trees classifier3.AdaBoost classifer4.Gradient Boosting classifer5.Support Vector Machine

输入上述分类器的参数

# 随机森林的参数rf_params = {'n_jobs': -1,'n_estimators': 100, 'warm_start': True, #'max_features': 0.2,'max_depth': 6,'min_samples_leaf': 2,'max_features': 'sqrt','verbose': 0}# Extra Trees的参数et_params = {'n_jobs': -1,'n_estimators': 100,#'max_features': 0.5,'max_depth': 8,'min_samples_leaf': 2,'verbose': 0}# AdaBoost的参数ada_params = {'n_estimators': 100,'learning_rate': 0.01}# Gradient Boosting的参数gb_params = {'n_estimators': 100, #'max_features': 0.2,'max_depth': 5,'min_samples_leaf': 2,'verbose': 0}# Support Vector Classifier的参数svc_params = {'kernel': 'linear','C': 0.025}第一级分类器# 通过前面定义的SklearnHelper类创建5个对象来表示5个学习模型rf = SklearnHelper(clf=RandomForestClassifier, seed=SEED, params=rf_params)et = SklearnHelper(clf=ExtraTreesClassifier, seed=SEED, params=et_params)ada = SklearnHelper(clf=AdaBoostClassifier, seed=SEED, params=ada_params)gb = SklearnHelper(clf=GradientBoostingClassifier, seed=SEED, params=gb_params)svc = SklearnHelper(clf=SVC, seed=SEED, params=svc_params)# 创建包含train、test的Numpy数组,以提供给我们的模型y_train = train['Survived'].ravel()train = train.drop(['Survived'], axis=1)x_train = train.values# test = test.drop(['Parch', 'Embarked', 'Has_Cabin', 'IsAlone'], axis=1)x_test = test.values#这些将会作为新的特征被使用et_oof_train, et_oof_test = get_oof(et, x_train, y_train, x_test)# Extra Treesrf_oof_train, rf_oof_test = get_oof(rf, x_train, y_train, x_test)# Random Forestada_oof_train, ada_oof_test = get_oof(ada, x_train, y_train, x_test)# AdaBoostgb_oof_train, gb_oof_test = get_oof(gb, x_train, y_train, x_test)# Gradient Boostsvc_oof_train, svc_oof_test = get_oof(svc, x_train, y_train, x_test)# Support Vector Classifier

现在已经获得了我们的第一级预测,我们可以把它看作是一组新的特性,作为下一个分类器的训练数据。

查看各个特征对上述分类器的重要性

rf_features = rf.feature_importances(x_train, y_train)et_features = et.feature_importances(x_train, y_train)ada_features = ada.feature_importances(x_train, y_train)gb_features = gb.feature_importances(x_train, y_train)cols = train.columns.valuesfeature_dataframe = pd.DataFrame({'features': cols, 'Random Forest feature importances': rf_features, 'Extra Treesfeature importances': et_features,'AdaBoost feature importances': ada_features,'Gradient Boost feature importances': gb_features})feature_dataframe['mean'] = feature_dataframe.mean(axis=1)# axis = 1 computes the mean row-wiseprint(feature_dataframe.head(11))4.14.2以图形形式显示各模型对特征的相关性,观察4.34.44.54.7

从图中观察可以知道,第一层模型特征相关性平均后,各特征的相关性相对降低,准而不同”这个要求的。所以第一层五个模型融合是符合的。

画图查看各个分类器的相关性

base_predictions_train = pd.DataFrame( {'RandomForest': rf_oof_train.ravel(), 'ExtraTrees': et_oof_train.ravel(), 'AdaBoost': ada_oof_train.ravel(),'GradientBoost': gb_oof_train.ravel()})data = [go.Heatmap(z= base_predictions_train.astype(float).corr().values ,x=base_predictions_train.columns.values,y= base_predictions_train.columns.values,colorscale='Viridis',showscale=True,reversescale = True)]py.iplot(data, filename='labelled-heatmap')4.8

,这些模型彼此之间的相关性越低,得分越高。

第二级分类器xgboostx_train = np.concatenate((et_oof_train, rf_oof_train, ada_oof_train, gb_oof_train, svc_oof_train), axis=1)x_test = np.concatenate((et_oof_test, rf_oof_test, ada_oof_test, gb_oof_test, svc_oof_test), axis=1)gbm = xgb.XGBClassifier( #learning_rate=0.01, n_estimators=2000, max_depth=4, min_child_weight=2, # gamma=1, gamma=0.9, subsample=0.8, colsample_bytree=0.8, objective='binary:logistic', nthread=-1, scale_pos_weight=1).fit(x_train, y_train)predictions = gbm.predict(x_test)

xgboost参数含义

提交StackingSubmission = pd.DataFrame({'PassengerId': PassengerId,'Survived': predictions})StackingSubmission.to_csv("StackingSubmission.csv", index=False)

提交后的分数如下

4.9

训练所用时间:

4.105.对模型第二层进行修改LGBM与XGBOOST:

XGBoost是在GBDT(梯度提升决策树)基础上发展而来,针对传统GBDT算法做了很多细节改进,包括损失函数、正则化、切分点查找算法优化、稀疏感知算法、并行化算法设计等等

LightGBM 是一个梯度 boosting 框架,使用基于学习算法的决策树。它可以说是分布式的,高效的与以往的算法比较①histogram算法替换了传统的Pre-Sorted,某种意义上是牺牲了精度(但是作者声明实验发现精度影响不大)换取速度,直方图作差构建叶子。(xgboost的分布式实现也是基于直方图的,利于并行)②带有深度限制的按叶子生长 (leaf-wise) 算法代替了传统的(level-wise) 决策树生长策略,提升精度,同时避免过拟合危险。

LightGBM作者对模型的一些解释:https://www.zhihu.com/question/51644470/answer/130946285

两者的结构主要区别:在过滤数据样例寻找分割值时,LightGBM 使用的是全新的技术:基于梯度的单边采样(GOSS);而 XGBoost 则通过预分类算法和直方图算法来确定最优分割。

选择LGBM替换XGBOOST的理由:1.在速度上LGBM比XGBOOST的快十倍甚至百倍以上2.LGBM与xgboost的精度不相上下

将stacking第二层xgboost替换成LGBMlgbm_train = lgbm.Dataset ( data=x_train ,label=y_train)lgbm_params = {'boosting': 'dart' ,'application': 'binary' ,'learning_rate': 0.01 ,'feature_fraction': 0.5 ,'verbose' : -1,'drop_rate': 0.02}cv_results = lgbm.cv ( train_set=lgbm_train , params=lgbm_params , nfold=5 , num_boost_round=600 , early_stopping_rounds=50 , verbose_eval=50 , metrics=['auc'] )optimum_boost_rounds = np.argmax ( cv_results['auc-mean'] )print ( 'Optimum boost rounds = {}'.format ( optimum_boost_rounds ) )print ( 'Best CV result = {}'.format ( np.max ( cv_results['auc-mean'] ) ) )clf = lgbm.train ( train_set=lgbm_train , params=lgbm_params , num_boost_round=optimum_boost_rounds)##预测结果为浮点数,而本次比赛的预测结果需要0,1,所以将其转换predictions = clf.predict ( x_test )predictions = predictions + 0.5predictions = predictions.astype(int)LGBM的重要参数用法:学习控制参数含义用法max_depth树的最大深度当模型过拟合时,可以考虑首先降低 max_depthmin_data_in_leaf叶子可能具有的最小记录数默认20,过拟合时用feature_fraction例如 为0.8时,意味着在每次迭代中随机选择80%的参数来建树boosting 为 random forest 时用bagging_fraction每次迭代时用的数据比例用于加快训练速度和减小过拟合early_stopping_round如果一次验证数据的一个度量在最近的early_stopping_round 回合中没有提高,模型将停止训练 加速分析,减少过多迭代lambda指定正则化0~1min_gain_to_split描述分裂的最小 gainv控制树的有用的分裂max_cat_group在 group 边界上找到分割点当类别数量很多时,找分割点很容易过拟合时核心参数含义用法Task数据的用途选择 train 或者 predictapplication模型的用途选择 regression: 回归时,binary: 二分类时,multiclass: 多分类时boosting要用的算法gbdt, rf: random forest, dart: Dropouts meet Multiple Additive Regression Trees, goss: Gradient-based One-Side Samplingnum_boost_round迭代次数通常 100+learning_rate如果一次验证数据的一个度量在最近的 early_stopping_round 回合中没有提高,模型将停止训练常用 0.1, 0.001, 0.003…num_leaves默认 31devicecpu 或者 gpumetricmae: mean absolute error , mse: mean squared error , binary_logloss: loss for binary classification , multi_logloss: loss for multi classificationIO参数含义max_bin表示 feature 将存入的 bin 的最大数量categorical_feature如果 categorical_features = 0,1,2, 则列 0,1,2是 categorical 变量ignore_column与 categorical_features 类似,只不过不是将特定的列视为categorical,而是完全忽略save_binary这个参数为 true 时,则数据集被保存为二进制文件,下次读数据时速度会变快调参IO parameter含义num_leaves取值应
免责声明:非本网注明原创的信息,皆为程序自动获取互联网,目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责;如此页面有侵犯到您的权益,请给站长发送邮件,并提供相关证明(版权证明、身份证正反面、侵权链接),站长将在收到邮件12小时内删除。

相关阅读

一周热门

查看更多