前言

各位伙伴们,Day 13 的学习旅程带我们进入了一个全新的高度!我们不再仅仅是使用现成的库函数,而是开始探索那些源于自然智慧、用于解决复杂优化问题的“启发式算法”。这些算法(如遗传算法、粒子群优化)听起来高深,但它们的思想却美妙而直观。

今天,我们将兵分两路:

  1. 练好内功:学习一个能让你的 Python 代码瞬间变得优雅简洁的“语法糖”——列表推导式
  2. 拓展视野:概览式地了解遗传算法 (GA)、粒子群优化 (PSO) 和模拟退火 (SA) 的核心思想,为未来的科研和工程应用(甚至是老师说的“写论文”)埋下伏笔。

最重要的是,今天我们将实践一种新的学习心法:在 AI 时代,理解思想、关注输入输出,比死记硬背复杂实现更重要!


一、列表推导式:Pythonic 编程的“语法糖” 🍬

在深入算法世界前,我们先来品尝一颗让代码更甜美的“语法糖”——列表推导式。它能用一行代码替代传统的多行循环,让代码更简洁、可读性更强。

1.1 基础用法:一行顶三行

需求:生成 [1, 4, 9, 16, 25]

传统写法:

squares = []
for x in range(1, 6):
    squares.append(x**2)
print(squares)
# [1, 4, 9, 16, 25]

列表推导式写法:

# 语法:[expression for item in iterable]
squares = [x**2 for x in range(1, 6)]
print(squares)
# [1, 4, 9, 16, 25]

是不是瞬间清爽了很多?

1.2 带 if 条件过滤

需求:生成 1到10 之间的所有偶数。

传统写法:

evens = []
for x in range(1, 11):
    if x % 2 == 0:
        evens.append(x)
print(evens)
# [2, 4, 6, 8, 10]

列表推导式写法:

# 语法:[expression for item in iterable if condition]
evens = [x for x in range(1, 11) if x % 2 == 0]
print(evens)
# [2, 4, 6, 8, 10]
1.3 嵌套循环:生成笛卡尔积

需求:生成 [1, 2][3, 4] 的所有元素组合。

传统写法:

combinations = []
for x in [1, 2]:
    for y in [3, 4]:
        combinations.append((x, y))
print(combinations)
# [(1, 3), (1, 4), (2, 3), (2, 4)]

列表推导式写法:

# 语法:[expression for item1 in iterable1 for item2 in iterable2]
combinations = [(x, y) for x in [1, 2] for y in [3, 4]]
print(combinations)
# [(1, 3), (1, 4), (2, 3), (2, 4)]
1.4 结合函数调用

需求:将列表中的所有单词转为大写。

words = ["apple", "banana", "cherry"]

# 列表推导式写法
upper_words = [word.upper() for word in words]
print(upper_words)
# ['APPLE', 'BANANA', 'CHERRY']

掌握列表推导式,是迈向 Python 高手的重要一步!


二、启发式算法:当调参遇上“大自然” 🌍

我们已经知道,模型调参就像在一个复杂的地形上寻找最高峰(最佳性能)。启发式算法就是一群受自然启发的“智能探险家”,它们用各自独特的策略来寻找这个最高点。

核心思想:这些算法都是优化器。我们的目标是找到一组超参数,让机器学习模型的评估指标(如准确率)最高。

在开始之前,我们先准备好数据和基准模型,以便衡量这些高级优化算法的效果。

点击展开:查看数据预处理与基准模型代码
# --- 0. 数据预处理与数据集划分 (与之前一致) ---
# 此处省略了详细的数据读取、编码、填充、划分代码
# 假设 X_train, X_test, y_train, y_test 已经准备就绪

# --- 1. 默认参数的随机森林 (作为基准) ---
import time
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix

print("--- 1. 默认参数随机森林 (基准模型) ---")
start_time = time.time()
rf_model = RandomForestClassifier(random_state=42)
rf_model.fit(X_train, y_train)
rf_pred = rf_model.predict(X_test)
end_time = time.time()

print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
print("\n默认随机森林在测试集上的分类报告:")
print(classification_report(y_test, rf_pred))
# 输出结果:
# 训练与预测耗时: 0.8383 秒
# 默认随机森林在测试集上的分类报告:
#               precision    recall  f1-score   support
#            0       0.77      0.97      0.86      1059
#            1       0.79      0.30      0.43       441
#     accuracy                           0.77      1500

接下来,让我们认识三位“探险家”。

2.1 遗传算法 (GA):物竞天择,适者生存 🧬

  • 灵感来源:达尔文的生物进化论。
  • 核心思想
    1. 种群 (Population):随机生成一堆超参数组合,每个组合都是一个“个体”。
    2. 适应度 (Fitness):用模型性能(如准确率)来评估每个“个体”的生存能力。
    3. 选择 (Selection):表现好的个体(高分)更容易被选中,进入下一代。
    4. 交叉 (Crossover):被选中的“父母”个体交换部分参数(基因),产生新的“后代”。
    5. 变异 (Mutation):“后代”的参数有小概率发生随机改变。
    6. 循环:新一代种群重复上述过程,一代代进化,最终找到适应环境的“超级个体”(最优参数)。
  • 感觉:像是在大范围“撒网”搜索,通过优胜劣汰和随机变动,逐步逼近最优解。
点击展开:查看遗传算法优化随机森林的 DEAP 代码
# --- 2. 遗传算法优化随机森林 ---
print("\n--- 2. 遗传算法优化随机森林 ---")
from deap import base, creator, tools, algorithms
import random

# (此处省略了DEAP框架的详细设置,包括定义个体、种群、评估函数、遗传操作等)
# 核心是定义了一个 evaluate 函数,输入一个体(参数组合),输出模型准确率

# 运行遗传算法...
# (此处省略了运行算法的循环代码)

# 结果展示
print(f"遗传算法优化耗时: 205.8067 秒")
print("最佳参数: {'n_estimators': 179, 'max_depth': 26, 'min_samples_split': 8, 'min_samples_leaf': 2}")
print("\n遗传算法优化后的分类报告:")
# ... (输出分类报告)
# precision    recall  f1-score   support
# 0       0.77      0.98      0.86      1059
# 1       0.84      0.29      0.43       441

2.2 粒子群优化 (PSO):鸟群觅食,信息共享 🐦

  • 灵感来源:鸟群或鱼群的集体觅食行为。
  • 核心思想
    1. 粒子 (Particle):每个超参数组合是一个在参数空间中“飞行”的粒子。
    2. 速度 (Velocity):每个粒子有自己的移动方向和速度。
    3. 个体最优 (pbest):每个粒子会记住自己飞过的历史最佳位置。
    4. 全局最优 (gbest):整个粒子群共享信息,所有粒子都知道当前整个群体发现的最佳位置。
    5. 更新:每个粒子根据自己的“个体经验 (pbest)”和“群体智慧 (gbest)”,并带一点惯性,来更新自己的速度和位置,飞向更有希望的区域。
  • 感觉:像是一群互相协作的探险家,既有自己的记忆,又听取团队的建议,集体高效地寻找目标。通常比遗传算法收敛更快。
点击展开:查看粒子群优化随机森林的代码
# --- 3. 粒子群优化随机森林 ---
print("\n--- 3. 粒子群优化随机森林 ---")

# (此处省略了PSO函数的具体实现,核心是 fitness_function 和 pso 循环)
# fitness_function 同样是输入参数组合,输出模型准确率

# 运行粒子群优化...
# (此处省略了调用 pso 函数的代码)

# 结果展示
print(f"粒子群优化耗时: 104.8761 秒")
print("最佳参数: {'n_estimators': 51, 'max_depth': 20, 'min_samples_split': 7, 'min_samples_leaf': 2}")
print("\n粒子群优化后的分类报告:")
# ... (输出分类报告)
# precision    recall  f1-score   support
# 0       0.77      0.97      0.86      1059
# 1       0.83      0.31      0.45       441

2.3 模拟退火 (SA):高温探索,低温收敛 🔥

  • 灵感来源:金属冶炼中的退火过程(加热后缓慢冷却,使分子排列到能量最低的稳定状态)。
  • 核心思想
    1. 初始状态:从一个随机的参数组合开始,设置一个很高的“温度”。
    2. 邻域搜索:在当前解附近随机找一个“新解”。
    3. 接受准则
      • 如果“新解”更好,直接接受。
      • 如果“新解”更差,以一定概率接受它。这个概率与“温度”和“差的程度”有关。在“高温”时,接受差解的概率更高,允许算法跳出局部最优的小山谷
    4. 降温:随着迭代,“温度”逐渐降低,算法接受差解的意愿也越来越低,变得“保守”,开始在已找到的优质区域内精细搜索。
  • 感觉:像一个初期“胆大冲动”、后期“沉稳保守”的探险家,擅长避免被小山丘(局部最优)迷惑,有更大机会找到真正的最高峰(全局最优)。
点击展开:查看模拟退火优化随机森林的代码
# --- 4. 模拟退火优化随机森林 ---
print("\n--- 4. 模拟退火优化随机森林 ---")

# (此处省略了模拟退火函数的具体实现,核心是 fitness_function 和 simulated_annealing 循环)
# fitness_function 同样是输入参数组合,输出模型准确率

# 运行模拟退火...
# (此处省略了调用 simulated_annealing 函数的代码)

# 结果展示
print(f"模拟退火算法优化耗时: 123.9574 秒")
print("最佳参数: {'n_estimators': 144, 'max_depth': 16, 'min_samples_split': 7, 'min_samples_leaf': 1}")
print("\n模拟退火优化后的分类报告:")
# ... (输出分类报告)
# precision    recall  f1-score   support
# 0       0.76      0.98      0.86      1059
# 1       0.84      0.28      0.42       441

三、总结与心得:拥抱 AI 时代的学习新范式

今天的学习带给我最大的震撼,不仅仅是这些算法本身,更是老师传递的一种学习思维的转变

  1. 思想 > 实现:面对遗传算法、PSO 等复杂的代码,很容易陷入每个参数、每个循环的细节中。但老师一针见血地指出:这些代码不具备复用性,搞懂了对学习其他方法帮助也有限。这让我意识到,在 AI 时代,我们的角色不是成为算法的“人肉编译器”,而是要成为算法的“指挥家”。

  2. 关注“接口”,而非“内脏”:我们应该重点关注:

    • 输入 (Input):这个算法需要我提供什么?(比如,参数范围 bounds,评估函数 fitness_function
    • 输出 (Output):它能给我返回什么?(比如,最佳参数 best_params,最佳得分 best_fitness
    • 适用场景 (Context):它擅长解决什么问题?(比如,参数空间巨大、不可导的优化问题)
      至于内部复杂的循环、交叉、变异逻辑,交给可靠的库或者 AI 去实现。我们只需理解其工作原理,然后正确地使用它。
  3. 启发式算法的价值:虽然我们的实验中,这些算法相比默认参数在 accuracy 上提升不明显(主要是因为 recall for class 1 依然很低,这是数据不平衡的锅),但它们在 precision for class 1 上都有所提升,并且找到了与默认参数完全不同的参数组合。这证明了它们强大的全局搜索能力,是贝叶斯优化、网格搜索之外,我们武器库中的又一利器。

  4. 从代码到思想的飞跃:今天的学习完美诠释了从“术”到“道”的过程。列表推导式是“术”,是具体的编码技巧;而启发式算法的学习方法,则是“道”,是更高维度的学习哲学。

感谢 @浙大疏锦行 老师带来的深刻一课,这不仅是关于算法的,更是关于如何在这个快速发展的时代高效学习的。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐