kaggle比赛入门

数据分析项目小试牛刀——kaggle经典案例

过去的一学期中,上了一门叫做《非参数统计》的课程,老师的要求是用latex或者Rmarkdown写作业,编程语言必须用R。课程结束发现自己成绩还不错,回顾这一学期,每次的作业书写对我的帮助很大:将零零散散的知识框架和代码整理成册,是一种复习也是学习的好方法。kaggle的这个泰坦尼克号的案例在最开始接触python数据分析的时候就做过,现将代码思路整理处理,作为自己参加kaggle比赛的练习案例。其中也有参考过别人的做法,将其做了融合。

数据基本结构了解

进行数据分析前,首先要明确目的,然后拿到的数据集做大致的了解。

载入数据

1、数据集:
训练集:乘客ID(passengerID)、是否被救(Survivd)、船舱等级(Pclass)、Name(姓名)、性别(Sex)、年龄(Age)、兄弟姐妹和配偶数(SibSp)、父母和孩子数(Parch)、票号、船价(Fare)、客舱号码(Cabin)、登船港口(Embarked)
测试集: 缺少是否被救(Survived)一列。
2、载入数据集并查看数据规模

from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier 
from sklearn import cross_validation
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
#读取数据
train=pd.read_csv('train.csv')
test=pd.read_csv('test.csv')
train.info()
test.info()

从图中我们可以看到:年龄(Age)、cabin、embarked都有缺失值
从图中我们可以看到:年龄(Age)、cabin、embarked(只训练集)、Fare(只测试集)都有缺失值。

缺失值的处理

缺失值处理一般有以下几种方法:

  1. 对于缺失数据很多,并且不重要的性质,可以直接把某一列去掉;对于缺失数据相对于数据总体量比较小的情况,可以考虑直接把有缺失值的样本去掉。
  2. 缺失样本不多的,可以用众数补充,比如本项目中的Embark属性只有两个缺失值,我们就直接用其众数补充缺失值。
    missing_embarked=train.Embarked.dropna().mode().values train.Embarked=train.Embarked.fillna(str(missing_embarked))
  3. 对于缺失值比较多并且是定性的属性,可以附一个代表缺失值的数,因为缺失本身就包含着一些信息。比如本项目中的Cabin属性,缺失值较多,我们用m表示缺失数据,
    train.Cabin=train.Cabin.fillna('m')
  4. 回归预测:使用一些回归模型来预测缺失属性的值。因为Age在数据集里是一个相当重要的特征,缺失值也比较多,所以可以用已知数据去预测缺失的数据。在这里我们选择的模型是随机森林。
age_df=train[['Age','Survived','Fare','Parch','SibSp','Pclass']]
age_df_notnull=age_df.loc[(train.Age.notnull())]
age_df_isnull=age_df.loc[(train.Age.isnull())]
X=age_df_notnull.loc[:,['Survived','Fare','Parch','SibSp','Pclass']]
Y=age_df_notnull.loc[:,'Survived']
#使用随机森林预测
model1=RandomForestClassifier(n_estimators=1000, n_jobs=-1)
model1.fit(X,Y)
predict_age=model1.predict(age_df_isnull.loc[:,['Survived','Fare','Parch','SibSp','Pclass']])
train.loc[train['Age'].isnull(),'Age']=predict_age

缺失值填充后的数据集如下:train.info()
在这里插入图片描述

描述性统计分析

在这一部分,采用直观的图方式,大致了解一下相关属性与死亡之间的关系。

(1) 性别与是否生存的关系

我们按照性别将训练集分类,得到的结果如下:

group1=train['Survived'].groupby(train['Sex'])
group1.count()
group1.mean().plot.bar()
group1.mean().plot(kind='bar')
plt.title('Survived probabality of different sex')

在这里插入图片描述在这里插入图片描述
female一共有314人,male一共有577人。在女性中的存活率是0.74,在男性中的是0.18889,所以在这一数据集中体现了“女士优先”的原则:女性的存活率远远高于男性。

(2)船舱等级与生存与否的关系(Pclass)

group2=train['Survived'].groupby(train['Pclass'])
group2.count()
group2.mean()
group2.mean().plot(kind='bar')
plt.title('Survived probabality of different Pclass')

在这里插入图片描述在这里插入图片描述运行结果显示:在一等船舱共有216人,存活率为0.63;二等船舱共有184人,存活率为0.47;二等船舱共有491人,存活率为0.24;通过条形图也能够很清楚的看出:船舱等级越高(1>2>3),存活机率越高。
将性别和船舱等级综合来看:

group3=train.groupby(['Sex','Pclass'])['Survived']
group3.count()
group3.mean()
group3.mean().plot(kind='bar')
font1 = {'family' : 'Times New Roman',
'weight' : 'normal',
'size'   : 25}
plt.title('survived probability of different sex and pclass',font1)

在这里插入图片描述在这里插入图片描述表中和图中都清楚的表明了:在泰坦尼克号的救援过程中,首先是女士优先的特点,其次在不同的仓位之间进行选择,不管在男士还是女士群体中,船舱等级越高都越容易获救。

(3)年龄与生存与否的关系(Age)

在这一阶段我们分别来看不同的船舱和不同性别间年龄与存活率之间的关系,采用小提琴图来展示这种关系,如下图:

fig,ax=plt.subplots(1,2,figsize=(15,5))
sns.violinplot('Pclass','Age',hue='Survived',data=train,split=True,ax=ax[0])
ax[0].set_title('Pclass and Age vs Survived')
ax[0].set_yticks(range(0,110,10))
sns.violinplot('Sex','Age',hue='Survived',data=train,split=True,ax=ax[1])
ax[1].set_title('Sex and Age vs Survived')
ax[1].set_yticks(range(0,110,10))
plt.savefig('2.png')

在这里插入图片描述
年龄的总体分布

plt.figure(figsize=(12,5))
plt.subplot(121)
train['Age'].hist(bins=80)
plt.xlabel('Age')
plt.ylabel('Number')
plt.subplot(122)
train.boxplot(column='Age')
plt.show()
plt.savefig('3.png')

在这里插入图片描述
从柱状图中可以看出:年龄基本分布再20-30岁之间,这和小提琴图中的峰值是能够对应的。但是这并不能说明这一年龄段的获救比率就高,因为这一年龄段的基数本来就很大,我们应该将年龄分组,比较每一组的获救比率。
看一下年龄的具体信息:

train['Age'].describe()

在这里插入图片描述
年龄的均值是29.36,最小值是0.42,最大值是80。根据年龄,将乘客划分为儿童、青少年、成年和老年

bins=[0,12,18,65,80]
train['age_group']=pd.cut(train.Age,bins)
group4=train.groupby('age_group')['Survived']
group4.mean()
group4.mean().plot(kind='bar')

在这里插入图片描述
我们可以看到:在救援的过程中,儿童和青少年会优先获救,但是老人获救的比例却很低,因为本来在这一年龄段的人中就只有8个人。

(4)港口和存活率的关系

group5=train.groupby('Embarked')['Survived']
group5.mean()
group5.mean().plot(kind='bar')
plt.savefig('6.png')

在这里插入图片描述
条形图告诉我们:不同的港口上船,存活率也不一样。港口C的存活率最高,其次是Q,最低的是S。泰坦尼克号从英国南安普顿港口出发,途径法国瑟堡和爱尔兰昆士敦,那么很多人就有可能在中途下船,这些人将不会早遇到灾难。

(5)有无兄弟姐妹、父母子女与存活率的关系(Sibsp)

根据是否有sibsp、parch,将训练集分成两组,做出每一类数据下存活率的饼状图。

#Sibsp
have_sibsp=train[train.SibSp!=0]
no_sibsp=train[train.SibSp==0]
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
have_sibsp['Survived'].value_counts().plot.pie(labels=['no survived','survived'],autopct = '%1.1f%%')
plt.xlabel('have sibsp')
plt.subplot(1,2,2)
no_sibsp['Survived'].value_counts().plot.pie(labels=['no survived','survived'],autopct = '%1.1f%%')
plt.xlabel('no sibsp')
plt.savefig('7.png')
#parch
have_parch=train[train.Parch!=0]
no_parch=train[train.Parch==0]
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
have_sibsp['Survived'].value_counts().plot.pie(labels=['no survived','survived'],autopct = '%1.1f%%')
plt.xlabel('have parch')
plt.subplot(1,2,2)
no_sibsp['Survived'].value_counts().plot.pie(labels=['no survived','survived'],autopct = '%1.1f%%')
plt.xlabel('no parch')
plt.savefig('8.png')

在这里插入图片描述
在这里插入图片描述
综合以上两幅图,我们可以看到:有父母子女的和有兄弟姐妹的人的存活机率要高于那些一个人的。也就是说:如果是独自一个人,那么其生还的比率较低。但我们考虑:是亲友人数越多,越容易获救吗?

亲友的人数与存活率之间的关系
根据亲友的人数进行分组,并画出每组中获救的比例,结果如下:

group6=train.groupby('SibSp')['Survived']
group7=train.groupby('Parch')['Survived']
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
group6.mean().plot.bar()
plt.title('SibSp and Survived')
plt.subplot(1,2,2)
group7.mean().plot.bar()
plt.title('Parch and Survived')
plt.savefig('9.png')

在这里插入图片描述
从图中可以看出,有亲友(兄弟姐妹+父母孩子)虽然会提高获救机会,但是并不是亲友越多存活机会越大,亲友过多的时候反而会降低获救机会。

特征工程

以上的工作我们都在进行描述性统计分析,大多靠数据的可视化实现的,优点是能够清楚明了的对数据整体做大体了解,但是信服度不够,需要通过更加量化的方法来说明我们的结论。

变量的转换

在统计分析中,变量数据可以分为定性数据和定量数据,在建模的过程中需要将所有的变量都转换为适合用于模型使用的数据,Scikit-learn要求数据都是数字型的,所以我们应该将原始数据转换为数字型。
1、定性数据转换
(1)哑变量方法
(2)因子化。在Pandas中有个方法叫做factorize(),他可以创建一些数字用来表示类别变量,对于每一个类映射一个数字,这种映射最后只生成一个特征,不像哑变量那样生成多个特征。
2、定量数据转换
(1)标准化
(2)Binning
Binning通过观察周围的值将连续数据离散化。存储的值被分布到一些“桶”或“箱”中,就像直方图的bin将数据划分成几块。在将数据Bining化后,要么将数据因子化,要么变成哑变量。

处理特征

对数据进行特征工程,也就是从各项参数中提取出对输出结果有或大或小的影响的特征,将这些特征作为训练模型的依据。 一般来说,我们会先从含有缺失值的特征开始。
(1)Embarked
缺失值不多,用众数填充。并且变为哑变量。

test['Survived']=0
combined=train.append(test)
passerageid=test['PassengerId']
emb_dummy=pd.get_dummies(combined['Embarked'],prefix='embarked')
combined= pd.concat([combined, emb_dummy], axis=1)

(2)Sex

combined.loc[combined['Sex']=='male','Sex']=0
combined.loc[combined['Sex']=='female','Sex']=1

(3)票价
我们在前面已经知道:在测试集中fare少一个值,所以需要对该值进行填充,我们按照一二三等舱各自的均价来填充

combined['Fare']=combined[['Fare']].fillna(combined.groupby('Pclass').transform(np.mean))
combined['Group_ticket']=combined['Fare'].groupby(combined['Ticket']).transform('count')
combined['Fare']=combined['Fare']/combined['Group_ticket']

通过ticket的数据,我们看到很多票号有重复,同时结合亲属人数,我们知道很多购买的票是团体票或者家庭票,所以我们需要将团体票的票价分配到每个人的头上。
给票价分级:

combined['Fare_bins']=pd.qcut(combined['Fare'],5)
combined['Fare_bin_id'] = pd.factorize(combined['Fare_bins'])[0]
fare_bin_dummies = pd.get_dummies(combined['Fare_bin_id']).rename(columns=lambda x: 'Fare_' + str(x))
combined = pd.concat([combined, fare_bin_dummies], axis=1)
combined.drop(['Fare_bins'], axis=1, inplace=True)

(4)Pclass 因子化

combined['Pclass']=pd.factorize(combined['Pclass'])[0]

(5)Parch 和SibSp
前面的描述性统计告诉我们:没有亲友和亲友的数量过多都会使Survived的比例下降,所以我们将这两项组合,只考虑家庭的规模。

def family_size_category(family_size):
    if family_size <= 0:
        return ('Single')
    elif family_size <= 3:
        return ('Small_Family')
    else:
        return ('Large_Family')
      
combined['Family_Size'] = combined['Parch'] + combined['SibSp'] 
combined['Family_Size_Category'] = combined['Family_Size'].map(family_size_category)
family_size_dummy=pd.get_dummies(combined['Family_Size_Category'])
combined = pd.concat([combined, family_size_dummy], axis=1)
combined['Family_Size_Category'] = pd.factorize(combined['Family_Size_Category'])[0]

(6)Name
本来name是一个文本变量,不易分析。但是我们看到:名字当中包含了对人的称呼,体现了乘客的地位和年龄。
(6)Age
综合来看训练集和测试集,age的缺失值都比较多,而age又是一个重要的属性不能直接删除,所以我们用机器学习的方法来预测缺失的Age。

机器学习方法预测缺失的Age

在这一部分,我们选取的特征分别是:**‘Embarked’、‘Sex’、 ‘Title’、 ‘Name_length’、 ‘Family_Size’、‘Family_Size_Category’、‘Fare’、 ‘Fare_bin_id’, ‘Pclass’**各变量处理过程如前所示,数据预处理部分代码如下:

age_group=combined[['Age', 'Embarked', 'Sex', 'Title', 'Name_length', 'Family_Size', 'Family_Size_Category','Fare', 'Fare_bin_id', 'Pclass']]
age_notnull = age_group[age_group['Age'].notnull()]
age_null= age_group[age_group['Age'].isnull()]
agenotnull_X_train = age_notnull.drop(['Age'], axis=1)
agenotnull_Y_train = age_notnull['Age'] 
agenull_X_test = age_null.drop(['Age'], axis=1)
  • 随机森林模型
    随机森林是集成学习的一种工具,是由多棵决策树(CART树)组合而成。对于分类问题:每棵树投票找最高票;回归问题:每棵树的值求和取平均。用python进行随机森林模型调参,主要有以下几个重要参数。详见【集成学习】scikit-learn随机森林调参小结

  • n_estimators:树的棵数。默认值是100

  • obb_score:是否采用袋外样本来评估模型的好坏,默认是False。袋外分数反映了一个模型拟合后的泛化能力。

  • max_feature:决策树划分时的最大特征数。

  • max_depth:默认不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。数据少的时候可以使用默认值

  • min_samples_split:内部节点再划分所需要的最小样本数。

  • min_samples_leaf:叶子结点最少样本数。如果某叶子节点数目小于这个数,则会和兄弟节点一起被剪枝。
    具体的代码如下:

#rf model
param1 = {'n_estimators': list(range(50,200,10)), 'max_depth': list(range(3,10,1))} 
model1 = GridSearchCV(estimator = RandomForestRegressor(random_state=10),param_grid = param1, scoring='mean_squared_error',cv=5)
model1.fit(agenotnull_X_train, agenotnull_Y_train) 
model1.grid_scores_
print('Age feature Best RF Params:' + str(model1.best_params_))
print('Age feature Best RF Score:' + str(model1.best_score_)) 
model_rf=RandomForestRegressor(n_estimators=60,max_depth=5,random_state=10)
model_rf.fit(agenotnull_X_train, agenotnull_Y_train)
agenull_X_test['Age_rf']=model_rf.predict(agenull_X_test)

首先通过交叉验证法找到最好的n_estimators和max_depth,然后拟合新的模型去预测age。
(7)Cabin
因为Cabin的缺失值太多,而且又是字符串型的变量,对他进行填充不太现实,所以我们将他分为有和无两项。

combined.loc[combined['Cabin'].isnull(),'Cabin']='N'
combined['Cabin']=pd.factorize(combined['Cabin'])

特征间可视化

特征间相关系数
接下来我们选取一些重要的特征,查看彼此间的相关系数:

correlation_list=pd.DataFrame(combined[['Embarked', 'Sex', 'Title', 'Name_length', 'Family_Size', 'Family_Size_Category','Fare', 'Fare_bin_id', 'Pclass', 'Age', 'Cabin']])
colormap = plt.cm.viridis
plt.figure(figsize=(14,12))
plt.title('Pearson Correlation of Features', y=1.05, size=15) 
sns.heatmap(correlation_list.astype(float).corr(),linewidths=0.1,vmax=1.0, square=True, cmap=colormap, linecolor='white', annot=True)
plt.savefig('correlation.png')

在这里插入图片描述
** 特征之间的数据分布图**

g = sns.pairplot(combined[[u'Survived', u'Pclass', u'Sex', u'Age', u'Fare', u'Embarked', u'Family_Size', u'Title']], hue='Survived', palette = 'seismic',size=1.2,diag_kind = 'kde',diag_kws=dict(shade=True),plot_kws=dict(s=10) )
g.set(xticklabels=[])
plt.savefig('distributed.png')

在这里插入图片描述

模型输入前的数据处理工作

1、数据的标准化
对age、fare、Name_length进行标准化

scaled=preprocessing.StandardScaler().fit(combined[['Age','Fare','Name_length']])
combined[['Age','Fare','Name_length']]=scaled.transform(combined[['Age','Fare','Name_length']])
#数据备份
combined_copy=combined

2、选取有用的(重要的)特征

combined.drop(['PassengerId', 'Embarked', 'Name', 'Title', 'Fare_bin_id', 'Parch', 'SibSp', 'Family_Size_Category', 'Ticket'],axis=1,inplace=True)
train_data=combined[:891]
test_data=combined[891:]
train_X=train_data.drop(['Survived'],axis=1)
train_Y=train_data['Survived']
test_X=test_data.drop(['Survived'],axis=1)

单个模型的预测

在这一阶段,我们将采用不同的机器学习算法进行预测,思路都是先通过交叉验证选择最优的参数,然后在最优参数下拟合数据并进行预测。调参方法详情请参见scikit-learn Adaboost类库使用小结Ababoost类库使用小结
1、随机森林(randomforest)

rf=RandomForestClassifier(random_state=10,max_features='sqrt')
param2 = {'n_estimators': list(range(50,200,10)), 'max_depth': list(range(3,10,1)),'min_samples_split':list(range(5,10,1))} 
model2 = GridSearchCV(estimator = rf,param_grid = param2, scoring='roc_auc',cv=5)
model2.fit(train_X, train_Y) 
model2.grid_scores_
model2.best_estimator_
print('The Best RF Params:' + str(model2.best_params_))
print('The Best RF Score:' + str(model2.best_score_)) 

在这里插入图片描述
通过结果我们可以看到:最好的参数分别是:‘n_estimators’:60,‘min_samples_split’
:9,‘max_depth’:7。将其带入模型,得到预测结果。

gbm1=RandomForestClassifier(random_state=10,max_features='sqrt',max_depth=7,min_samples_split=9,n_estimators=60)
gbm1.fit(train_X,train_Y)
test_Y1=gbm1.predict(test_X)

2、提升算法(adaboost)

ada=AdaBoostClassifier(random_state=10)
param_ada={'n_estimators':list(range(100,200,10)),'learning_rate':(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8)}
model3=GridSearchCV(estimator =ada,param_grid = param_ada,cv=5)
model3.fit(train_X, train_Y)
model3.best_score_
model3.best_params_

gbm2=AdaBoostClassifier(random_state=10,n_estimators=140,learning_rate=0.1)
gbm2.fit(train_X,train_Y)
test_Y2=gbm2.predict(test_X)

步骤类似于随机森林,只不过需要调整的参数有所改变。得到结果为test_Y2
3、决策树(decision tree)

dc=DecisionTreeClassifier(random_state=10)
param_dc={'max_depth': list(range(10,50,5)),'min_samples_split':list(range(5,20,2))}
model4=GridSearchCV(estimator=dc,param_grid=param_dc,cv=5)
model4.fit(train_X,train_Y)
model4.best_params_
model4.best_score_

gbm3=DecisionTreeClassifier(random_state=10,max_depth=10,min_samples_split=19)
gbm3.fit(train_X,train_Y)
test_Y3=gbm3.predict(test_X)

多个模型的融合

在这一部分,我们将几种机器学习的算法结合起来,第一层使用单一的机器学习算法,将这几种算法的预测结果当做第二层的输入,进而得到最终的模型。
然而,我们不能简单地在全部训练数据上训练基本模型,产生预测,输出用于第二层的训练。如果我们在Train Data上训练,然后在Train Data上预测,就会造成标签。为了避免标签,我们需要对每个基学习器使用K-fold,将K个模型对Valid Set的预测结果拼起来,作为下一层学习器的输入。
所以这里我们建立输出fold预测方法:

from sklearn.model_selection import KFold
ntrain=train_X.shape[0]
ntest=test_X.shape[0]
SEED = 0 # for reproducibility
NFOLDS = 7 # set folds for out-of-fold prediction
kf = KFold(n_splits = NFOLDS, random_state=SEED, shuffle=False)

def get_out_fold(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.split(x_train)):
        x_tr = x_train[train_index]
        y_tr = y_train[train_index]
        x_te = x_train[test_index]
        clf.fit(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)

构建不同的基学习器,当然这里的基学习器可以用上述的调参方法调参,但是这里为了方便略去了这一步。后面再慢慢调试吧,有点累了哈哈哈哈

from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
rf_=RandomForestClassifier(n_estimators=500, warm_start=True, max_features='sqrt',max_depth=6,min_samples_split=3, min_samples_leaf=2, n_jobs=-1, verbose=0)
ada_ = AdaBoostClassifier(n_estimators=500, learning_rate=0.1)
gb_= GradientBoostingClassifier(n_estimators=500, learning_rate=0.008, min_samples_split=3, min_samples_leaf=2, max_depth=5, verbose=0)
dt_ = DecisionTreeClassifier(max_depth=8)
knn_ = KNeighborsClassifier(n_neighbors = 2)
svm_= SVC(kernel='linear', C=0.025)

转化为numpy再进行模型预测(第一步)

x_train=train_X.values
x_test=test_X.values
y_train=train_Y.values
rf_oof_train, rf_oof_test = get_out_fold(rf_, x_train, y_train, x_test) # Random Forest
ada_oof_train, ada_oof_test = get_out_fold(ada_, x_train, y_train, x_test) # AdaBoost 
gb_oof_train, gb_oof_test = get_out_fold(gb_, x_train, y_train, x_test) # Gradient Boost
dt_oof_train, dt_oof_test = get_out_fold(dt_, x_train, y_train, x_test) # Decision Tree
knn_oof_train, knn_oof_test = get_out_fold(knn_, x_train, y_train, x_test) # KNeighbors
svm_oof_train, svm_oof_test = get_out_fold(svm_, x_train, y_train, x_test) # Support Vector

第二部分,利用xgboost,对第一层的结果作为特征进行最终的预测,并生成结果。(和单个模型的预测结果放到同一张表里)

x_train = np.concatenate((rf_oof_train, ada_oof_train, gb_oof_train, dt_oof_train, knn_oof_train, svm_oof_train), axis=1)
x_test = np.concatenate((rf_oof_test, ada_oof_test, gb_oof_test, dt_oof_test, knn_oof_test, svm_oof_test), axis=1)
from xgboost import XGBClassifier
gbm = XGBClassifier( n_estimators= 2000, max_depth= 4, min_child_weight= 2, 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)
StackingSubmission = pd.DataFrame({'PassengerId': passerageid, 'Survived_rf':test_Y1,'Survived_ada':test_Y2,'Survived_dctr':test_Y3,'Survived_xgboost': predictions})
StackingSubmission.to_csv('StackingSubmission.csv',index=False,sep=',')

猜你喜欢

转载自blog.csdn.net/hu_wenqiong/article/details/85883899