Skip to content

1、集成算法

1.1、不同集成算法

集成算法流程概述

不同集成算法对比

同质学习器(也叫算法,model,模型)

  • 随机森林,同质学习器,内部的100个模型,都是决策树
  • bagging:套袋法
    • 随机森林
    • 极端森林
  • boosting:提升法
    • GBDT
    • AdaBoost

1.2、bagging

1.3、自建集成算法(同质)

1、导包数据创建

Python
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
X,y = datasets.load_wine(return_X_y = True)
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state = 1024)

2、KNN集成算法

算法原理:

Python
# 一个算法,准确率 62%
knn = KNeighborsClassifier()
knn.fit(X_train,y_train)
print('单一KNN算法,得分是:',knn.score(X_test,y_test))

# 100个KNN算法
knn = KNeighborsClassifier()
# bag中100个knn算法
bag_knn = BaggingClassifier(base_estimator=knn,n_estimators=100,max_samples=0.8,max_features=0.7)
bag_knn.fit(X_train,y_train)
print('KNN集成算法,得分是:',bag_knn.score(X_test,y_test))

3、逻辑斯蒂回归集成算法

Python
import warnings
warnings.filterwarnings('ignore')
lr = LogisticRegression()
lr.fit(X_train,y_train)
print('单一逻辑斯蒂算法,得分是:',lr.score(X_test,y_test))

# 偶尔效果会好
bag = BaggingClassifier(base_estimator=LogisticRegression(),n_estimators=500,
                        max_samples=0.8, max_features=0.5)
bag.fit(X_train,y_train)
print('逻辑斯蒂集成算法,得分是:', bag.score(X_test,y_test))

4、决策树自建集成算法

Python
clf = DecisionTreeClassifier()
clf.fit(X_train,y_train)
print('单棵决策树,得分是:',clf.score(X_test,y_test))

bag = BaggingClassifier(base_estimator=DecisionTreeClassifier(),n_estimators=100,
                        max_samples=1.0,max_features=0.5)
bag.fit(X_train,y_train)
print('决策树集成算法,得分是:',bag.score(X_test,y_test))

5、随机森林(bagging封装)

Python
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(max_features='sqrt')
clf.fit(X_train,y_train)
print('随机森林集成算法,得分是:',clf.score(X_test,y_test))

1.4、boosting

2、GBDT梯度提升回归树

2.1、梯度提升树概述

  • gradient Boosting DecisionTree ----> GBDT

  • Boosting :提升的,一点点靠近最优答案

  • 残差
    • 残差的意思就是: A的预测值 + A的残差 = A的实际值
    • 残差 = 实际值 - 预测值
    • 预测值 = 实际值 - 残差

2.2、梯度提升树应用

1、数据加载

Python
import numpy as np
import pandas as pd 

# 加载数据
data_train = pd.read_csv('zhengqi_train.txt', sep='\t')
data_test = pd.read_csv('zhengqi_test.txt', sep='\t')
X_train = data_train.iloc[:,:-1]
y_train = data_train['target']
X_test = data_test

2、使用线性回归模型建模

Python
from sklearn.linear_model import LinearRegression,Ridge

model = LinearRegression()
model.fit(X_train,y_train)
y_pred = model.predict(X_test)
np.savetxt('LinearRegression.txt', y_pred)


model = Ridge(alpha=0.2)
model.fit(X_train,y_train)
y_pred = model.predict(X_test)
np.savetxt('Ridge.txt', y_pred)

1、使用全量数据构建梯度提升树(0.1434)

Python
from sklearn.ensemble import GradientBoostingRegressor

# GBDT模型训练预测
model = GradientBoostingRegressor()
model.fit(X_train,y_train)
y_pred = model.predict(X_test)
np.savetxt('GradientBoostingRegressor.txt', y_pred)

2.3、梯度提升树原理

1、创建数据并使用梯度提升回归树进行预测

Python
import numpy as np
from sklearn.ensemble import GradientBoostingRegressor
import matplotlib.pyplot as plt
from sklearn import tree
import graphviz

### 实际问题,年龄预测,回归问题
# 简单的数据,算法原理,无论简单数据,还是复杂数据,都一样
# 属性一表示花销,属性二表示上网时间
X = np.array([[600,0.8],[800,1.2],[1500,10],[2500,3]])
y = np.array([14,16,24,26]) # 高一、高三,大四,工作两年
# loss  = ls 最小二乘法
learning_rate = 0.1
gbdt = GradientBoostingRegressor(n_estimators=3,loss = 'squared_error',# 最小二乘法
                                 learning_rate=0.1)#learning_rate 学习率
gbdt.fit(X,y)#训练
y_ = gbdt.predict(X)#预测
y_

2、计算残差

Python
# 目标值,真实值,算法,希望,预测,越接近真实,模型越好!!!
print(y)
# 求平均,这个平均值就是算法第一次预测的基准,初始值
print(y.mean())
# 残差:真实值,和预测值之间的差
residual = y - y.mean()
residual
# 残差,越小越好
# 如果残差是0,算法完全准确的把数值预测出来!

3、绘制三棵树

  • 第一棵树

    Python
    # 第一颗树,分叉时,friedman-mse (就是均方误差)= 26
    print('均方误差:',((y - y.mean())**2).mean())
    dot_data = tree.export_graphviz(gbdt[0,0],filled=True)
    graph = graphviz.Source(dot_data)
    graph

    Python
    # 梯度下降,降低残差
    residual = residual - learning_rate*residual
    residual
    # 输出:array([-5.4, -3.6,  3.6,  5.4])
  • 第二棵树

    Python
    # 第二颗树
    dot_data = tree.export_graphviz(gbdt[1,0],filled=True)
    graph = graphviz.Source(dot_data)
    graph

    Python
    # 梯度下降,降低残差
    residual = residual - learning_rate*residual
    residual
    # 输出:array([-4.86, -3.24,  3.24,  4.86])
  • 第三棵树

    Python
    # 第三颗树
    dot_data = tree.export_graphviz(gbdt[2,0],filled=True)
    graph = graphviz.Source(dot_data)
    graph

    Python
    # 梯度下降,降低残差
    residual = residual - learning_rate*residual
    residual
    # 输出:array([-4.374, -2.916,  2.916,  4.374])

    4、使用残差计算最终结果

    Python
    # 使用残差一步步,计算的结果
    y_ = y - residual
    print('使用残差一步步计算,最终结果是:\n',y_)
    # 使用算法,预测
    gbdt.predict(X)
    # 两者输出结果一样

    结论:

    使用残差计算的结果和算法预测一模一样!

2.4、梯度提升回归树的最佳裂分条件计算

1、第一棵树,分裂情况如下:

Python
# 计算残差,计算未分裂均方误差
residual_1 = y - y.mean() # 初始残差
lower_mse = ((residual_1 - residual_1.mean())**2).mean()
print('未分裂均方误差是:',lower_mse)


best_split = {}
for col in range(2): # 遍历特征,两列特征
    for i in range(3): # 拆分成3份
        t = X[:,col].copy()
        t.sort() # 从小到大
        
        split = t[i:i + 2].mean() # 拆分条件值,600-800 平均值700
        cond = X[:,col] <= split # 左右两边
        
        # 左右两边分别计算mse
        mse1 = round(((residual_1[cond] - residual_1[cond].mean())**2).mean(),3)
        mse2 = round(((residual_1[~cond] - residual_1[~cond].mean())**2).mean(),3)
        
        p1 = cond.sum()/cond.size
        mse = round(mse1 * p1 + mse2 * (1- p1),3)
        print('第%d列' % (col),'裂分条件是:',split,'均方误差是:',mse1,mse2,mse)
        
        if mse < lower_mse:
            best_split.clear()
            lower_mse = mse
            best_split['第%d列'%(col)] = [split,lower_mse]
        elif mse == lower_mse:
            lower_mse = mse
            best_split['第%d列'%(col)] = [split,lower_mse]

print('最佳分裂条件是:',best_split)

2、第二棵树,分裂情况如下:

Python
# 梯度下降,降低残差
residual_2 = residual_1 - learning_rate*residual_1

# 计算未分裂均方误差
lower_mse = round(((residual_2 - residual_2.mean())**2).mean(),3)
print('未分裂均方误差是:',lower_mse)
best_split = {}
for col in range(2):
    for i in range(3):
        t = X[:,col].copy()
        t.sort()
        split = t[i:i + 2].mean()
        cond = X[:,col] <= split
        mse1 = round(((residual_2[cond] - residual_2[cond].mean())**2).mean(),3)
        mse2 = round(((residual_2[~cond] - residual_2[~cond].mean())**2).mean(),3)
        p1 = cond.sum()/cond.size
        mse = round(mse1 * p1 + mse2 * (1- p1),3)
        print('第%d列' % (col),'裂分条件是:',split,'均方误差是:',mse1,mse2,mse)
        if mse < lower_mse:
            best_split.clear()
            lower_mse = mse
            best_split['第%d列'%(col)] = [split,lower_mse]
        elif mse == lower_mse:
            lower_mse = mse
            best_split['第%d列'%(col)] = [split,lower_mse]
print('最佳分裂条件是:',best_split)

3、第三棵树,分裂情况如下:

Python
# 梯度下降,降低残差
residual_3 = residual_2 - learning_rate*residual_2
# 计算未分裂均方误差
lower_mse = round(((residual_3 - residual_3.mean())**2).mean(),3)
print('未分裂均方误差是:',lower_mse)
best_split = {}
for col in range(2):
    for i in range(3):
        t = X[:,col].copy()
        t.sort()
        split = t[i:i + 2].mean()
        cond = X[:,col] <= split
        mse1 = round(((residual_3[cond] - residual_3[cond].mean())**2).mean(),3)
        mse2 = round(((residual_3[~cond] - residual_3[~cond].mean())**2).mean(),3)
        p1 = cond.sum()/cond.size
        mse = round(mse1 * p1 + mse2 * (1- p1),3)
        print('第%d列' % (col),'裂分条件是:',split,'均方误差是:',mse1,mse2,mse)
        if mse < lower_mse:
            best_split.clear()
            lower_mse = mse
            best_split['第%d列'%(col)] = [split,lower_mse]
        elif mse == lower_mse:
            lower_mse = mse
            best_split['第%d列'%(col)] = [split,lower_mse]
print('最佳分裂条件是:',best_split)

Released under the MIT License.