随机森林+不平衡处理+标准化+遗传算法优化

  • 一、数据来源、文章介绍、代码获取
  • 二、简单:随机森林实现
  • 1、数据划分
  • 2、数据不平衡处理
  • 3、数据标准化
  • 4、随机森林模型训练(默认参数)
  • 5、模型评估
  • 5.1 模型评估函数
  • 5.2 模型特征重要性(非必要)
  • 5.3 混淆矩阵热力图(非必要)
  • 三、进阶:使用遗传算法优化随机森林


一、数据来源、文章介绍、代码获取

数据来源
本文使用的数据来源于(下载链接),2022年11月13日举办的第五届泰迪杯技能赛B题,文中所展示的数据作者已经进行过预处理和特征工程。
文章介绍
二分类问题是机器学习当中非常常见的问题。预测二分类问题有非常多的解决办法,如BP神经网络、SVM、梯度提升树等等非常多的模型可以使用。但是如何使得模型在基础模型上,能够有进一步性能提升就需要我们不断的通过参数的调整来使得模型具有更好的表现。同时,数据不平衡问题也是模型在训练过程当中不可忽视的问题。数据不平衡会导致模型偏向于多数类,使得模型的精度很高,但是召回率却非常低(说人话就是,少数类的特征没有学习到位)。因此,本文就针对于数据不平衡和参数调优基于随机森林算法进行处理。
完整代码获取:
完整代码链接

二、简单:随机森林实现

1、数据划分

这一部分比较常规,不多做论述,不懂得可以评论区讨论。

X_train, X_test, Y_train, Y_test = train_test_split(X,
                                                    Y,
                                                    shuffle=True,
                                                    test_size=0.2,
                                                    random_state=0)

2、数据不平衡处理

数据不平衡,在二分类当中简单来说,就是其中有一个类别得数量特别得多,具体表现为两个类别的数量不是近似于1:1的。这个时候问问就需要把数据调整为1:1使得模型能够更好的学习到少数类的特征。处理数据不平衡常见的手段是:采样,采样又分类为上采样和下采样,具体含义可以自己查一下,因为本文的数据量还凑合,所以使用了下采样。

from imblearn.under_sampling import RandomUnderSampler

rus = RandomUnderSampler(random_state=0, replacement=True)  # 采用随机欠采样(下采样)
X_train, Y_train = rus.fit_resample(X_train, Y_train)
print(X_train.shape, Y_train.shape)

3、数据标准化

这一部分比较常规,不多做论述,不懂得可以评论区讨论。其实,对于随机森林这类树状模型来说,标准化对模型的影响会比较小。

sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)

4、随机森林模型训练(默认参数)

调用sklearn库当中的随机森林算法进行模型的训练,这部分也比较常规,其中random_state参数为随机种子目的是为了实验的可复制性,n_jobs参数为调用所有资源进行计算加快计算速度。

RandomForest = RandomForestClassifier(random_state=0,
                                      n_jobs=-1)  #  随机森林
RandomForest.fit(X_train, Y_train)
print('模型基本构成:\n', RandomForest.base_estimator_)
print('模型特征重要性:\n', RandomForest.feature_importances_)

5、模型评估

5.1 模型评估函数

下面是作者封装好的一个二分类模型评估函数,有需要可以直接使用。

def model_evaluation(model, X, Y):
    pred = model.predict(X)
    print('准确率:', accuracy_score(Y, pred))
    print('召回率:', recall_score(Y, pred))
    print('精确率:', precision_score(Y, pred))
    print('F1:', f1_score(Y, pred))
    print("AUC", roc_auc_score(Y, pred))
    print('混淆矩阵:\n', confusion_matrix(Y, pred))
    print('模型评估报告:\n', classification_report(Y, pred))

    with sns.color_palette('Paired'):
        plt.figure(figsize=(8, 5))
        fpr, tpr, thres = roc_curve(Y, pred)
        auc_value = auc(fpr,tpr)
        plt.plot(fpr, tpr)
        plt.plot([0, 1], [0, 1], 'r--')
        plt.title('ROC')
        plt.xlabel('fpr',fontsize = 15)
        plt.ylabel('tpr',fontsize = 15)
        plt.text(0.35,0.5,f'auc:{auc_value}',fontsize = 15,c = 'r')
        plt.show()

model_evaluation(RandomForest,X_test,Y_test)

5.2 模型特征重要性(非必要)

在树状模型当中,可以通过信息增益或者信息增益比来知道哪一个特征在改模型当中更具有重要性,为了更加直观和美观的表示,作者利用pyecharts库对其模型的特征重要性进行了可视化。

随机森林需要迭代 随机森林算法改进_python

import os
from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.globals import ThemeType

Feature = [round(i,3)for i in list(RandomForest.feature_importances_*100)]
Columns = list(X.columns)
c = (
    Bar({"theme": ThemeType.MACARONS})
    .add_xaxis(Columns)
    .add_yaxis("Feature", Feature)
    .reversal_axis()
    .set_series_opts(label_opts=opts.LabelOpts(position="right",
                                               formatter="{c} %"))
    .set_global_opts(title_opts=opts.TitleOpts(title="Feature Importances"),
                    xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value} %")))
)


PATH = './image/'
if not os.path.exists(PATH):  # 如果路径不存在
    os.makedirs(PATH)
    
c.render("./image/RandomForestClassifier_feature_importances.html")

5.3 混淆矩阵热力图(非必要)

有时候写论文为了更加直观和美观的表示模型的性能,作者利用pyecharts库对其模型的混淆矩阵进行了可视化。

随机森林需要迭代 随机森林算法改进_python_02

from pyecharts import options as opts
from pyecharts.charts import HeatMap


# 测试数据的混淆矩阵
Y_pred = RandomForest.predict(X_test)
value = np.rot90(confusion_matrix(Y_test, Y_pred),-1)
value = [[i, j, int(value[i][j])] for i in range(value.shape[0]) for j in range(value.shape[1])]

c = (
    HeatMap()
    .add_xaxis(['0','1'])
    .add_yaxis("", ['1','0'], value,
              label_opts=opts.LabelOpts(is_show=True, position="inside"),)

    .set_global_opts(
        title_opts=opts.TitleOpts(title="RandomForestRegressor Test HeatMap"),
        visualmap_opts=opts.VisualMapOpts(max_=int(max(map(max, value))),
                                         orient='horizontal',
                                         pos_left='40%'),
    )
)
PATH = './result/'
if not os.path.exists(PATH):  # 如果路径不存在
    os.makedirs(PATH)
    
c.render("./result/RandomForestRegressor_Test_HeatMap.html")

三、进阶:使用遗传算法优化随机森林

在sklearn当中是带有参数调整的函数的,比如网络调参和随机调参,但是这两种方式比较简单,难以一步到位,参数范围大一点的话时间需要比较长,因此,本文使用了现代智能优化算法当中比较经典的遗传算法(GA),对随机森林进行优化。n_estimators、max_depth、min_samples_split、min_samples_leaf、max_features这几个参数对于随机森林算法来说比较重要。因此在本文当中使用sko库对其调参。这一部分比较难,不懂得可以私信,或者下载全部代码。
部分代码如下所示:

def RF(X):
    x1, x2, x3, x4, x5 = X
    mf = {0: 'auto', 1: 'sqrt', 2: 'log2', 3: None}

    rf = RandomForestClassifier(n_estimators=int(x1),
                                max_depth=int(x2),
                                min_samples_split=int(x3),
                                min_samples_leaf=int(x4),
                                max_features=mf[x5],
                                random_state=0,
                                n_jobs=-1)
    rf.fit(X_train, Y_train)
    pred = rf.predict(X_test)
    temp = f1_score(Y_test, pred)
    print('F1:', temp, 'n_estimators:', x1, 'max_depth:', x2,
          'min_samples_split:', x3, 'min_samples_leaf:', x4, 'max_features:',
          mf[x5])
    return -temp


ga = GA(
    func=RF,  # 优化函数
    n_dim=5,  # 优化参数维度
    size_pop=50,  # 种群规模
    max_iter=10,  # 最大迭代次数
    lb=[100, 2, 2, 2, 0],  # 下界
    ub=[1000, 50, 50, 50, 3],  # 上界
    precision=1)  # 整数约束

start_time = time.time()
best_x, best_y = ga.run()
print(time.time() - start_time)
print('best_X:', best_x, '\n', 'best_y:', best_y)