Python基础学习打卡第12天(虫豸版)- Python60天挑战之旅

退火算法

物理现象:退火现象指物体逐渐降温的物理现象,温度愈低,物体的能量状态会低;温度足够低后,液体开始冷凝与结晶,在结晶状态时,系统的能量状态最低。大自然在缓慢降温(即退火)时,可找到最低能量状态:结晶。但是,如果过程过急过快,快速降温(亦称淬炼)时,会导致不是最低能态的非晶形。

算法概述

  • 目标函数 f 在第 i+1 步比第 i 步更优,即移动后比移动前更优,则总是向该方向移动
  • 目标函数 f 移动后比移动前要差,则以一定概率接受该移动,这个概率随着时间推移而降低(逐步降低则趋向稳定)
  • 这个根据一定概率P是否选择差解的方法,叫做Metropolis准则(这个准则来源于模拟退火,故整个方法成为模拟退火)

    # --- 2. 模拟退火算法优化随机森林 ---
    print("\n--- 2. 模拟退火算法优化随机森林 (训练集 -> 测试集) ---")
    
    import random
    import numpy as np
    import time
    
    # 定义适应度函数
    def fitness_function(params): 
        n_estimators, max_depth, min_samples_split, min_samples_leaf = params
        model = RandomForestClassifier(n_estimators=int(n_estimators),
                                       max_depth=int(max_depth),
                                       min_samples_split=int(min_samples_split),
                                       min_samples_leaf=int(min_samples_leaf),
                                       random_state=42)
        model.fit(X_train, y_train)
        y_pred = model.predict(X_test)
        accuracy = accuracy_score(y_test, y_pred)
        return accuracy
    
    
    # 模拟退火算法实现(simulated_annealing函数的初始化阶段)
    def simulated_annealing(initial_solution, bounds, initial_temp, final_temp, alpha):
        current_solution = initial_solution # 把你的当前位置设为起始点
        current_fitness = fitness_function(current_solution) # 给当前位置评分
        best_solution = current_solution
        best_fitness = current_fitness
        temp = initial_temp # 探索热情值,会随时间递减
    
        while temp > final_temp:
            # 只要温度高于最终值,必定生成邻域解
            neighbor_solution = []
            for i in range(len(current_solution)):
                new_val = current_solution[i] + random.uniform(-1, 1) * (bounds[i][1] - bounds[i][0]) * 0.1 # 随机生成一组邻域解/新参数
                new_val = max(bounds[i][0], min(bounds[i][1], new_val)) # 规范一组新参数,确保新值在边界范围内
                neighbor_solution.append(new_val)
    
            neighbor_fitness = fitness_function(neighbor_solution)
            delta_fitness = neighbor_fitness - current_fitness # 计算新解与当前解的适应度差,本质上就是在比较新旧参数(也就是新旧解)的好坏
    
            if delta_fitness > 0 or random.random() < np.exp(delta_fitness / temp):
                # 如果 delta_fitness > 0 ,意味着邻域解的适应度值高于当前解,也就是邻域解更优,此时会直接接受邻域解
                # 如果 delta_fitness < 0 ,意味着邻域解的适应度值低于当前解,也就是邻域解更差,此时会以一定概率接受邻域解,概率与 delta_fitness 的大小成正比,即 delta_fitness 越大,接受邻域解的概率越大。
                current_solution = neighbor_solution
                current_fitness = neighbor_fitness
    
            if current_fitness > best_fitness:
                best_solution = current_solution
                best_fitness = current_fitness
    
            temp *= alpha
    
        return best_solution, best_fitness # 新函数simulated_annealing输出最优解与最优解的适应度值
    
    
    # 超参数范围
    bounds = [(50, 200), (10, 30), (2, 10), (1, 4)]  # n_estimators, max_depth, min_samples_split, min_samples_leaf
    
    # 模拟退火算法参数
    initial_temp = 100 # 初始温度
    final_temp = 0.1 # 终止温度
    alpha = 0.95 # 温度衰减系数
    
    # 初始化初始解
    initial_solution = [random.uniform(bounds[i][0], bounds[i][1]) for i in range(len(bounds))]
    
    start_time = time.time()
    best_params, best_fitness = simulated_annealing(initial_solution, bounds, initial_temp, final_temp, alpha)
    end_time = time.time()
    
    print(f"模拟退火算法优化耗时: {end_time - start_time:.4f} 秒")
    print("最佳参数: ", {
        'n_estimators': int(best_params[0]),
        'max_depth': int(best_params[1]),
        'min_samples_split': int(best_params[2]),
        'min_samples_leaf': int(best_params[3])
    })
    
    # 使用最佳参数的模型进行预测
    best_model = RandomForestClassifier(n_estimators=int(best_params[0]),
                                        max_depth=int(best_params[1]),
                                        min_samples_split=int(best_params[2]),
                                        min_samples_leaf=int(best_params[3]),
                                        random_state=42)
    best_model.fit(X_train, y_train)
    best_pred = best_model.predict(X_test)
    
    print("\n模拟退火算法优化后的随机森林 在测试集上的分类报告:")
    print(classification_report(y_test, best_pred))
    print("模拟退火算法优化后的随机森林 在测试集上的混淆矩阵:")
    print(confusion_matrix(y_test, best_pred))

    粒子群算法

    想象你在公园里和一群小伙伴的目标是找到全公园最甜的那棵苹果树。

    初始状态:随机撒网

  • 1.你们所有人(粒子)一开始蒙着眼睛,被随机扔到公园各个角落(随机初始位置)
  • 2.每个人手里有个小本子,用来记录自己找到过的最甜苹果的位置(个体最优解)
  • 3.公园广播会实时播报当前所有人找到的最甜苹果的位置(群体最优解)。
  • 找苹果的规则:边跑边交流,方向由三部分决定:

  • 1.惯性: 你本来跑的方向(比如你本来往东跑,会保持一点惯性继续往东)
  • 2.个体经验: 你记得自己之前找到过的好位置,会不自觉往那个方向偏。
  • 3.群体经验: 听说某个区域有人找到超甜的苹果,大家会一起往那个方向冲
  • 调整速度: 每次移动时综合这三个因素调整速度和方向(如60%惯性+20%自己经验+20%群体经验)

    边走边更新:

  • 1.如果你现在的位置苹果比以前记录的更甜,就更新自己小本子的位置。
  • 2.如果某人的苹果比广播里说的还甜,公园广播会立刻更新全群最优位置。
  • 3.最终结果:群体智慧爆发
  • 经过几轮边跑边交流,所有人会逐渐聚集到公园里苹果最甜的那棵树附近。即使一开始有人走错路,但通过不断分享信息,最终大家都能找到最优解!

    步骤类比

    1.定义寻宝规则(初始化优化目标)

    1. 定义参数范围:# 告诉小伙伴要找什么样的苹果树
    2. 树的数量范围=(50,200)
    3. 最大深度范围 =(5,30)
    4. 叶子样本范围 =(1,10)

    定义甜度检测函数(参数):验货员尝苹果流程

    1. 将参数转换为整数 ->(树的数量,深度,叶子样本)
    2. 用这些参数种一片苹果树
    3. 摘取苹果进行检测,计算甜度分数(F1值)
    4. 返回甜度的负值(因为要找更甜的)

    2.组织小伙伴开始寻宝(初始化粒子群)设置寻宝队参数:

    1. 小伙伴数量=20
    2. 最大寻宝轮次=30
    3. 惯性权重=0.6 # 保持原方向跑的倾向
    4. 个体学习率=1.5 # 相信自己经验的强度
    5. 集体学习率=1.5 # 相信广播的强度

    初始化所有小伙伴:

    1. 随机分配到公园各地 -> 初始位置
    2. 每人发空白小本子 -> 记录个人最佳
    3. 初始速度为0 -> 站在原地不动
    4. 收集所有初始位置甜度 -> 首次广播最佳位置

    3. 开始多轮寻宝(优化循环)
    for 每轮寻宝 in 总轮次:
    for 每个小伙伴 in 队伍:
    # 调整跑步方向(速度更新)

    1. 惯性方向 = 惯性权重 * 当前速度
    2. 个人倾向 = 个体学习率 * 随机数 * (小本子位置 – 当前位置)
    3. 集体倾向 = 集体学习率 * 随机数 * (广播位置 – 当前位置)
    4. 新速度 = 惯性方向 + 个人倾向 + 集体倾向

    移动脚步(位置更新),新位置 = 当前位置 + 新速度

    确保不跑出公园边界 -> 修正坐标

    # 评估新位置苹果

    当前甜度 = 甜度检测函数(新位置)

     # 更新记录(最优解更新)

    if 当前甜度 > 小本子记录:更新小本子: 位置和甜度

    if 当前甜度 > 广播甜度:更新全公园广播 -> 新最佳位置

    4. 宣布最终发现(输出结果)

    原文链接:https://blog.csdn.net/2503_91003121/article/details/147647065

    # --- 2. 粒子群优化算法优化随机森林 ---
    print("\n--- 2. 粒子群优化算法优化随机森林 (训练集 -> 测试集) ---")
    
    
    # 定义适应度函数,本质就是构建了一个函数实现 参数--> 评估指标的映射
    def fitness_function(params): 
        n_estimators, max_depth, min_samples_split, min_samples_leaf = params # 序列解包,允许你将一个可迭代对象(如列表、元组、字符串等)中的元素依次赋值给多个变量。
        model = RandomForestClassifier(n_estimators=int(n_estimators),
                                       max_depth=int(max_depth),
                                       min_samples_split=int(min_samples_split),
                                       min_samples_leaf=int(min_samples_leaf),
                                       random_state=42)
        model.fit(X_train, y_train)
        y_pred = model.predict(X_test)
        accuracy = accuracy_score(y_test, y_pred)
        return accuracy
    
    
    # 粒子群优化算法实现
    def pso(num_particles, num_iterations, c1, c2, w, bounds): # 粒子群优化算法核心函数
        # num_particles:粒子的数量,每个粒子代表一组参数组合,即算法中用于搜索最优解的个体数量。
        # num_iterations:迭代次数,算法运行的最大循环次数。
        # c1:认知学习因子,用于控制粒子向自身历史最佳位置移动的程度。
        # c2:社会学习因子,用于控制粒子向全局最佳位置移动的程度。
        # w:惯性权重,控制粒子的惯性,影响粒子在搜索空间中的移动速度和方向。
        # bounds:超参数的取值范围,是一个包含多个元组的列表,每个元组表示一个超参数的最小值和最大值。
    
        num_params = len(bounds) 
        particles = np.array([[random.uniform(bounds[i][0], bounds[i][1]) for i in range(num_params)] for _ in
                              range(num_particles)])
        velocities = np.array([[0] * num_params for _ in range(num_particles)])
        personal_best = particles.copy()
        personal_best_fitness = np.array([fitness_function(p) for p in particles]) # 可以理解为给每个粒子代表的超参数组合进行评分
        global_best_index = np.argmax(personal_best_fitness) # 找到评分最高的粒子的索引
        global_best = personal_best[global_best_index]
        global_best_fitness = personal_best_fitness[global_best_index]
    
        for _ in range(num_iterations):
            r1 = np.array([[random.random() for _ in range(num_params)] for _ in range(num_particles)]) # 生成一个与粒子数量和参数数量相同的随机数矩阵
            r2 = np.array([[random.random() for _ in range(num_params)] for _ in range(num_particles)])
    
            velocities = w * velocities + c1 * r1 * (personal_best - particles) + c2 * r2 * (global_best - particles) # 
            particles = particles + velocities # 新位置 = 当前位置 + 新速度
    
            for i in range(num_particles): # 确保粒子的位置在超参数的取值范围内
                for j in range(num_params):
                    if particles[i][j] < bounds[j][0]:
                        particles[i][j] = bounds[j][0]
                    elif particles[i][j] > bounds[j][1]:
                        particles[i][j] = bounds[j][1]
    
            fitness_values = np.array([fitness_function(p) for p in particles]) # 对每个粒子代表的超参数组合进行评分
            improved_indices = fitness_values > personal_best_fitness # 只有当找到更好的解/参数组合时才会更新这个记录
            personal_best[improved_indices] = particles[improved_indices] # 更新个体最佳位置
            personal_best_fitness[improved_indices] = fitness_values[improved_indices] # 更新个体的最佳参数组合评分
    
            current_best_index = np.argmax(personal_best_fitness)
            if personal_best_fitness[current_best_index] > global_best_fitness: # 更新全局最佳位置和适应度值
                global_best = personal_best[current_best_index] # 个体找到更高评分对应的参数组合后,才会更新到全局最优位置
                global_best_fitness = personal_best_fitness[current_best_index]
    
        return global_best, global_best_fitness
    
    
    # 超参数范围
    bounds = [(50, 200), (10, 30), (2, 10), (1, 4)]  # n_estimators, max_depth, min_samples_split, min_samples_leaf
    
    # 粒子群优化算法参数
    num_particles = 20   # num_particles:粒子的数量,每个粒子代表一组参数组合,即算法中用于搜索最优解的个体数量。
    num_iterations = 10  # num_iterations:迭代次数,算法运行的最大循环次数。
    c1 = 1.5             # c1:认知学习因子,用于控制粒子向自身历史最佳位置移动的程度。
    c2 = 1.5             # c2:社会学习因子,用于控制粒子向全局最佳位置移动的程度。
    w = 0.5              # w:惯性权重,控制粒子的惯性,影响粒子在搜索空间中的移动速度和方向。
    
    start_time = time.time()
    best_params, best_fitness = pso(num_particles, num_iterations, c1, c2, w, bounds)
    end_time = time.time()
    
    print(f"粒子群优化算法优化耗时: {end_time - start_time:.4f} 秒")
    print("最佳参数: ", {
        'n_estimators': int(best_params[0]),
       'max_depth': int(best_params[1]),
       'min_samples_split': int(best_params[2]),
       'min_samples_leaf': int(best_params[3])
    })
    
    # 使用最佳参数的模型进行预测
    best_model = RandomForestClassifier(n_estimators=int(best_params[0]),
                                        max_depth=int(best_params[1]),
                                        min_samples_split=int(best_params[2]),
                                        min_samples_leaf=int(best_params[3]),
                                        random_state=42)
    best_model.fit(X_train, y_train)
    best_pred = best_model.predict(X_test)
    
    print("\n粒子群优化算法优化后的随机森林 在测试集上的分类报告:")
    print(classification_report(y_test, best_pred))
    print("粒子群优化算法优化后的随机森林 在测试集上的混淆矩阵:")
    print(confusion_matrix(y_test, best_pred))
    

     

    作者:小喵喵生气气

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python基础学习打卡第12天(虫豸版)- Python60天挑战之旅

    发表回复