1. 基于投票法的集成学习

1.1 投票与机器学习

        投票简单来说就是“少数服从多数”,那么这个道理跟机器学习有什么关系呢?

        我们知道集成学习简单来说就是用多个不同的模型来处理同一个问题,那么对于多个不同的处理结果我们应该如何选取呢?

        对于一个分类问题来说,如果我们用多个不同的模型来预测,可能会得到多个不同的结果。显然,这里我们就可以用少数服从多数的投票法来决定。我们可以直接将投票结果中出现次数最多的类别当作预测结果,这种投票方法叫硬投票。我们还可以所有模型预测概率算数平均值最大的类别当作预测结果,这种投票方法叫软投票

        关于硬投票和软投票,我们可以举一个简单的例子。假设有一个二分类问题,预测的标签只有A和B,我们使用了三个模型分别对某个数据进行预测,得到的结果如下:

模型结果(标签和预测概率)
模型1A(51%)
模型2A(51%)
模型3B(99%)

        如果是按照硬投票预测,根据少数服从多数的原则,最后的预测结果应该是A。但是如果是按照软投票来预测,三个模型对A的预测概率的算数平均数是34.33%,而对B则是65.67%。因此最后的预测结果应该是B。换句话说,对于同一个问题,软投票和硬投票的结果未必一致。

        对于一个回归问题,如果我们用多个不同的模型来预测,也可能会得到多个不同的结果。但是在这里我们很难直接用少数服从多数的方式判断应取的预测值。这里,我们可以将所有模型的预测结果取一个平均值。这样也相当于所有模型都参与到了最终的决策中。

        由此,投票法自身也就是一种集成学习模型。它通过多个模型的集成来降低方差,从而提升模型鲁棒性。理想情况下,投票法的预测效果应优于任何一个单一模型。

        理论上,参与投票法的模型可以是任何已经训练好了的模型,但在实际应用上,投票法想产生较好的效果需要满足两个条件。

        1. 不同模型之间的效果不可以差太大。如果某个模型效果远不如其他模型,很可能会成为噪声;

        2. 模型之间应具有较小的同质性。换句话说所有参与的模型在原理或结构上应具有明显的差异。例如在模型预测效果近似的情况下,基于树模型和线性模型的投票法就要优于两个树模型和两个线性模型。

        对于分类问题,应当采取硬投票还是软投票要看参与的模型可否能预测出明确的结果。假如所有参与的模型都是决策树模型,那么采取硬投票更合适。而如果模型预测的都是概率,则采用软投票更合适。

        投票法面临两个问题。第一个问题就是,它将所有参与的模型都一视同仁。这就意味着所有的模型对结果的贡献都是一样的。假如某些模型表现不稳定,时好时坏。则对最后的结果也会产生一定的影响。第二个则是同质性较小的多个模型的条件太理想化,大多模型可能都比较相近。

1.2 在sklearn中使用投票法

        sklearn中有两个投票法的封装模块,VotingRegressor和VotingClassifier。它们参数相同,操作方式也相同。下面我们看个构建投票法的实例。

from sklearn.linear_model import LogisticRegression #模型1
from sklearn.svm import SVC #模型2
from sklearn.ensemble import VotingClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

# 构建集成模型参数,包括每个模型的名称,所用的函数,其中还可以使用管道操作封装一系列操作
# 这里我们给SVC模型添加一个标准归一化处理
models = [('lr', LogisticRegression()), \
            ('svm', make_pipeline(StandardScaler(), SVC()))]

# 构建集成模型实例,投票方式选择软投票
ensemble = VotingClassifier(estimators = models, voting = 'soft')

        我们再看一个例子,这次我们将多个kNN模型封装成一个集成模型,并用它做分类。

from sklearn.datasets import make_classification
from sklearn.ensemble import VotingClassifier
from sklearn.model_selection import cross_val_score
from sklearn.neighbors import KNeighborsClassifier
from matplotlib import pyplot

# 生成人工数据
def get_dataset():
    X, y = make_classification(n_samples = 1000, n_features = 20, \
                                n_informative = 15, n_redundant = 5, \
                                random_state = 2)
    return X,y

# 构建由多个不同的kNN模型组成的集成模型
def get_voting():

    models = list()
    models.append(('knn1', KNeighborsClassifier(n_neighbors=1)))
    models.append(('knn3', KNeighborsClassifier(n_neighbors=3)))
    models.append(('knn5', KNeighborsClassifier(n_neighbors=5)))
    models.append(('knn7', KNeighborsClassifier(n_neighbors=7)))
    models.append(('knn9', KNeighborsClassifier(n_neighbors=9)))

    ensemble = VotingClassifier(estimators = models, voting = 'hard')
    return ensemble

# 构建评估函数
def evaluate_model(model, X, y):
    cv = RepeatedStratifiedKFold(n_splits = 10, n_repeats = 3, \
                                random_state = 1)
    scores = cross_val_score(model, X, y, scoring = 'accuracy', cv = cv, \
                                n_jobs = -1, error_score='raise')
    return scores

# 收集所有待评估的模型
def get_models():
    models = dict()
    models['knn1'] = KNeighborsClassifier(n_neighbors=1)
    models['knn3'] = KNeighborsClassifier(n_neighbors=3)
    models['knn5'] = KNeighborsClassifier(n_neighbors=5)
    models['knn7'] = KNeighborsClassifier(n_neighbors=7)
    models['knn9'] = KNeighborsClassifier(n_neighbors=9)
    models['hard_voting'] = get_voting()
    return models

X, y = get_dataset()
models = get_models()
results, names = list(), list()

for name, model in models.items():
    scores = evaluate_model(model, X, y)
    results.append(scores)
    names.append(name)
    print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))

# 查看不同模型精度分数分布
pyplot.boxplot(results, labels = names, showmeans = True)
pyplot.show()

          输出结果如下:

knn1 0.873 (0.030)
knn3 0.889 (0.038)
knn5 0.895 (0.031)
knn7 0.899 (0.035)
knn9 0.900 (0.033)
hard_voting 0.902 (0.034)

         通过箱形图我们可以看到硬投票方法对预测结果精度的提升。

2. Bagging

2.1 原理

         在我看来,Bagging是对投票法的一种优化。既然是优化,则说明一般的投票法存在某些问题。我们之前提到,对于集成学习而言,理想的基模型选取条件是希望各个模型具有异质性即彼此的原理和结构具有较大差异。但是,实际情况下这一点不太容易保证,就像上面的实例一样,我们采用的基模型可能都是同质的。因此,为了提升同质基模型的异质性,我们想到一个简单的思路,那就是对数据进行不同的采样。然后让同质基模型在各自的采样数据集上训练,这样基模型的训练环境就存在了差异,进而提升了异质性。

        Bagging的核心在于自助采样(bootstrap)这一概念。简单来说就是有放回抽样。我们通过有放回抽样的方式得到多个可能存在交集但是又不完全一样的数据集。然后基于每个数据集并行训练各自的基模型。最后将这些模型做集成,利用投票方式得到预测结果。这就是Bagging的基本流程。

        Bagging中的每个基模型都是弱模型,而且它们都倾向于过拟合,多个这样的模型并行训练和决策会通过降低方差的方式减少误差。

2.2 Bagging在决策树中的应用

        由于Bagging最常见和最成功的应用都是在决策树模型上的集成。因此这里我们也用两种决策树模型当作基模型来举例。

        我们先复习一下决策树的基础知识。决策树模型的每个非叶子节点表示模型对样本在一个特征上的判断,节点下方的分支代表对样本的划分。决策树的建立过程是一个对训练数据不断划分的过程。我们希望通过划分,决策树的分支节点所包含的样本“纯度”要尽可能地高。换句话说,每次划分之后,子节点中包含的所有数据应当越来越相似。这不但是决策树的训练过程,而且还是决策树选择当前最佳划分节点的特征的规则。

        那么,要如何来衡量这种“纯度”呢?目前常见的指标有信息增益(IG)、信息增益比和基尼指数。

        要了解什么是信息增益,首先要了解什么叫信息熵和条件信息熵。在信息论和概率统计中,信息熵表示随机变量的不确定程度。对于一组数据来说,越随机、不确定性越高,信息熵越大,反之则越小。信息熵可以用香农公式

H=-\sum_{i=1}^{k} p_{i} \log \left(p_{i}\right)

来计算。其中,k表示随机变量的所有取值情况。在决策树中可以用来表示节点中的所有数据的标签的取值情况。

        我们假设有两组标签

1:\{0, 0, 1, 1, 0, 1, 1, 1\}

2:\{0, 0, 0, 1, 0, 0, 0, 0\}

        则它们对应的信息熵为

H_{1} = -(p_{0}log_{2}p_{0} + p_{1}log_{2}p_{1})=-(\frac{3}{8}log_{2} \frac{3}{8} + \frac{5}{8} log_{2} \frac{5}{8}) = 0.95

H_{2} = -(p_{0}log_{2}p_{0} + p_{1}log_{2}p_{1})=-(\frac{7}{8}log_{2} \frac{7}{8} + \frac{1}{8} log_{2} \frac{1}{8}) = 0.54

        显然H_{1}>H_{2},从数据中我们可以发现1确实比2要更加“不确定”或者“不纯净”。

        知道了信息熵,我们还需要进一步了解什么叫条件信息熵。简单来说,条件信息熵指的就是按照某特征对节点划分后,各个子节点的信息熵的加权平均值。其中权值就是新节点中数据占原节点中数据的比例。用形式化定义来描述就是

H(T \mid X)=\sum_{x \in X} p(X=x) H(T \mid X=x)

其中,T指原节点,X指划分特征,x是该划分特征的不同取值。

        为了更好地理解,我们举一个例子。假设有一个如图所示的矩阵

\LARGE \begin{bmatrix} 1 & 1 & 1\\ 1 & 0 & 0\\ 1 & 1 & 1\\ 0 & 0 & 0 \end{bmatrix}

        该矩阵每行代表一个数据,前两列代表特征,记作x_{1}x_{2},最后一列代表标签 。我们分别按照x_{1}x_{2}来对数据进行划分,可以计算如下的条件信息熵

H(T|x_{1})=\frac{3}{4}H(\{1, 0, 1\}) + \frac{1}{4}H(\{0\})=0.69

H(T|x_{2})= \frac{2}{4} H(\{1, 1\}) + \frac{2}{4} H(\{0, 0\})=0

        在知道了信息熵和条件信息熵之后,我们就可以计算信息增益了。实际上,信息增益就是一个节点划分前的信息熵与划分后的条件信息熵的差。这个差值越大,说明划分后的节点中标签取值越确定。我们还是按照上面的例子,先计算原节点的信息熵

H(T)=H(\{1, 0, 1, 0\})=1

然后我们计算以不同特征划分后的信息增益

IG(T,x_{1})=H(T)-H(T|x_{1})=1-0.69=0.31

IG(T,x_{2})=H(T)-H(T|x_{2})=1-0=1

        显然IG(T,x_{2})>IG(T,x_{1}),这说明x_{2}在目前可以作为划分节点的最佳特征。

        在信息增益的基础上,诞生了信息增益比的概念。信息增益比实际上就是让信息增益除以一个系数。该系数是划分特征在原节点中的信息熵。我们还是按照上个例子来计算

IG_{R}(T,x_{1})=\frac{IG(T,x_{1})}{H_{x_{1}}(T)}=\frac{0.31}{H(\{1,1,1,0\})}=0.38

IG_{R}(T,x_{2})=\frac{IG(T,x_{2})}{H_{x_{2}}(T)}=\frac{1}{H(\{1, 0, 1, 0\})}=1

        除了信息增益和信息增益比,我们还可以用基尼指数来衡量确定性。基尼指数指的是一个随机选中的样本被分错的概率。由此它的形式化定义如下

Gini(T) =\sum_{i=1}^{k} p_{i}(1-p_{i})=1-\sum_{i=1}^{k} p_{i}^{2}

        如果我们对节点进行划分,划分后的基尼指数可以定义为

Gini_{x}=\sum_{x \in X} p(X=x)Gini(T|X=x)

        一般,我们会选择使得划分后基尼指数最小的特征来划分。需要强调的是在用基尼指数衡量划分效果时我们只看指数值而不是变化量。

        另外,这三种指标对应的决策树模型分别为:ID3(信息增益),C4.5(信息增益比)和CART(基尼指数)。

        Bagging最经典的应用是随机森林(RF)。在具体实现上,每个决策树模型的构建特征和训练样本都是通过随机采样得到的。随机森林的预测结果是多个决策树输出的投票结果。

2.3 在sklearn中使用Bagging

        类似于投票法,在sklearn中也有两个封装好的模块,BaggingRegressor和BaggingClassifier。

from sklearn.datasets import make_classification
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import BaggingClassifier

X, y = make_classification(n_samples = 1000, n_features = 20, \
                            n_informative = 15, n_redundant = 5, \
                            random_state = 5)

model = BaggingClassifier()

cv = RepeatedStratifiedKFold(n_splits = 10, n_repeats = 3, random_state = 1)
n_scores = cross_val_score(model, X, y, scoring = 'accuracy', cv = cv, \
                            n_jobs = -1, error_score = 'raise')

print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐