找回密码
 立即注册
查看: 398|回复: 0

粒子群算法(PSO)优化随机森林超参数python实现

[复制链接]
发表于 2021-11-28 12:46 | 显示全部楼层 |阅读模式
PSO- RF算法首先对超参数n estimators、max depth随机初始化一群粒子,计算相应的适应度值,并通过不断更新粒子的速度和位置来达到最佳的适应度值,从而得到最佳RF模型的超参数n_estimators、max_depth,进而提高RF模型的收敛速度及预测性能。粒子群优化算法在解决实际问题中展现了其实现容易、精度高、收敛速度快等优点。

样本数据:
(附件已经上传)
trainX:shape为 n x 132 的特征矩阵
trainY:长度为 n 的 list
废话不多说,直接上代码。



# -*- coding: utf-8 -*-
"""
Created on Sat Dec  1 17:00:23 2018

@author: lj
"""
import pickle
import time

import numpy as np
from sklearn import svm
from sklearn import model_selection
import random
import matplotlib.pyplot as plt

## 1.加载数据
from sklearn.ensemble import RandomForestClassifier
from tqdm import tqdm

max_count = 300

def load_data():
    '''导入训练数据
    '''
    with open(rf"I:/样本数据_非60m点/pickle/labels_all_{max_count}.pkl", "rb") as f:
        labels = pickle.load(f)
    with open(rf"I:/样本数据_非60m点/pickle/features_all_{max_count}.pkl", "rb") as f:
        features = pickle.load(f)

    X = features
    y = labels

    return X, y


## 2. PSO优化算法
class PSO(object):
    def __init__(self, particle_num, particle_dim, iter_num, c1, c2, w, max_value, min_value):
        '''参数初始化
        particle_num(int):粒子群的粒子数量
        particle_dim(int):粒子维度,对应待寻优参数的个数
        iter_num(int):最大迭代次数
        c1(float):局部学习因子,表示粒子移动到该粒子历史最优位置(pbest)的加速项的权重
        c2(float):全局学习因子,表示粒子移动到所有粒子最优位置(gbest)的加速项的权重
        w(float):惯性因子,表示粒子之前运动方向在本次方向上的惯性
        max_value(float):参数的最大值
        min_value(float):参数的最小值
        '''
        self.particle_num = particle_num
        self.particle_dim = particle_dim
        self.iter_num = iter_num
        self.c1 = c1  ##通常设为2.0
        self.c2 = c2  ##通常设为2.0
        self.w = w
        self.max_value = max_value
        self.min_value = min_value

    ### 2.1 粒子群初始化
    def swarm_origin(self):
        '''粒子群初始化
        input:self(object):PSO类
        output:particle_loc(list):粒子群位置列表
               particle_dir(list):粒子群方向列表
        '''
        particle_loc = []
        particle_dir = []
        for i in range(self.particle_num):
            tmp1 = []
            tmp2 = []
            for j in range(self.particle_dim):
                a = random.random()
                b = random.random()
                tmp1.append(a * (self.max_value - self.min_value) + self.min_value)
                tmp2.append(b)
            particle_loc.append(tmp1)
            particle_dir.append(tmp2)

        return particle_loc, particle_dir

    ## 2.2 计算适应度函数数值列表;初始化pbest_parameters和gbest_parameter
    def fitness(self, particle_loc):
        '''计算适应度函数值
        input:self(object):PSO类
              particle_loc(list):粒子群位置列表
        output:fitness_value(list):适应度函数值列表
        '''
        fitness_value = []
        ### 1.适应度函数为RBF_SVM的3_fold交叉校验平均值
        for i in range(self.particle_num):
            print(f"particle_loc 0 {particle_loc[0]} particle_loc 1 {particle_loc[1]}")

            model = RandomForestClassifier(n_estimators=int(particle_loc[0]), max_features=int(particle_loc[1]),
                                           n_jobs=-1, verbose=1)

            # rbf_svm = svm.SVC(kernel='rbf', C=particle_loc[0], gamma=particle_loc[1])
            cv_scores = model_selection.cross_val_score(model, trainX, trainY, cv=3, scoring='accuracy')
            fitness_value.append(cv_scores.mean())
        ### 2. 当前粒子群最优适应度函数值和对应的参数
        current_fitness = 0.0
        current_parameter = []
        for i in range(self.particle_num):
            if current_fitness < fitness_value:
                current_fitness = fitness_value
                current_parameter = particle_loc

        return fitness_value, current_fitness, current_parameter

    ## 2.3  粒子位置更新
    def update(self, particle_loc, particle_dir, gbest_parameter, pbest_parameters):
        '''粒子群位置更新
        input:self(object):PSO类
              particle_loc(list):粒子群位置列表
              particle_dir(list):粒子群方向列表
              gbest_parameter(list):全局最优参数
              pbest_parameters(list):每个粒子的历史最优值
        output:particle_loc(list):新的粒子群位置列表
               particle_dir(list):新的粒子群方向列表
        '''
        ## 1.计算新的量子群方向和粒子群位置
        for i in range(self.particle_num):
            a1 = [x * self.w for x in particle_dir]
            a2 = [y * self.c1 * random.random() for y in
                  list(np.array(pbest_parameters) - np.array(particle_loc))]
            a3 = [z * self.c2 * random.random() for z in list(np.array(gbest_parameter) - np.array(particle_dir))]
            particle_dir = list(np.array(a1) + np.array(a2) + np.array(a3))
            #            particle_dir = self.w * particle_dir + self.c1 * random.random() * (pbest_parameters - particle_loc) + self.c2 * random.random() * (gbest_parameter - particle_dir)
            particle_loc = list(np.array(particle_loc) + np.array(particle_dir))

        ## 2.将更新后的量子位置参数固定在[min_value,max_value]内
        ### 2.1 每个参数的取值列表
        parameter_list = []
        for i in range(self.particle_dim):
            tmp1 = []
            for j in range(self.particle_num):
                tmp1.append(particle_loc[j])
            parameter_list.append(tmp1)
        ### 2.2 每个参数取值的最大值、最小值、平均值   
        value = []
        for i in range(self.particle_dim):
            tmp2 = []
            tmp2.append(max(parameter_list))
            tmp2.append(min(parameter_list))
            value.append(tmp2)

        for i in range(self.particle_num):
            for j in range(self.particle_dim):
                particle_loc[j] = (particle_loc[j] - value[j][1]) / (value[j][0] - value[j][1]) * (
                            self.max_value - self.min_value) + self.min_value


        return particle_loc, particle_dir

    ## 2.4 画出适应度函数值变化图
    def plot(self, results):
        '''画图
        '''
        X = []
        Y = []
        for i in range(self.iter_num):
            X.append(i + 1)
            Y.append(results)
        plt.plot(X, Y)
        plt.xlabel('Number of iteration', size=15)
        plt.ylabel('Value of CV', size=15)
        plt.title('PSO_RF parameter optimization')
        plt.show()

    ## 2.5 主函数
    def main(self):
        '''主函数
        '''
        results = []
        log = []
        best_fitness = 0.0
        ## 1、粒子群初始化
        particle_loc, particle_dir = self.swarm_origin()
        ## 2、初始化gbest_parameter、pbest_parameters、fitness_value列表
        ### 2.1 gbest_parameter
        gbest_parameter = []
        for i in range(self.particle_dim):
            gbest_parameter.append(0.0)
        ### 2.2 pbest_parameters
        pbest_parameters = []
        for i in range(self.particle_num):
            tmp1 = []
            for j in range(self.particle_dim):
                tmp1.append(0.0)
            pbest_parameters.append(tmp1)
        ### 2.3 fitness_value
        fitness_value = []
        for i in range(self.particle_num):
            fitness_value.append(0.0)

        ## 3.迭代
        for i in tqdm(range(self.iter_num)):
            ### 3.1 计算当前适应度函数值列表
            current_fitness_value, current_best_fitness, current_best_parameter = self.fitness(particle_loc)
            ### 3.2 求当前的gbest_parameter、pbest_parameters和best_fitness
            for j in range(self.particle_num):
                if current_fitness_value[j] > fitness_value[j]:
                    pbest_parameters[j] = particle_loc[j]
            if current_best_fitness > best_fitness:
                best_fitness = current_best_fitness
                gbest_parameter = current_best_parameter

            print('iteration is :', i + 1, ';Best parameters:', gbest_parameter, ';Best fitness', best_fitness)
            results.append(best_fitness)
            ### 3.3 更新fitness_value
            fitness_value = current_fitness_value
            ### 3.4 更新粒子群
            particle_loc, particle_dir = self.update(particle_loc, particle_dir, gbest_parameter, pbest_parameters)
            ## 写入日志
            log.append((i, gbest_parameter[0], gbest_parameter[1], best_fitness))
            ##绘图

            print(particle_loc)
            # 绘制粒子适应度图
            os.makedirs('fig', exist_ok=True)
            plt.plot(list(range(0, len(current_fitness_value))), current_fitness_value)
            plt.title(i)
            plt.savefig(f"fig/{i}_适应度_{current_best_fitness}.png")
            plt.show()
            # 绘制粒子位置
            a = np.array(particle_loc)
            x = a[:, 0].tolist()
            y = a[:, 1].tolist()

            plt.scatter(x, y)
            plt.title(i)
            plt.savefig(f"fig/{i}_粒子位置_{current_best_fitness}.png")
            plt.show()

        ## 4.结果展示
        results.sort()
        self.plot(results)
        print('Final parameters are :', gbest_parameter)
        with open("log.pkl", "wb") as f:
            pickle.dump(log, f)

if __name__ == '__main__':
    print('----------------1.Load Data-------------------')
    trainX, trainY = load_data()
    print('----------------2.Parameter Seting------------')
    particle_num = 100
    particle_dim = 2
    iter_num = 7
    c1 = 2
    c2 = 2
    w = 0.8
    max_value = 100
    min_value = 1
    print('----------------3.PSO_RF-----------------')
    pso = PSO(particle_num, particle_dim, iter_num, c1, c2, w, max_value, min_value)
    pso.main()



输出:





样本数据:
样例数据。仅供测试
features_all_300.pkl
1.3M
· 百度网盘


labels_all_300.pkl
4.8K
· 百度网盘

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-16 02:45 , Processed in 0.091321 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表