机器学习基础¶
一句话说明¶
机器学习是让计算机从数据中自动找规律、做预测的技术。在生信中,它是从高维组学数据(如菌群丰度表)中筛选生物标志物、做疾病分类预测的核心工具。
核心概念(白话版)¶
1. 什么是机器学习¶
- 定义:机器学习(Machine Learning, ML)是人工智能的一个分支,核心思想是让计算机通过"看数据"自动学会规律,而不需要人类一条条写规则。
- 白话比方:就像你学打篮球——不是靠看说明书,而是靠反复投篮、根据进没进来调整姿势。计算机也一样,喂它大量数据(投篮经验),它自己调整内部参数(姿势),最终学会预测(投进)。
三大类型¶
| 类型 | 英文 | 白话解释 | 生信例子 |
|---|---|---|---|
| 监督学习 | Supervised Learning | 有标准答案的考试——给你题目和答案,让你学会做新题 | 用已知健康/T2D标签的菌群数据训练分类器 |
| 无监督学习 | Unsupervised Learning | 没有标准答案——让你自己把一堆东西分分类 | 对样本做聚类看有没有自然分群 |
| 强化学习 | Reinforcement Learning | 打游戏学习——做对了奖励,做错了惩罚,慢慢变强 | 生信中很少用,主要用在药物设计等 |
2. 监督学习常用算法¶
随机森林(Random Forest)¶
- 白话比方:你生病了去看诊,不是只找一个医生,而是同时找 500 个医生各自独立诊断,最后"投票表决"——多数医生说的结论就是最终结论。每个医生(决策树)可能有偏见,但 500 个人一起投票就很稳。
- 原理:
- 决策树(Decision Tree):像一棵倒着的树,每个节点问一个问题(比如"Prevotella 丰度 > 0.05 吗?"),根据回答往左走或往右走,最终到达叶子节点得出结论。
- 随机森林 = 很多棵决策树的集合:
- 每棵树只看"部分样本"(有放回随机抽样,叫 Bootstrap)
- 每个节点只考虑"部分特征"(随机选一部分菌属来做分裂判断)
- 最终预测 = 所有树投票取多数(分类)或取平均(回归)
- 这种"随机 + 集成"的方式让模型既不容易过拟合,又能捕捉复杂关系
- 生信应用:
- 疾病分类预测(如 T2D vs 健康人的菌群分类)
- 特征重要性排序(找出哪些菌属对分类最有贡献 = 候选标志物)
- 基因表达分类(肿瘤 vs 正常)
- 微生物组关联分析
- 优缺点:
| 优点 | 缺点 |
|---|---|
| 不容易过拟合(相比单棵决策树) | 模型是"黑盒",不如逻辑回归好解释因果 |
| 能处理高维数据(特征比样本多) | 样本极少时效果可能一般 |
| 自带特征重要性排序 | 对极度不平衡数据需要额外处理 |
| 不要求数据标准化 | 训练时间比简单模型长 |
| 能处理非线性关系和高维特征交互 | 预测结果不容易做因果解释 |
注意:sklearn 的
RandomForestClassifier不能直接处理缺失值(NaN 会报错),需要先做缺失值填充。R 的经典randomForest包同样不能处理 NA。能原生处理缺失值的是 R 的ranger包、XGBoost 和 LightGBM。
支持向量机(SVM, Support Vector Machine)¶
- 白话比方:在两类数据点之间画一条"最宽的分界线"。想象桌上有红球和蓝球,你要放一根尺子把它们分开——SVM 就是找那个让两边球离尺子都最远的摆法。
- 原理:找到一个超平面(hyperplane,你只需要理解为"把两堆数据分开的那条线/面"),使得两类样本到这个超平面的最小距离(margin,间隔)最大。用"核函数"(kernel)可以处理线性不可分的情况——线性不可分 = 画一条直线分不开。核函数相当于把数据"抛到高处",在高处就能用一个平面分开。
- 生信应用:基因表达谱分类、蛋白质功能预测、DNA 甲基化分析
- 优缺点:
| 优点 | 缺点 |
|---|---|
| 高维数据表现好 | 样本量大时训练很慢 |
| 核函数灵活 | 参数调优复杂(C、gamma) |
| 理论基础扎实 | 不直接给出概率,需要额外处理 |
逻辑回归(Logistic Regression)¶
- 白话比方:用一个 S 形曲线把"得分"转换成"概率"。比如你考试得了 70 分,逻辑回归告诉你"及格概率 85%"。它本质上是在算各个特征对结果的"加权投票"。
- 原理:对特征做线性组合得到一个分数,再用 sigmoid 函数(S 形曲线,不用记名字,只要知道它把任意数字"压"到 0-1 之间就行)把分数映射到 0-1 之间作为概率。如果概率 > 0.5 就预测为正类。
- 生信应用:风险预测(如患病概率)、GWAS 中的关联分析、简单的二分类基线模型
- 优缺点:
| 优点 | 缺点 |
|---|---|
| 简单快速,容易解释(系数=贡献度) | 只能学线性关系 |
| 直接输出概率 | 特征间有复杂交互时效果差 |
| 适合做基线模型对比 | 高维且特征相关时不稳定 |
3. 无监督学习常用算法¶
K-means 聚类¶
- 白话比方:你要把一堆没有标签的球分成 K 组,先随便放 K 个"中心点",然后每个球跑向离自己最近的中心,之后把中心挪到每组球的正中间,反复几轮直到稳定。
- 原理:
- 指定 K 个簇(cluster)的数量
- 随机初始化 K 个质心(centroid)
- 每个样本分配给最近的质心
- 重新计算每个簇的质心
- 重复 3-4 直到收敛
- 生信应用:样本分群(如把患者分成不同亚型)、基因表达模式聚类
- 优缺点:
| 优点 | 缺点 |
|---|---|
| 简单直观,速度快 | 必须预先指定 K |
| 适合大数据集 | 对初始质心敏感 |
| 结果容易解释 | 只能找"球形"簇,不能处理复杂形状 |
层次聚类(Hierarchical Clustering)¶
- 白话比方:像画家谱——先把最相似的两个人合成一个小家庭,再把最相似的两个家庭合成一个大家族,一层层往上合并,最终画出一棵"族谱树"(dendrogram,树状图)。
- 原理:
- 凝聚式(Agglomerative):自底向上,从每个样本单独一类开始,逐步合并最相似的两类
- 分裂式(Divisive):自顶向下,把所有样本当一类,逐步分裂
- 生信应用:样本聚类热图(heatmap)、物种进化关系推断、基因共表达模块发现
- 优缺点:
| 优点 | 缺点 |
|---|---|
| 不需要预先指定 K | 计算量随样本数增加会急剧增大,样本多了会非常慢 |
| 能产生树状图,信息更丰富 | 大样本量时很慢 |
| 对簇形状没有限制 | 一旦合并/分裂不可撤销 |
4. 模型评估¶
交叉验证(Cross Validation, CV)¶
- 白话解释:考试不能只考一次——你可能碰巧抽到会的题。交叉验证就是反复考多次,每次换一部分题当考卷,其他题拿来复习,最后取平均分才算你的真实水平。
- 常用方式:K 折交叉验证(K-Fold CV)——把数据分成 K 份,轮流拿 1 份当测试、其余 K-1 份当训练,重复 K 次取平均。
- 为什么要用:避免因为数据分割的偶然性(运气好/运气差)而高估或低估模型表现。样本量小的时候尤其重要。
- 分层交叉验证(Stratified K-Fold):保证每一折中正负样本比例和总体一致。在类别不平衡时必须用。
过拟合与欠拟合¶
- 过拟合(Overfitting):
- 白话比方:考试前把答案背下来了,原题全会,但换个说法就不会了。模型"记住了"训练数据的噪声,对新数据预测很差。
- 表现:训练集准确率 99%,测试集 60%。
-
解决:增加数据量、减少模型复杂度、正则化、交叉验证、early stopping。
-
欠拟合(Underfitting):
- 白话比方:上课没听懂,考什么都不会。模型太简单,连训练数据的规律都没学到。
- 表现:训练集和测试集准确率都很低。
- 解决:用更复杂的模型、增加特征、减少正则化。
评估指标¶
| 指标 | 英文 | 白话解释 | 公式 |
|---|---|---|---|
| 准确率 | Accuracy | 判对的占总数的比例。"100个人判对了多少个" | (TP+TN)/(TP+TN+FP+FN) |
| 精确率 | Precision | 你说"有病"的人里面,真的有病的比例。"抓的人里有几个是真犯人" | TP/(TP+FP) |
| 召回率 | Recall/Sensitivity | 真正有病的人里面,你找出来了多少。"10个犯人你抓到了几个" | TP/(TP+FN) |
| F1 分数 | F1-Score | 精确率和召回率的"调和平均"。两个都高 F1 才高 | 2PR/(P+R) |
| AUC-ROC | AUC-ROC | 不管阈值怎么设,模型区分正负样本的整体能力。0.5=瞎猜,1.0=完美 | ROC曲线下面积 |
| 特异度 | Specificity | 真正健康的人中,你正确判为健康的比例 | TN/(TN+FP) |
注意:样本不平衡时不能只看 Accuracy!比如 100 人中 95 个健康、5 个有病,全猜"健康"准确率就 95% 但完全没用。此时应该看 AUC、F1、PR-AUC。
混淆矩阵(Confusion Matrix)¶
- 白话解释:一个 2x2 的表格,记录模型把每类样本判对了多少、判错了多少。
预测为正(有病) 预测为负(健康)
实际为正(有病) TP FN
实际为负(健康) FP TN
- TP(True Positive):有病,判对了——"真阳性"
- FP(False Positive):没病,误判为有病——"假阳性"(误报)
- FN(False Negative):有病,漏判了——"假阴性"(漏报)
- TN(True Negative):没病,判对了——"真阴性"
5. 特征选择与特征工程¶
为什么要做特征选择¶
- 高维数据(如 245 个菌属特征)中很多是噪声,会干扰模型
- 减少特征可以降低过拟合风险
- 让结果更可解释("这 10 个菌属最关键"比"这 245 个菌属一起用"更有意义)
- 减少训练时间
常用方法¶
| 方法 | 白话解释 | 适用场景 |
|---|---|---|
| 随机森林特征重要性 | 看哪个特征被用得最多、对预测贡献最大 | 通用,非线性 |
| Permutation Importance | 随机打乱某个特征的值,看模型准确率掉多少——掉得越多说明这个特征越重要 | 更可靠,你的 T2D 项目就用了这个 |
| LASSO——一种自动"砍"掉不重要特征的方法 | 自动把不重要的特征系数压到 0 | 线性模型 |
| Prevalence 过滤 | 只保留在足够多样本中出现的特征(过滤掉太稀有的菌) | 微生物组数据预处理 |
| 方差过滤 | 去掉所有样本中值都一样的特征(零方差=无信息) | 通用预处理 |
6. 数据预处理¶
标准化(Standardization)vs 归一化(Normalization)¶
| 方法 | 操作 | 结果 | 适用算法 |
|---|---|---|---|
| 标准化 | (x - 均值) / 标准差 | 均值=0, 标准差=1 | SVM、逻辑回归、PCA |
| 归一化 | (x - min) / (max - min) | 值映射到 [0,1] | 神经网络、K-means |
随机森林不需要标准化或归一化,因为它是基于"大小比较"做分裂的,值的缩放不影响排序。
缺失值处理¶
- 直接删除(样本少时不推荐)
- 均值/中位数填充
- 在微生物组中:丰度为 0 通常表示"未检测到",不一定要当缺失值处理
类别不平衡问题¶
- 问题:正负样本数量差很多(如 T2D 78 例 vs 健康 104 例)
- 常用方法:
class_weight='balanced':让模型对少数类给更高的关注- SMOTE:人工生成少数类的"合成样本"
- 下采样:减少多数类样本
- 评估时用 AUC / F1 / PR-AUC 而不是 Accuracy
常用工具/命令¶
| 工具/库 | 语言 | 用途 | 安装方式 |
|---|---|---|---|
| scikit-learn | Python | 机器学习核心框架(分类、回归、聚类、评估) | pip install scikit-learn |
| pandas | Python | 数据读取和处理 | pip install pandas |
| numpy | Python | 数值计算 | pip install numpy |
| matplotlib | Python | 画图(ROC、特征重要性等) | pip install matplotlib |
| seaborn | Python | 更美观的统计图 | pip install seaborn |
| XGBoost | Python | 梯度提升树,常作为 RF 的对比模型 | pip install xgboost |
| imbalanced-learn | Python | 处理类别不平衡(SMOTE等) | pip install imbalanced-learn |
| joblib | Python | 模型保存与加载 | sklearn 自带 |
实操代码¶
随机森林分类完整示例¶
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
随机森林分类完整示例 —— 从数据加载到模型评估
使用 sklearn 内置的乳腺癌数据集(二分类,类似 T2D 项目场景)
"""
import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer # 加载内置数据集(乳腺癌,569样本×30特征)
from sklearn.model_selection import StratifiedKFold, cross_val_predict # 分层交叉验证
from sklearn.ensemble import RandomForestClassifier # 随机森林分类器
from sklearn.metrics import (
roc_auc_score, # AUC 评估
classification_report, # 分类报告(精确率、召回率、F1)
confusion_matrix, # 混淆矩阵
)
import matplotlib.pyplot as plt # 画图
# ========== 第1步:加载数据 ==========
data = load_breast_cancer() # 加载数据
X = pd.DataFrame(data.data, columns=data.feature_names) # 特征矩阵(569×30)
y = pd.Series(data.target, name="label") # 标签(0=恶性, 1=良性)
print(f"样本数: {X.shape[0]}, 特征数: {X.shape[1]}")
print(f"标签分布:\n{y.value_counts()}") # 查看正负样本比例
# ========== 第2步:定义模型和交叉验证策略 ==========
# 5折分层交叉验证——保证每折中正负样本比例一致
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
# 随机森林模型配置
rf_model = RandomForestClassifier(
n_estimators=500, # 500棵决策树
max_depth=None, # 树的深度不限制(让每棵树充分生长)
min_samples_split=2, # 节点最少2个样本才继续分裂
max_features="sqrt", # 每次分裂时随机选 sqrt(n_features) 个特征
class_weight="balanced", # 自动根据类别频率调整权重(处理不平衡)
random_state=42, # 随机种子,保证可复现
n_jobs=-1, # 用所有CPU核心并行训练
)
# ========== 第3步:交叉验证获取 OOF 预测 ==========
# cross_val_predict: 每个样本只在作为测试集时被预测一次(Out-of-Fold)
oof_proba = cross_val_predict(
rf_model, X, y,
cv=cv,
method="predict_proba", # 获取概率预测
n_jobs=-1,
)[:, 1] # 取第二列,即正类的概率值(第一列是负类概率)
# ========== 第4步:模型评估 ==========
# AUC-ROC
oof_auc = roc_auc_score(y, oof_proba)
print(f"\nOOF AUC-ROC: {oof_auc:.4f}")
# 用 0.5 作为阈值转换为 0/1 预测
oof_pred = (oof_proba >= 0.5).astype(int)
# 分类报告
print("\n分类报告:")
print(classification_report(y, oof_pred, target_names=["恶性(0)", "良性(1)"]))
# 混淆矩阵
cm = confusion_matrix(y, oof_pred)
print(f"混淆矩阵:\n{cm}")
# 解读: 行=真实标签, 列=预测标签
# [[TN, FP], [FN, TP]]
交叉验证示例¶
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
交叉验证示例 —— 展示 5 折 CV 每折的性能指标
"""
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import StratifiedKFold, cross_val_score
import numpy as np
# 加载数据
X, y = load_breast_cancer(return_X_y=True)
# 定义模型
rf = RandomForestClassifier(n_estimators=300, random_state=42, n_jobs=-1)
# 定义 5 折分层交叉验证
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
# 用 AUC 作为评分指标进行交叉验证
scores = cross_val_score(rf, X, y, cv=cv, scoring="roc_auc")
# 打印每折的 AUC 和汇总
print("各折 AUC:")
for i, score in enumerate(scores, 1):
print(f" Fold {i}: {score:.4f}")
print(f"\n平均 AUC: {scores.mean():.4f} (+/- {scores.std():.4f})")
# 白话解读: 如果 std > 0.05,说明模型稳定性不够,可能数据太少或模型过拟合
# 参考: std < 0.02 很稳定; 0.02-0.05 基本可以; > 0.05 需要关注
特征重要性可视化¶
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
特征重要性可视化 —— 使用 Permutation Importance
(你的 T2D 项目就用了这个方法来找候选核心菌属)
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.inspection import permutation_importance # permutation importance
from sklearn.model_selection import train_test_split
# ========== 加载并拆分数据 ==========
data = load_breast_cancer()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = data.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y # stratify 保证分层
)
# ========== 训练模型 ==========
rf = RandomForestClassifier(n_estimators=500, random_state=42, n_jobs=-1)
rf.fit(X_train, y_train)
# ========== 计算 Permutation Importance ==========
# 原理:随机打乱某个特征的值,看模型在测试集上的性能掉多少
# 掉得越多 = 这个特征越重要
perm_result = permutation_importance(
rf, X_test, y_test,
n_repeats=10, # 每个特征重复打乱10次取平均
random_state=42,
scoring="roc_auc", # 用 AUC 衡量性能变化
n_jobs=-1,
)
# 整理为 DataFrame
importance_df = pd.DataFrame({
"feature": X.columns,
"importance_mean": perm_result.importances_mean,
"importance_std": perm_result.importances_std,
}).sort_values("importance_mean", ascending=False)
# ========== 可视化 Top 15 ==========
top_n = 15
top_df = importance_df.head(top_n).iloc[::-1] # 倒序方便画横向条形图
plt.figure(figsize=(10, 8))
plt.barh(range(top_n), top_df["importance_mean"], xerr=top_df["importance_std"])
plt.yticks(range(top_n), top_df["feature"])
plt.xlabel("Permutation Importance (AUC drop)")
plt.title(f"Top {top_n} Features by Permutation Importance")
plt.tight_layout()
plt.savefig("feature_importance.png", dpi=150)
plt.show()
print("Top 5 most important features:")
print(importance_df.head(5).to_string(index=False))
和你项目的关联¶
你的 T2D 项目具体做了什么¶
根据你的毕业论文项目(train_rf_prjna686835_thesis.py),整体流程如下:
- 数据来源:PRJNA686835 数据集,从 GMrepo 获取的公开肠道微生物组数据(属水平丰度矩阵)
- 任务:Healthy vs T2D 二分类(健康 104 例,T2D 78 例,共 182 个样本)
- 特征处理:
- 原始 245 个属特征
- Prevalence 过滤(出现率 < 5% 的属被移除)
- 零方差过滤
- 无效特征移除(未知菌属)
- 最终保留约 134 个特征
log1p变换(对丰度取 log(1+x),压缩极端值)- 模型:RandomForestClassifier
- 外层:5 折分层交叉验证(StratifiedKFold)
- 内层:3 折 + RandomizedSearchCV(12 次随机搜索调参)
- 参数搜索范围:n_estimators=[200,300,500,800]、max_depth=[None,5,8,12]等
- class_weight="balanced" / "balanced_subsample"(处理轻度不平衡)
- 特征选择:Permutation Importance(在测试折上计算,重复 10 次取平均)
- 评估指标:
- OOF AUC = 0.5163(接近随机水平 0.5,说明区分能力有限)
- OOF AP = 0.4874
- 默认阈值 0.5 混淆矩阵:[[80,24],[55,23]]
- 结果解读:
- 模型预测性能有限,接近随机水平
- 但 Permutation Importance 排序出了 Anaerobutyricum、Prevotella 等候选菌属
- 定位为"探索性分析",候选菌属作为后续验证的线索
关键数字(面试必记)¶
- 样本量:182(Healthy 104 / T2D 78)
- 原始特征:245 属 -> 过滤后 134 属
- 交叉验证:5折外层 + 3折内层
- OOF AUC:0.5163
- 候选核心菌属:Anaerobutyricum、Evtepia、Prevotella、Dysosmobacter 等
面试怎么答¶
Q1: 解释一下随机森林的原理¶
A: "随机森林是一种集成学习方法。它的核心思想是'三个臭皮匠赛过诸葛亮'——训练很多棵决策树,每棵树只看部分样本和部分特征,最后投票表决。具体来说有两个随机:第一,每棵树用 Bootstrap 方式随机抽一部分样本来训练;第二,每个节点分裂时只随机选一部分特征来比较。这两个随机降低了模型方差,让整体不容易过拟合。最终预测就是所有树投票取多数。在我的项目中用了 200-800 棵树,用 StratifiedKFold 来评估。"
Q2: 什么是过拟合?怎么避免?¶
A: "过拟合就是模型把训练数据的噪声也'背'下来了,在训练集上表现好但在新数据上表现差。就像考试背答案,原题全会但换个说法就不行了。避免过拟合常用的方法有:一、交叉验证——让模型在不同数据划分上都表现好才算好;二、控制模型复杂度——比如限制树的深度、增加最小叶节点样本数;三、集成方法——随机森林本身就是通过多棵树平均来降低方差;四、正则化——比如 LASSO 对特征系数做惩罚。我的项目用了嵌套交叉验证:外层 5 折评估真实性能,内层 3 折做参数调优,严格防止信息泄漏。"
Q3: 你的项目中为什么选择随机森林?¶
A: "选随机森林有几个原因:第一,我的数据是属水平丰度表,特征维度高(245个属)、样本量相对小(182例),随机森林在这种高维小样本场景下比较稳健,不容易过拟合;第二,随机森林自带特征重要性排序,我可以直接用 Permutation Importance 找出对分类贡献最大的菌属作为候选标志物;第三,它对数据预处理要求低,不需要标准化,对缺失值也有一定容忍度;第四,作为本科论文,方法不宜过于复杂,随机森林是成熟、被广泛认可的方法。当然,最终 AUC 只有 0.52 左右,说明属水平数据在这个数据集上区分能力有限,这也是诚实的结论。面试时不要回避数字,但要紧跟解释原因和你学到了什么。"
Q4: 交叉验证是什么?为什么要用?¶
A: "交叉验证是把数据分成 K 份,轮流拿 1 份做测试、K-1 份做训练,重复 K 次后取平均作为模型评估结果。为什么要用?因为样本量有限的时候,如果只做一次 train/test split,结果受数据分割的偶然性影响很大——可能碰巧分到'简单'的测试集就高估了模型。交叉验证相当于考多次试取平均,结果更可靠。另外在我的项目中用了'分层'交叉验证,保证每折里 T2D 和健康人的比例和总体一致,避免某一折正好没有 T2D 样本的极端情况。"
Q5: AUC-ROC 曲线怎么解读?¶
A: "ROC 曲线的横轴是假阳性率(FPR),纵轴是真阳性率(TPR),它展示了在不同分类阈值下模型的表现。AUC 就是这条曲线下面的面积。AUC=0.5 表示模型和随机猜一样没用;AUC=1.0 表示完美分类。一般 0.7-0.8 算可以接受,0.8-0.9 算比较好。我的项目 OOF AUC = 0.52,说明模型整体区分能力接近随机水平。但这并不意味着没有价值——通过 Permutation Importance 我们仍然能找到一些有相对区分力的候选菌属,作为后续深入研究的线索。"
Q6: 你的模型效果怎么样?怎么评估的?¶
A: "说实话,模型效果有限。OOF AUC 约 0.52,接近随机水平。评估方式是 5 折分层交叉验证 + 内层 3 折参数搜索的嵌套设计,确保评估结果不受调参过拟合的影响。除了 AUC,我还看了 Average Precision(0.49)、不同阈值下的混淆矩阵、F1 分数和平衡准确率。效果不好的原因可能有:一、属水平丰度数据本身分辨率不够,种水平或功能层面可能更有信息量;二、样本量只有 182 例,统计力不足;三、T2D 是复杂疾病,单纯菌群丰度可能不够。但作为探索性分析,能找到候选菌属线索就是有价值的贡献。"
延伸阅读¶
- scikit-learn 官方文档 - Ensemble Methods:https://scikit-learn.org/stable/modules/ensemble.html
- 最权威的随机森林和梯度提升实现文档,含代码示例
- StatQuest with Josh Starmer (YouTube):搜索 "StatQuest Random Forest"
- 用动画讲解 ML 概念,非常适合入门,有英文字幕
- 《Pattern Recognition and Machine Learning》Bishop (2006)
- 机器学习经典教材,适合想深入理论的同学(有中文翻译版)