项目实例---随机森林在Kaggle实例:Titanic中的应用(二)
发布日期:2021-07-24 12:00:34 浏览次数:1 分类:技术文章

本文共 13281 字,大约阅读时间需要 44 分钟。

4、 特征工程

特征工程主要是对一些不适合直接参与建模的特征进行各种处理,通过已有数据构建一些新特征,对特征进行哑变量转换等等。

4.1 对Name进行处理

由于名字一般都比较杂乱,似乎对模型预测没有任何作用。但是通过对Name进行观察发现,在姓名里包含了一些身份信息,性别信息,我们可以粗略看一下。

#对Name进行处理#查看Nameprint(dataset["Name"].head())

结果如下:

0                              Braund, Mr. Owen Harris1    Cumings, Mrs. John Bradley (Florence Briggs Th...2                               Heikkinen, Miss. Laina3         Futrelle, Mrs. Jacques Heath (Lily May Peel)4                             Allen, Mr. William HenryName: Name, dtype: object

从上面可以看到名字中间部分有Mr、Mrs这些能代表性别也能一定程度上反映身份的信息,更具体的可以查看整个数据集,这里直接提取出中间部分,并进行统计。

#下面直接提取名字中间部分dataset_title=[i.split(",")[1].split(".")[0].strip() for i in dataset["Name"]]dataset["Title"]=pd.Series(dataset_title)#查看详情print(dataset["Title"].describe())print(dataset["Title"].unique())

结果如下

count     1299unique      18top         Mrfreq       753Name: Title, dtype: object['Mr' 'Mrs' 'Miss' 'Master' 'Don' 'Rev' 'Dr' 'Mme' 'Ms' 'Major' 'Lady' 'Sir' 'Mlle' 'Col' 'Capt' 'the Countess' 'Jonkheer' 'Dona']

以下是从百度查询到的相关解释:

Mr.= mister,先生Mrs.= mistress,太太/夫人Miss,复数为misses,对未婚妇女用,Ms.或Mz,美国近来用来称呼婚姻状态不明的妇女Madame简写是Mme.,复数是mesdames(简写是Mme)Mlle,小姐Lady, 女士,指成年女子,有些人尤其是长者认为这样说比较礼貌Dona,是西班牙语对女子的称谓,相当于英语的 LadyMaster,佣人对未成年男少主人的称呼,相当于汉语的"少爷"。Mr. Mister的略字,相当于汉语中的"先生",是对男性一般的称呼,区别于有头衔的人们,如Doctor, Professor,Colonel等Don,n. 
<西>
(置于男士名字前的尊称)先生,堂jonkheer是贵族St.= saint,圣人Rev.= reverend,用于基督教的牧师,如the Rev. Mr.SmithDr.= doctor,医生/博士Colonel,上校major,意思有少校人意思The Countless,女伯爵

所以我们可以将上面定义的Title进行分类:

第一类:’Mr’ 、’Don’
第二类:’Mrs’ 、’Miss’ 、’Mme’ 、’Ms’ 、’Lady’、 ‘Dona’ 、’Mlle’
第三类: ‘Sir’ 、’Major’、 ‘Col’ 、’Capt’
第四类:’Master’ 、’Jonkheer’、 ‘the Countess’
第五类:’Rev’ 、’Dr’

#将title合并为几个组dataset["Title"]=dataset["Title"].replace(['Mr','Don'],'Mr')dataset["Title"]=dataset["Title"].replace(['Mrs','Miss','Mme','Ms','Lady','Dona','Mlle'],'Ms')dataset["Title"]=dataset["Title"].replace(['Sir','Major','Col','Capt'],'Major')dataset["Title"]=dataset["Title"].replace(['Master','Jonkheer','the Countess'],'Jonkheer')dataset["Title"]=dataset["Title"].replace(['Rev','Dr'],'Rev')

查看各组的幸存率

#我们查看各组的幸存率情况:g=sns.barplot(data=dataset[:train_len],x="Title",y="Survived")g.set_ylabel("Survival Probability")plt.show()

结果如下:

这里写图片描述
从图上可以看到男女的差别与之前的分析是一致的,同时贵族和军人相对其他男性也有较高的幸存率,但是神职人员和医生的生存率并没有高出很多,医生的幸存率有点不合逻辑因而重新分组。
结果如下:
这里写图片描述
从图上看到神职人员没有幸存的,而医生的幸存率较普通男性仍然高出很多。

#下面将姓名数值化dataset["Title"]=dataset["Title"].map({
'Mr':0,'Ms':1,'Major':2,'Jonkheer':3,'Rev':4,'Dr':5})dataset["Title"]=dataset["Title"].astype(int)#将Title哑变量化dataset=pd.get_dummies(dataset,columns=["Title"],prefix="TL")# 去掉name这一特征dataset.drop(labels = ["Name"], axis = 1, inplace = True)print(dataset.info())

4.2 对Cabin进行处理

#对Cabin进行处理#先查看Cabin的情况print(dataset["Cabin"].describe())

结果如下:

count     292unique    186top        G6freq        5Name: Cabin, dtype: object

从上可以看到Cabin中有186个不同的取值,直接统计不太可能也没必要。

下面再查看缺失值的情况

print(dataset["Cabin"].isnull().sum())

结果如右:1007

缺失值和存在真实值的样本比例是1007:292,通常这种情况可以直接将该特征去掉(而且船舱与票价是有相关性的);这里我们并没有去掉,主要考虑到船舱本身可能能反映乘客的身份和逃生的硬件实施和便利性,而普通人群中没有特殊身份的人更可能缺少船舱信息,用字母X来表示缺失,不失为一种恰当的处理方法。首字母相同的船舱情况相近,船舱信息直接用首字母来代替也是合理的。

#将船舱信息进行替换dataset["Cabin"]=pd.Series([i[0] if not pd.isnull(i) else 'X' for i in dataset['Cabin']])#再来查看一下船舱信息print(dataset["Cabin"].describe())print(dataset["Cabin"].isnull().sum())

可以看到如下结果:

count     1299unique       9top          Xfreq      1007Name: Cabin, dtype: object0

现在只有Cabin只有9个值,而缺失值为0。

#查看不同船舱的幸存率g=sns.barplot(data=dataset[:train_len],x="Cabin",y="Survived")g.set_ylabel("Survival Probability")plt.show()

结果如下:

这里写图片描述
从图上可以看到不同船舱的幸存率是有差异的,除了T(全部遇难),其他有船舱信息的幸存率均要高于没有船舱信息的乘客,与预期一致。

#利用哑变量将Cabin信息数值化dataset=pd.get_dummies(dataset,columns=["Cabin"],prefix="Cabin")#再来查看一下船舱信息print(dataset.info())

结果如下:

RangeIndex: 1299 entries, 0 to 1298Data columns (total 20 columns):Age            1299 non-null float64Embarked       1299 non-null objectFare           1299 non-null float64Parch          1299 non-null int64PassengerId    1299 non-null int64Pclass         1299 non-null int64Sex            1299 non-null int64SibSp          1299 non-null int64Survived       881 non-null float64Ticket         1299 non-null objectTitle          1299 non-null int32Cabin_A        1299 non-null uint8Cabin_B        1299 non-null uint8Cabin_C        1299 non-null uint8Cabin_D        1299 non-null uint8Cabin_E        1299 non-null uint8Cabin_F        1299 non-null uint8Cabin_G        1299 non-null uint8Cabin_T        1299 non-null uint8Cabin_X        1299 non-null uint8dtypes: float64(3), int32(1), int64(5), object(2), uint8(9)memory usage: 118.1+ KBNone

4.3 对Ticket进行处理

通过对原始数据进行查看可以知道,Ticket中包含的信息也是比较杂乱的,需要做一定处理。船票主要是分为两种,有字母前缀和没有字母前缀的,有字母前缀的应该是一些较特殊的票,其中就有类似于现在的VIP这种票,也可能有一些比较差的票。正如之前的分析中讲到,将船票这一特征纳入到模型中主要是考虑船票本身能反映票价和位置等信息从而与生存率相关联;而相同的字母前缀具有相同的性质,因而这里将字母前缀来代替船票信息。如果是纯数字,则归为同一类“X”。

#对Ticket进行处理Ticket=[]for i in list(dataset["Ticket"]):    if not i.isdigit():        Ticket.append(i.replace(".","").replace("/","").strip().split(' ')[0])    else:        Ticket.append("X")dataset["Ticket"]=Ticket#查看替换后的情况print(dataset["Ticket"].describe())

结果如下:

count     1299unique      37top          Xfreq       954Name: Ticket, dtype: object
#查看不同船票的生存率g=sns.barplot(data=dataset,x="Ticket",y="Survived")g.set_ylabel("Survival Probability")plt.show()

结果如下:

这里写图片描述
从图上可以看到不同船票之间的差别。

#利用哑变量将Ticket数值化dataset=pd.get_dummies(dataset,columns=["Ticket"],prefix="T")

4.4 对Embarked进行处理

#将Embarked哑变量化dataset = pd.get_dummies(dataset, columns = ["Embarked"], prefix="Em")

4.4 对Pclass进行处理

#将Pclass哑变量化dataset["Pclass"] = dataset["Pclass"].astype("category")dataset = pd.get_dummies(dataset, columns = ["Pclass"],prefix="Pc")

4.5 去除PassengerId

dataset.drop(labels = ["PassengerId"], axis = 1, inplace = True)

4.6 查看处理好的数据

#查看最终数据#print(dataset.head())print(dataset.info())

结果如下:

RangeIndex: 1299 entries, 0 to 1298Data columns (total 64 columns):Age          1299 non-null float64Fare         1299 non-null float64Parch        1299 non-null int64Sex          1299 non-null int64SibSp        1299 non-null int64Survived     881 non-null float64TL_0         1299 non-null uint8TL_1         1299 non-null uint8TL_2         1299 non-null uint8TL_3         1299 non-null uint8TL_4         1299 non-null uint8TL_5         1299 non-null uint8Cabin_A      1299 non-null uint8Cabin_B      1299 non-null uint8Cabin_C      1299 non-null uint8Cabin_D      1299 non-null uint8Cabin_E      1299 non-null uint8Cabin_F      1299 non-null uint8Cabin_G      1299 non-null uint8Cabin_T      1299 non-null uint8Cabin_X      1299 non-null uint8T_A          1299 non-null uint8T_A4         1299 non-null uint8T_A5         1299 non-null uint8T_AQ3        1299 non-null uint8T_AQ4        1299 non-null uint8T_AS         1299 non-null uint8T_C          1299 non-null uint8T_CA         1299 non-null uint8T_CASOTON    1299 non-null uint8T_FC         1299 non-null uint8T_FCC        1299 non-null uint8T_Fa         1299 non-null uint8T_LINE       1299 non-null uint8T_LP         1299 non-null uint8T_PC         1299 non-null uint8T_PP         1299 non-null uint8T_PPP        1299 non-null uint8T_SC         1299 non-null uint8T_SCA3       1299 non-null uint8T_SCA4       1299 non-null uint8T_SCAH       1299 non-null uint8T_SCOW       1299 non-null uint8T_SCPARIS    1299 non-null uint8T_SCParis    1299 non-null uint8T_SOC        1299 non-null uint8T_SOP        1299 non-null uint8T_SOPP       1299 non-null uint8T_SOTONO2    1299 non-null uint8T_SOTONOQ    1299 non-null uint8T_SP         1299 non-null uint8T_STONO      1299 non-null uint8T_STONO2     1299 non-null uint8T_STONOQ     1299 non-null uint8T_SWPP       1299 non-null uint8T_WC         1299 non-null uint8T_WEP        1299 non-null uint8T_X          1299 non-null uint8Em_C         1299 non-null uint8Em_Q         1299 non-null uint8Em_S         1299 non-null uint8Pc_1         1299 non-null uint8Pc_2         1299 non-null uint8Pc_3         1299 non-null uint8dtypes: float64(3), int64(3), uint8(58)memory usage: 134.5 KBNone

5、 数据建模

#重新获取训练数据和测试数据train=dataset[:train_len]train["Survived"]=train["Survived"].astype(int)Y_train=train["Survived"]X_train=train.drop(labels=["Survived"],axis=1)test=dataset[train_len:]test.drop(labels=["Survived"],axis=1,inplace=True)

5.1 利用分类算法进行分类

有时候可能会使用多种算法进行测试,从中选出比较适应数据场景的算法;对新样本的预测也可能是综合多种算法的结果;这里我直接选用随机森林进行数据分类,之后有时间再做更复杂的训练。

使用搜索最佳参数的方式进行训练。

# 搜索随机森林的最佳参数 RFC = RandomForestClassifier()## 设置参数网络rf_param_grid = {
"max_depth": [None], "max_features": [1, 3, 10], "min_samples_split": [2, 3, 10], "min_samples_leaf": [1, 3, 10], "bootstrap": [False], "n_estimators" :[100,300], "criterion": ["gini"]}gsRFC = GridSearchCV(RFC,param_grid = rf_param_grid, cv=kfold, scoring="accuracy", n_jobs= 1, verbose = 1)gsRFC.fit(X_train,Y_train)RFC_best = gsRFC.best_estimator_print(RFC_best)# 打印最佳得分print(gsRFC.best_score_)

结果如下:

RandomForestClassifier(bootstrap=False, class_weight=None, criterion='gini',            max_depth=None, max_features=3, max_leaf_nodes=None,            min_impurity_decrease=0.0, min_impurity_split=None,            min_samples_leaf=3, min_samples_split=3,            min_weight_fraction_leaf=0.0, n_estimators=100, n_jobs=1,            oob_score=False, random_state=None, verbose=0,            warm_start=False)0.83427922815

从以上结果可以看到,如果使用随机森林作模型,其最佳配置为max_features=3,min_samples_leaf=3,min_samples_split=3,n_estimators=100,最佳得分为0.83427922815

可以使用不同算法进行尝试,优中选优。

5.2 评估模型效果

这里只通过学习曲线对比欠拟合和过拟合的情况

欠拟合:简单讲就是模型参数太少,不管数据多少,都无法正确反映出数据真实的结构和规律;欠拟合情况下训练集的效果较差,测试集的效果也差。
在欠拟合情况下,增加样本数量对模型没有什么帮助,因为参数本身不够,模型先天不足;
过拟合:模型参数太多,数据太少,这样模型的参数取值会过分的迎合训练集数据特点,从对训练集的数据拟合的非常好,但测试集数据结构不一定与训练集完全一样,这就导致了此种情况下得到的模型泛化能力很弱,在训练集之外的数据中效果很差;
在过拟合情况下,增加训练样本模型效果会得到提升,因为样本越多,数据结构就越复杂,从而需要更多参数建立模型。

# 效果评估#####--------------------------------------------------------------------------------------------------### 效果评估之学习曲线def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None,                        n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5)):    """Generate a simple plot of the test and training learning curve"""    plt.figure()    plt.title(title)    if ylim is not None:        plt.ylim(*ylim)    plt.xlabel("Training examples")    plt.ylabel("Score")    train_sizes, train_scores, test_scores = learning_curve(        estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes)    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)    plt.grid()    plt.fill_between(train_sizes, train_scores_mean - train_scores_std,                     train_scores_mean + train_scores_std, alpha=0.1,                     color="r")    plt.fill_between(train_sizes, test_scores_mean - test_scores_std,                     test_scores_mean + test_scores_std, alpha=0.1, color="g")    plt.plot(train_sizes, train_scores_mean, 'o-', color="r",             label="Training score")    plt.plot(train_sizes, test_scores_mean, 'o-', color="g",             label="Cross-validation score")    plt.legend(loc="best")    return pltg = plot_learning_curve(gsRFC.best_estimator_,"RF mearning curves",X_train,Y_train,cv=kfold)plt.show()

结果如下:

这里写图片描述
如何查看学习曲线?
首先看训练集的得分和交叉验证的得分会不会随着样本增加而产生大的变化,如果样本增加得分明显提高说明过拟合;
然后看训练集得分和交叉验证得分差别大不大,如果两差别很大,说明模型在不同数据中表现不一样,即模型的泛化能力差;
从上图中可以看到随机森林算法中随着样本的增多,分类效果变好,说明有一定的过拟合,但变化程度不大,说明过拟合能接受;而训练样本中的得分一直都比交叉验证时的高,这个与实际情况相符;交叉验证时得分与训练样本中的得分差别不大,说明模型的泛化能力不差。
效果的查看更需要通过与其他算法对比,才知道哪种算法比较适应该数据场景。这里只有一种算法,只是演示如下查看学习曲线。

5.3 查看特征变量在模型中的权重

不算算法权重的意义并不完全相同,在回归算法,权重表示回归系数,在PCA算法中,权重仅反映该特征包含信息的多少。

# 特征变量权重分析#####--------------------------------------------------------------------------------------------------nrows = ncols = 1fig, axes = plt.subplots(nrows = nrows, ncols = ncols, sharex="all", figsize=(15,15))#names_classifiers = [("AdaBoosting", ada_best),("ExtraTrees",ExtC_best),("RandomForest",RFC_best),("GradientBoosting",GBC_best)]names_classifiers = [("RandomForest",RFC_best)]nclassifier = 0for row in range(nrows):    for col in range(ncols):        name = names_classifiers[nclassifier][0]        classifier = names_classifiers[nclassifier][1]        indices = np.argsort(classifier.feature_importances_)[::-1][:40]        g = sns.barplot(y=X_train.columns[indices][:40],x = classifier.feature_importances_[indices][:40] , orient='h',ax=axes[row][col])        g.set_xlabel("Relative importance",fontsize=12)        g.set_ylabel("Features",fontsize=12)        g.tick_params(labelsize=9)        g.set_title(name + " feature importance")        nclassifier += 1plt.show()

结果如下:

这里写图片描述
从上图可以看到,在随机森林的生成模型中,对预测结果产生最大权重的特征是sex,然后是TL_0和TL_1;
如果对比不同算法,可能会看到在不同算法中,各特征权重并不是完全相同的。还有一个有趣的现象,同样的算法,同样的输入,两次跑的结果中不同特征的权重可能也不一样,像随机森林之类算法也好理解,毕竟在抽取样本和特征组成新数据集的时候本身也存在随机性。

5.4 集成预测

利用多种算法建模并对测试样本进行预测

其思想其实跟随机森林的整体思想是一样的,对最后的结果采取少数服从多数的策略。

# 集成预测#####--------------------------------------------------------------------------------------------------votingC = VotingClassifier(estimators=[('rfc', RFC_best),('svc', SVMC_best)], voting='soft', n_jobs=4)#里面放的是各算法最佳参数之下的模型votingC = votingC.fit(X_train, Y_train)test_Survived = pd.Series(votingC.predict(test), name="Survived")results = pd.concat([IDtest,test_Survived],axis=1)results.to_csv("ensemble_python_voting.csv",index=False)

对测试集的预测结果保存至当前文件夹的ensemble_python_voting.csv文件中。

至此单机版的数据挖掘整个过程就大致如此了!

转载地址:https://blog.csdn.net/qingqing7/article/details/78516797 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:数据挖掘工具---spark使用方法(一)
下一篇:数据基础---mysql数据库操作(二)---JOIN用法

发表评论

最新留言

很好
[***.229.124.182]2024年03月01日 05时13分00秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

慕课python第五周测试答案_中国大学MOOC(慕课)_python+_满分章节测试答案 2021-06-24
lsof查看占用高_lsof解决磁盘占用过高,查询却无大文件处理一例! 2021-06-24
python调用oracle过程 权限不足_oracle-存储过程提示 ORA-01031: 权限不足 2021-06-24
java ee6教程_Java EE 极简教程(六):框架的选择 2021-06-24
java io流过滤流_IO流分类详细介绍和各种字节流类介绍与使用 过滤流 字节流 2019-04-21
java预处理指令_Java程序员学C++_1_C++中的预处理命令 | 学步园 2019-04-21
java分词支持拼音_java 支持分词的高性能拼音转换工具,速度是 pinyin4j 的两倍... 2019-04-21
java中的%不对 如何处理_Java心得--异常及其处理 2019-04-21
java 上传速度计算_java常见3种文件上传速度对比和文件上传方法详细代码 2019-04-21
java 中区分月份_输入一年当中的月份,判断是哪个季节.(用java编写并且用到了import java.io.*;)... 2019-04-21
java 试图模版_图解Java设计模式之模板模式 2019-04-21
java.exe占用cpu_Windows服务器java.exe占用CPU过高问题分析及解决 2019-04-21
支付宝 java 乱码_支付宝即时到账接口中文乱码问题 2019-04-21
java中的handler理解_handler 与message的一些理解 2019-04-21
JAVA礼物题_这些Java面试题,你一定要记住! 2019-04-21
java 隐藏email_java Email 2019-04-21
linux下qt浏览word文件内容,Qt获取office文件内容 2019-04-21
amd锐龙笔记本cpu怎么样_不知不觉已经15款 AMD Ryzen锐龙笔记本处理器盘点 2019-04-21
syslog打印不带等级_(转)syslog日志等级 2019-04-21
librosa能量_librosa语音信号处理 2019-04-21