随机森林API之泰坦尼克号案例
1 课程概览
本课使用随机森林API完成泰坦尼克号生存预测案例。对比单一决策树和随机森林的效果,并通过交叉验证和网格搜索优化参数。
2 核心概念与定义
- 随机森林:RandomForestClassifier,Bagging思想的集成学习。
- 单一决策树:DecisionTreeClassifier,作为对比基准。
- 网格搜索:GridSearchCV,寻找最优参数。
- 交叉验证:CV折数,评估模型稳定性。
3 算法与模型详解
3.1 案例流程
- 加载数据
- 数据预处理
- 提取特征(Pclass、Age、Sex)
- 缺失值填充(Age列)
- One-Hot编码(Sex列)
- 划分训练集和测试集
- 单一决策树训练和评估
- 随机森林训练和评估
- 网格搜索调参
3.2 数据预处理
特征列:
- Pclass:船舱等级
- Age:年龄(有缺失,需填充)
- Sex:性别(字符串,需One-Hot编码)
处理步骤:
- 提取特征和标签
- Age列缺失值填充(平均值)
- Sex列One-Hot编码
3.3 模型对比
单一决策树:
DecisionTreeClassifier()
随机森林:
RandomForestClassifier(max_depth=6, random_state=22)
预期结果:随机森林评分 > 单一决策树
3.4 网格搜索调参
参数列表:
param_grid = {
'n_estimators': [40, 50, 60, 70], # 树的数量
'max_depth': [2, 4, 6, 8, 10] # 最大深度
}
交叉验证:CV折数(如3折)
注意:
- 参数组合多,训练时间长
- n_estimators=70 + max_depth=5 + CV=3 → 训练次数很多
3.5 集成学习总结
集成学习:多个弱学习器组合成强学习器
Bagging思想:
- 有放回的随机抽样
- 平权投票
- 并行执行
- 代表:随机森林
Boosting思想:
- 每次使用全部样本
- 加权投票(预测正确权重降低,预测错误权重增加)
- 串行执行
- 代表:AdaBoost、GBDT、XGBoost
3.6 随机森林特点
弱学习器:
- 每个弱学习器都是CART树
- 必须是二叉树
核心操作:
- 有放回的随机抽样
- 平权投票
- 并行执行
4 代码示例
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.feature_extraction import DictVectorizer
# 1. 加载数据
def load_data():
"""加载数据"""
data = pd.read_csv('data/train.csv')
print(f"数据形状: {data.shape}")
return data
# 2. 数据预处理
def preprocess_data(data):
"""数据预处理"""
# 2.1 提取特征和标签
X = data[['Pclass', 'Age', 'Sex']]
y = data['Survived']
# 2.2 缺失值填充(Age列用平均值)
X = X.copy()
X['Age'] = X['Age'].fillna(X['Age'].mean())
# 2.3 One-Hot编码(Sex列)
X_dict = X.to_dict(orient='records')
transfer = DictVectorizer(sparse=False)
X_new = transfer.fit_transform(X_dict)
print(f"特征形状: {X_new.shape}")
print(f"特征名称: {transfer.get_feature_names_out()}")
return X_new, y, transfer
# 3. 划分数据集
def split_data(X, y):
"""划分训练集和测试集"""
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=22
)
print(f"训练集: {X_train.shape}")
print(f"测试集: {X_test.shape}")
return X_train, X_test, y_train, y_test
# 4. 单一决策树
def train_decision_tree(X_train, X_test, y_train, y_test):
"""单一决策树"""
print("\n=== 单一决策树 ===")
dt = DecisionTreeClassifier(random_state=22)
dt.fit(X_train, y_train)
y_pred = dt.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print(f"准确率: {acc:.4f}")
return dt, acc
# 5. 随机森林
def train_random_forest(X_train, X_test, y_train, y_test):
"""随机森林"""
print("\n=== 随机森林 ===")
rf = RandomForestClassifier(
max_depth=6,
random_state=22
)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print(f"准确率: {acc:.4f}")
return rf, acc
# 6. 网格搜索调参
def grid_search(X_train, X_test, y_train, y_test):
"""网格搜索调参"""
print("\n=== 网格搜索调参 ===")
rf = RandomForestClassifier(random_state=22)
# 参数列表
param_grid = {
'n_estimators': [40, 50, 60, 70],
'max_depth': [2, 4, 6, 8, 10]
}
# 网格搜索
grid_search = GridSearchCV(
rf,
param_grid,
cv=3, # 3折交叉验证
n_jobs=-1 # 使用所有CPU
)
grid_search.fit(X_train, y_train)
# 最优参数
print(f"最优参数: {grid_search.best_params_}")
print(f"最优得分: {grid_search.best_score_:.4f}")
# 最优模型评估
best_model = grid_search.best_estimator_
y_pred = best_model.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print(f"测试集准确率: {acc:.4f}")
return best_model, acc
# 7. 主函数
def main():
"""主函数"""
print("=" * 50)
print("随机森林 - 泰坦尼克号案例")
print("=" * 50)
# 1. 加载数据
data = load_data()
# 2. 数据预处理
X, y, transfer = preprocess_data(data)
# 3. 划分数据集
X_train, X_test, y_train, y_test = split_data(X, y)
# 4. 单一决策树
dt, dt_acc = train_decision_tree(X_train, X_test, y_train, y_test)
# 5. 随机森林
rf, rf_acc = train_random_forest(X_train, X_test, y_train, y_test)
# 6. 网格搜索调参
best_model, best_acc = grid_search(X_train, X_test, y_train, y_test)
# 7. 对比
print("\n=== 对比 ===")
print(f"单一决策树: {dt_acc:.4f}")
print(f"随机森林: {rf_acc:.4f}")
print(f"网格搜索后: {best_acc:.4f}")
# 8. 预测新样本
print("\n=== 预测新样本 ===")
samples = [
{'Pclass': 3, 'Age': 25.0, 'Sex': 'male'},
{'Pclass': 1, 'Age': 30.0, 'Sex': 'female'},
{'Pclass': 2, 'Age': 35.0, 'Sex': 'male'}
]
X_new = transfer.transform(samples)
predictions = best_model.predict(X_new)
for sample, pred in zip(samples, predictions):
status = '存活' if pred == 1 else '未存活'
print(f"{sample}: {status}")
if __name__ == '__main__':
main()
输出示例:
==================================================
随机森林 - 泰坦尼克号案例
==================================================
数据形状: (891, 12)
特征形状: (891, 4)
特征名称: ['Age' 'Pclass' 'Sex=female' 'Sex=male']
训练集: (712, 4)
测试集: (179, 4)
=== 单一决策树 ===
准确率: 0.7989
=== 随机森林 ===
准确率: 0.8212
=== 网格搜索调参 ===
最优参数: {'max_depth': 8, 'n_estimators': 60}
最优得分: 0.8202
测试集准确率: 0.8268
=== 对比 ===
单一决策树: 0.7989
随机森林: 0.8212
网格搜索后: 0.8268
=== 预测新样本 ===
{'Pclass': 3, 'Age': 25.0, 'Sex': 'male'}: 未存活
{'Pclass': 1, 'Age': 30.0, 'Sex': 'female'}: 存活
{'Pclass': 2, 'Age': 35.0, 'Sex': 'male'}: 未存活
5 重难点与易错提醒
- ❗重点:随机森林效果通常优于单一决策树。
- ❗重点:网格搜索参数组合多,训练时间长。
- ❗重点:n_jobs=-1使用所有CPU加速。
- ❗重点:CV是交叉验证折数。
- ⚠️易错:参数组合过多导致训练时间过长。
- ⚠️易错:忘记设置random_state导致结果不可复现。
- 💡深入理解:网格搜索通过交叉验证找最优参数。
6 课堂问答精选
Q: 随机森林和单一决策树哪个效果更好?
A: 正常情况下,随机森林的评分比单一决策树好一些,但不会好到夸张的程度(如单一决策树70%,随机森林可能80%多,不会直接到98%)。随机森林通过集成多个弱学习器,降低了过拟合风险。
Q: 网格搜索的训练时间为什么很长?
A: 网格搜索需要遍历所有参数组合。例如n_estimators有4个值,max_depth有5个值,CV=3折,则训练次数 = 4 × 5 × 3 = 60次。每次都要训练一个随机森林模型,所以时间很长。可以通过n_jobs=-1使用多核CPU加速。
7 本课小结
- 数据预处理:Age填充、Sex的One-Hot编码。
- 单一决策树:作为基准对比。
- 随机森林:通常优于单一决策树。
- 网格搜索:寻找最优参数(n_estimators、max_depth)。
- 交叉验证:CV折数评估模型稳定性。
8 延伸思考与实践
- 实践:运行泰坦尼克号随机森林案例。
- 预习:Boosting算法(AdaBoost、GBDT)。
- 思考:如何平衡网格搜索的精度和时间?