GBDT算法之泰坦尼克号案例
1 课程概览
本课使用GBDT完成泰坦尼克号生存预测案例。通过梯度提升树API和网格搜索调参,对比GBDT与其他算法的效果。
2 核心概念与定义
- GBDT:Gradient Boosting Decision Tree,梯度提升树。
- 负梯度:等于残差,真实值 - 预测值。
- GradientBoostingClassifier:GBDT分类器API。
3 算法与模型详解
3.1 GBDT构建流程
- 初始化弱学习器:采用所有目标值的均值作为预测值
- 计算负梯度:目标值 - 预测值 = 负梯度(残差)
- 该值作为第二个弱学习器的目标值
- 找最佳分隔点:依次计算每个分隔点的最小平方和
- 搭建第一个弱学习器
- 代入第二个弱学习器:计算预测值(以分隔点为界,目标值的均值)
- 迭代:重复直到达到指定学习器个数
- 最终输出:将所有弱学习器的输出结果组合起来
3.2 案例流程
- 读取数据
- 提取特征(Pclass、Age、Sex)
- 缺失值填充(Age用均值)
- One-Hot编码(Sex)
- 划分数据集
- 创建GBDT模型
- 网格搜索调参
- 评估模型
3.3 GBDT API
GradientBoostingClassifier()
3.4 网格搜索
GridSearchCV(
estimator,
param_grid,
cv
)
4 代码示例
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.ensemble import GradientBoostingClassifier
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']].copy()
y = data['Survived']
# 2.2 缺失值填充(Age用均值)
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. GBDT基本训练
def train_gbdt(X_train, X_test, y_train, y_test):
"""GBDT基本训练"""
print("\n=== GBDT基本训练 ===")
gbc = GradientBoostingClassifier(random_state=22)
gbc.fit(X_train, y_train)
y_pred = gbc.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print(f"准确率: {acc:.4f}")
return gbc, acc
# 5. 网格搜索调参
def grid_search(X_train, X_test, y_train, y_test):
"""网格搜索调参"""
print("\n=== 网格搜索调参 ===")
gbc = GradientBoostingClassifier(random_state=22)
param_grid = {
'n_estimators': [50, 100, 200],
'learning_rate': [0.01, 0.1, 0.2],
'max_depth': [3, 5, 7]
}
grid_search = GridSearchCV(
gbc,
param_grid,
cv=3,
n_jobs=-1
)
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
# 6. 主函数
def main():
"""主函数"""
print("=" * 50)
print("GBDT - 泰坦尼克号案例")
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. GBDT基本训练
gbc, gbc_acc = train_gbdt(X_train, X_test, y_train, y_test)
# 5. 网格搜索调参
best_model, best_acc = grid_search(X_train, X_test, y_train, y_test)
# 6. 对比
print("\n=== 对比 ===")
print(f"GBDT基本: {gbc_acc:.4f}")
print(f"GBDT调参后: {best_acc:.4f}")
# 7. 预测新样本
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()
输出示例:
==================================================
GBDT - 泰坦尼克号案例
==================================================
数据形状: (891, 12)
特征形状: (891, 4)
特征名称: ['Age' 'Pclass' 'Sex=female' 'Sex=male']
训练集: (712, 4)
测试集: (179, 4)
=== GBDT基本训练 ===
准确率: 0.8101
=== 网格搜索调参 ===
最优参数: {'learning_rate': 0.1, 'max_depth': 3, 'n_estimators': 200}
最优得分: 0.8230
测试集准确率: 0.8324
=== 对比 ===
GBDT基本: 0.8101
GBDT调参后: 0.8324
=== 预测新样本 ===
{'Pclass': 3, 'Age': 25.0, 'Sex': 'male'}: 未存活
{'Pclass': 1, 'Age': 30.0, 'Sex': 'female'}: 存活
{'Pclass': 2, 'Age': 35.0, 'Sex': 'male'}: 未存活
5 重难点与易错提醒
- ❗重点:GBDT通过拟合负梯度(残差)获取强学习器。
- ❗重点:初始化预测值 = 目标值的均值。
- ❗重点:每一轮的残差作为下一轮的目标值。
- ❗重点:最终结果是所有弱学习器输出之和。
- ⚠️易错:忘记copy()导致警告。
- ⚠️易错:网格搜索参数过多导致训练时间长。
- 💡深入理解:GBDT通过迭代优化残差,逐步逼近真实值。
6 课堂问答精选
Q: GBDT的预测值如何计算?
A:
- 初始化:所有目标值的均值
- 每一轮:以分隔点为界,目标值的均值作为该部分数据的预测值
- 最终:所有弱学习器输出结果相加
Q: GBDT和AdaBoost有什么区别?
A:
- AdaBoost:通过加权(预测对权重降低,预测错权重提升)
- GBDT:通过拟合残差(负梯度)
- GBDT使用CART回归树,AdaBoost使用CART分类树
7 本课小结
- GBDT流程:初始化(均值)→ 计算负梯度 → 找最佳分隔点 → 迭代。
- 泰坦尼克号案例:数据预处理 + GBDT + 网格搜索。
- 最终结果:所有弱学习器输出之和。
- 网格搜索:优化n_estimators、learning_rate、max_depth。
8 延伸思考与实践
- 实践:运行GBDT泰坦尼克号案例。
- 预习:XGBoost极限梯度提升树。
- 思考:GBDT为什么使用回归树?