python学习DAY12打卡

启发式算法

超参数调整专题2

  1. 三种启发式算法的示例代码:遗传算法、粒子群算法、退火算法
  2. 学习优化算法的思路(避免浪费无效时间)

今天以自由探索的思路为主,尝试检索资料、视频、文档,用尽可能简短但是清晰的语言看是否能说清楚这三种算法每种算法的实现逻辑,帮助更深入的理解。

启发式算法(Heuristic Algorithm)是一种“经验法则”式的求解方法,用近似、快速、可接受的策略,在合理时间内找到问题的“足够好”的解,而非追求理论上绝对最优的解

1. 这些启发式算法都是优化器。你的目标是找到一组超参数,让你的机器学习模型在某个指标(比如验证集准确率)上表现最好。

2. 这个过程就像在一个复杂的地形(参数空间)上寻找最高峰(最佳性能)。

3. 启发式算法就是一群聪明的“探险家”,它们用不同的策略(模仿自然、物理现象等)来寻找这个最高峰,而不需要知道地形每一处的精确梯度(导数)。

核心思想可概括为三点:
  1. 牺牲最优性,换取效率
    传统算法(如暴力枚举)可能耗时指数级,而启发式算法通过“智能猜测”快速逼近解,适合NP难问题(如旅行商问题、排班优化)。

  2. 模仿自然或人类经验
    例如:

    • 遗传算法模仿生物进化(优胜劣汰、交叉变异);

    • 蚁群算法模拟蚂蚁觅食的信息素路径;

    • 模拟退火借鉴金属退火的“接受劣解”机制,避免陷入局部最优。

  3. 迭代改进+随机探索
    通过“试错-反馈-调整”循环逐步优化解,同时引入随机性防止过早收敛到局部最优(如遗传算法的突变操作)。

总结:启发式算法是“聪明地偷懒”,用直觉和经验在复杂问题中快速找到“性价比最高”的答案。

遗传算法

遗传算法(Genetic Algorithm,GA)是启发式算法里最经典、最易懂也最易编程实现的一种,它把“解”当成“个体”,把“优化”当成“进化”用于解决优化和搜索问题。它基于达尔文的“自然选择”和“遗传学”原理,通过模拟种群中个体的优胜劣汰和基因的交叉、变异等机制,逐步逼近问题的最优解。

  1. 先生成一大群随机解(种群);

  2. 让解之间“交配”(交叉)并“突变”(变异);

  3. 用“适者生存”的法则淘汰差的解;

  4. 反复迭代,直到时间或质量满足要求。

———— 实现四步曲 ————

  1. 编码(Encoding)
    把问题的解变成“染色体”——通常是二进制串、整数数组或浮点数组。

  2. 初始化(Initialization)
    随机生成 N 个染色体作为第 0 代种群。

  3. 进化循环(Evolution Loop)
    3.1 计算适应度(Fitness):评价每个染色体的好坏。
    3.2 选择(Selection):按“好解多生、差解少生”的原则挑父母。常用轮盘赌或锦标赛选择。
    3.3 交叉(Crossover):父母染色体按一定概率交换片段,产生后代。
    3.4 变异(Mutation):对后代按小概率随机翻转某几位,保持多样性。
    3.5 环境选择:用精英保留或代沟策略决定下一代种群。

  4. 终止(Termination)
    达到最大代数或连续若干代无改进即停,输出最佳个体并解码成实际解。

用遗传算法“进化”出最舒适的一杯手冲咖啡配方

背景

你想每天冲一杯最好喝的手冲咖啡,但不确定 水温、粉水比、研磨度、萃取时间 四个参数的最佳组合。于是用遗传算法来“自动调参”。

1. 编码(把配方变成“基因”)

用 4 个整数分别代表 4 个参数,合起来是一条 16 位二进制染色体:

  • 水温:0000~1111 → 80°C~96°C(每单位 1°C)

  • 粉水比:0000~1111 → 1:10~1:25(每单位 1g 水)

  • 研磨度:0000~1111 → 20~35格(每单位 1 格)

  • 萃取时间:0000~1111 → 90s~240s(每单位 10s)

例:染色体 0101 1001 0011 1010
水温 85°C,粉水比 1:19,研磨度 27格,萃取时间 200s

2. 初始化

随机冲 10 杯不同参数的咖啡,组成第 0 代“种群”。

3. 适应度(打分)

你亲自品尝,按 0~10 分给每杯打分(香味、酸苦平衡、醇厚度)。分数就是适应度。

4. 进化循环(以一代为例)

  • 选择:高分配方更有可能被选中做“父母”。

  • 交叉:父母染色体随机交叉互换一段,比如交换“研磨度”部分。

  • 变异:随机改 1~2 位二进制,比如把水温 85°C 改成 86°C。

  • 新一代:冲 10 杯新配方,重新打分。

5. 终止

冲 5 代后,若平均分不再提升,停止。
最终染色体如 0110 1010 0011 1001
水温 86°C,粉水比 1:20,研磨度 27格,萃取时间 190s,你喝后打出 9.5 分,成为“黄金配方”。

总结

把咖啡参数当基因,让好喝的“基因”多繁殖、变异,几轮后就能“进化”出你的专属完美手冲。

遗传算法术语 vs 手冲咖啡优化例子
遗传算法术语 手冲咖啡优化例子
个体(染色体) 一整组冲煮参数(水温+粉水比+研磨度+萃取时间)
基因 单一参数,例如“水温”
适应度 你亲口品尝后给出的 0–10 分
选择 只留下得分高的配方继续“繁殖”
交叉 把高分配方的部分参数互换,例如 A 的水温与 B 的研磨度组合
变异 随机把某个参数微调 1°C、5 秒或 1 格研磨

代码实现:

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.metrics import classification_report, confusion_matrix
import warnings
warnings.filterwarnings("ignore")
import time
from deap import base, creator, tools, algorithms # DEAP是一个用于遗传算法和进化计算的Python库
import random
import numpy as np
 
 
 
# --- 2. 遗传算法优化随机森林 ---
print("\n--- 2. 遗传算法优化随机森林 (训练集 -> 测试集) ---")
 
# 定义适应度函数和个体类型
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)
 
# 定义超参数范围
n_estimators_range = (50, 200)
max_depth_range = (10, 30)
min_samples_split_range = (2, 10)
min_samples_leaf_range = (1, 4)
 
# 初始化工具盒
toolbox = base.Toolbox()
 
# 定义基因生成器
toolbox.register("attr_n_estimators", random.randint, *n_estimators_range)
toolbox.register("attr_max_depth", random.randint, *max_depth_range)
toolbox.register("attr_min_samples_split", random.randint, *min_samples_split_range)
toolbox.register("attr_min_samples_leaf", random.randint, *min_samples_leaf_range)
 
# 定义个体生成器
toolbox.register("individual", tools.initCycle, creator.Individual,
                 (toolbox.attr_n_estimators, toolbox.attr_max_depth,
                  toolbox.attr_min_samples_split, toolbox.attr_min_samples_leaf), n=1)
 
# 定义种群生成器
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
 
# 定义评估函数
def evaluate(individual):
    n_estimators, max_depth, min_samples_split, min_samples_leaf = individual
    model = RandomForestClassifier(n_estimators=n_estimators,
                                   max_depth=max_depth,
                                   min_samples_split=min_samples_split,
                                   min_samples_leaf=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,
 
# 注册评估函数
toolbox.register("evaluate", evaluate)
 
# 注册遗传操作
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutUniformInt, low=[n_estimators_range[0], max_depth_range[0],
                                                     min_samples_split_range[0], min_samples_leaf_range[0]],
                 up=[n_estimators_range[1], max_depth_range[1],
                     min_samples_split_range[1], min_samples_leaf_range[1]], indpb=0.1)
toolbox.register("select", tools.selTournament, tournsize=3)
 
# 初始化种群
pop = toolbox.population(n=20)
 
# 遗传算法参数
NGEN = 10
CXPB = 0.5
MUTPB = 0.2
 
start_time = time.time()
# 运行遗传算法
for gen in range(NGEN):
    offspring = algorithms.varAnd(pop, toolbox, cxpb=CXPB, mutpb=MUTPB)
    fits = toolbox.map(toolbox.evaluate, offspring)
    for fit, ind in zip(fits, offspring):
        ind.fitness.values = fit
    pop = toolbox.select(offspring, k=len(pop))
 
end_time = time.time()
 
# 找到最优个体
best_ind = tools.selBest(pop, k=1)[0]
best_n_estimators, best_max_depth, best_min_samples_split, best_min_samples_leaf = best_ind
 
print(f"遗传算法优化耗时: {end_time - start_time:.4f} 秒")
print("最佳参数: ", {
    'n_estimators': best_n_estimators,
    'max_depth': best_max_depth,
    'min_samples_split': best_min_samples_split,
    'min_samples_leaf': best_min_samples_leaf
})
 
# 使用最佳参数的模型进行预测
best_model = RandomForestClassifier(n_estimators=best_n_estimators,
                                    max_depth=best_max_depth,
                                    min_samples_split=best_min_samples_split,
                                    min_samples_leaf=best_min_samples_leaf,
                                    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))

@浙大疏锦行

你可能感兴趣的:(python学习打卡,学习)