代码及数据集:https://github.com/JIANG54864/ml_exp/tree/main/exp5

【实验内容及说明】

本实验通过使用乘客数据(即姓名、年龄、性别、社会经济阶层等)使用集成学习的方法,来对数据集进行分类,从而预测哪些乘客在事故中幸存。本实验训练集包含891条数据,测试集包含418条数据。每条数据都有以下几个特征,包括Pclass(舱位等级)、Sex(性别)、Age(年龄)、SibSp(同行的兄弟姐妹/配偶等的个数)、Parch(同行的父母/子女的个数)、Ticker(票号)、Fare(票价)、Cabin(舱位号)、Embarked(上船港口,C = Cherbourg,Q = Queenstown,S = Southampton)等。通过Survived(乘客是否存活,1表示存活) 作为标签进行模型的训练。

利用若干算法,针对同一样本数据训练模型,使用投票机制,少数服从多数,用多数算法给出的结果当作最终的决策依据,对数据集进行分类,给出在测试集上的精确度。集成学习所用的基学习器需要自己实现而不能调用现成的第三方库。

【正文】

集成学习构建并结合多个学习器来完成任务,这些学习器可以都相同(同质集成)也可以不同(异质集成)。同质集成中,根据个体学习器的生成方式可分为两大类,一类是个体学习器间存在强依赖关系、必须串行生成的序列化方法,代表是将弱学习器提升为强学习器的Boosting族算法:

1739787107176

先从初始训练集训练出一个基学习器,根据基学习器的表现对训练样本分布进行权重调整,使得先前基学习器做错的训练样本在后续受到更多关注,基于调整后的样本分布来训练下一个学习器,如此重复进行,最终的分类器是这些基学习器的加权组合。

另一类是个体学习器间不存在强依赖关系、可同时生成的并行化方法,代表是Bagging和 “随机森林” (Random Forest)。随机森林在以决策树为基学习器构建Bagging集成的基础上,进一步在决策树的训练过程中引入了随机属性选择。具体来说,传统决策树在选择划分
属性时是在当前结点的属性集合中选择一个最优属性;而在RF中,对基决策树的每个结点,先从该结点的属性集合中随机选择一个包含k个属性的子集,然后再从这个子集中选择一个最优属性用于划分。

本实验采用Bagging方法,基学习器采用贝叶斯分类器,不再赘述。

Bagging的基本流程为:给定包含馆个样本的数据集,我们先随机取出一个样本放入采样集中,再把该样本放回初始数据集,使得下次采样时该样本仍有可能被选中,这样,经过m
次随机采样操作,我们得到含m个样本的采样集,照这样,我们可采样出T个含 m 个训练样本的采样集

1
2
3
Array = []
for i in range(5):
Array.append(train.sample(frac=1, replace=True, axis=0))

然后基于每个采样集训练出一个基学习器,

1
2
3
4
5
6
isSurvived = []
for index, row in test.iterrows():
t = []
for i in range(5):
t.append(BayesClassifier(row, Array[i]))
isSurvived.append(t)

再将这些基学习器进行结合,这就是在对预测输出进行结合时,Bagging通常对分类任务使用简单投票法,对回归任务使用简单平均法。本实验是分类,故采用投票法。

1
2
3
4
5
6
7
8
vote = []
for item in isSurvived:
SurvivedCount = str(item).count('1')
if SurvivedCount > 2:
vote.append(1)
else:
vote.append(0)
test['forecast'] = vote

补上数据预处理的部分,通过dataframe.info()和unique = dataframe[name].unique().shape[0]查看到cabin的缺失值过高,Ticket的取值也过多,查看具体的值可以判断对于分类任务没有意义,因此在删除取值唯一和取值各不相同的值后将他们手动删除。

1
2
3
4
5
6
7
8
for name in dataframe.columns:
unique = dataframe[name].unique().shape[0]
full = dataframe[name].shape[0]
# print({name}, '的不同取值个数:', unique, '/', full)
if (unique == 1) | (unique == full):
dataframe = dataframe.drop(name, axis=1)
# print({name}, '被删除')
dataframe = dataframe.drop(['Cabin', 'Ticket'], axis=1)

用众数填充缺失值,并将object对象替换为数值方便处理。取值较多的age和fare进行离散化。

1
2
3
4
5
6
7
8
9
10
11
missing = dataframe.isnull().any(axis=0)
for index, value in missing.items():
if value:
dataframe[index].fillna(dataframe[index].mode()[0], inplace=True)
mapper = {
'Sex': {'male': 0,'female': 1},
'Embarked': {'C': 0,'Q': 1,'S': 2,}
}
dataframe.replace(mapper, inplace=True)
for col in ['Age', 'Fare']:
dataframe[col] = pd.cut(dataframe[col],2, labels=[0, 1])

参考文献及资料:

[1] 周志华 著. 机器学习[M]. 北京: 清华大学出版社, 2016.

[2] https://mima.sdu.edu.cn/Members/xinshunxu/Courses/ML/Chapter8.pdf