Scikit-learn 1.3+ 决策树实战:泰坦尼克号生存预测准确率 0.82(附特征重要性分析)
当数据科学家面对结构化数据的分类问题时,决策树往往是工具箱中第一个被取出的利器。这种模仿人类决策过程的算法,以其直观的可解释性和接近人类思考方式的分支逻辑,在金融风控、医疗诊断等关键领域持续发光发热。本文将带您深入Scikit-learn 1.3+版本中的决策树实现,通过经典的泰坦尼克号数据集,演示如何构建准确率达82%的生存预测模型,并揭示哪些特征真正决定了乘客的命运。
1. 环境准备与数据加载
在开始建模之前,我们需要配置合适的Python环境并获取数据。建议使用Python 3.8+版本,并安装以下依赖库:
pip install scikit-learn==1.3.0 pandas numpy matplotlib graphviz泰坦尼克号数据集可以从多个来源获取,这里我们使用Kaggle提供的版本,它包含以下关键特征:
- pclass:船舱等级(1/2/3等舱)
- sex:乘客性别
- age:乘客年龄
- sibsp:兄弟姐妹/配偶数量
- parch:父母/子女数量
- fare:船票价格
- embarked:登船港口
- survived:生存状态(目标变量)
import pandas as pd from sklearn.model_selection import train_test_split # 加载数据 titanic = pd.read_csv('titanic.csv') print(f"数据集形状: {titanic.shape}") print("\n前5行数据:") print(titanic.head())执行后会显示类似如下的输出:
数据集形状: (891, 12) 前5行数据: PassengerId Survived Pclass ... Fare Cabin Embarked 0 1 0 3 ... 7.2500 NaN S 1 2 1 1 ... 71.2833 C85 C 2 3 1 3 ... 7.9250 NaN S 3 4 1 1 ... 53.1000 C123 S 4 5 0 3 ... 8.0500 NaN S2. 数据预处理实战技巧
原始数据往往包含缺失值和需要转换的类别特征。以下是关键预处理步骤:
2.1 缺失值处理策略
年龄字段约有20%的缺失值,我们采用基于其他特征的预测填充法:
from sklearn.experimental import enable_iterative_imputer from sklearn.impute import IterativeImputer # 选择用于预测年龄的特征 age_features = ['Pclass', 'SibSp', 'Parch', 'Fare'] # 使用随机森林回归填充年龄 imputer = IterativeImputer(max_iter=10, random_state=42) titanic['Age'] = imputer.fit_transform(titanic[age_features + ['Age']])[:, -1]2.2 特征工程创新点
除了原始特征,我们可以构造有预测力的新特征:
# 家庭规模 titanic['FamilySize'] = titanic['SibSp'] + titanic['Parch'] + 1 # 年龄分段 titanic['AgeGroup'] = pd.cut(titanic['Age'], bins=[0, 12, 18, 35, 60, 100], labels=['Child', 'Teen', 'Adult', 'MidAge', 'Senior']) # 票价等级 titanic['FareCategory'] = pd.qcut(titanic['Fare'], 4, labels=['Low', 'Mid', 'High', 'VIP'])2.3 类别特征编码
使用独热编码处理类别变量时需注意内存问题:
from sklearn.preprocessing import OneHotEncoder # 选择需要编码的特征 cat_features = ['Pclass', 'Sex', 'Embarked', 'AgeGroup', 'FareCategory'] # 稀疏矩阵格式节省内存 encoder = OneHotEncoder(sparse=True, handle_unknown='ignore') X_cat = encoder.fit_transform(titanic[cat_features])3. 决策树模型构建与调优
Scikit-learn的DecisionTreeClassifier在1.3版本中优化了计算效率,特别是对大型数据集的处理。
3.1 基础模型训练
from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import accuracy_score # 划分训练测试集 X_train, X_test, y_train, y_test = train_test_split( X_features, titanic['Survived'], test_size=0.2, random_state=42) # 初始化决策树 dt_clf = DecisionTreeClassifier( criterion='gini', max_depth=5, min_samples_split=20, random_state=42 ) # 训练模型 dt_clf.fit(X_train, y_train) # 评估 train_acc = accuracy_score(y_train, dt_clf.predict(X_train)) test_acc = accuracy_score(y_test, dt_clf.predict(X_test)) print(f"训练集准确率: {train_acc:.2%}") print(f"测试集准确率: {test_acc:.2%}")典型输出结果:
训练集准确率: 86.52% 测试集准确率: 82.12%3.2 超参数调优实战
使用GridSearchCV进行参数搜索时,重点关注这些关键参数:
from sklearn.model_selection import GridSearchCV param_grid = { 'max_depth': [3, 5, 7, None], 'min_samples_split': [10, 20, 30], 'min_samples_leaf': [1, 5, 10], 'max_features': ['sqrt', 'log2', None] } grid_search = GridSearchCV( DecisionTreeClassifier(random_state=42), param_grid, cv=5, scoring='accuracy', n_jobs=-1 ) grid_search.fit(X_train, y_train) print("最佳参数组合:", grid_search.best_params_) print("最佳交叉验证得分:", grid_search.best_score_)3.3 决策树可视化解析
安装graphviz后,可以导出决策树图形:
from sklearn.tree import export_graphviz import graphviz dot_data = export_graphviz( dt_clf, out_file=None, feature_names=feature_names, class_names=['Died', 'Survived'], filled=True, rounded=True, special_characters=True ) graph = graphviz.Source(dot_data) graph.render("titanic_decision_tree") # 保存为PDF决策树图形中,颜色深浅表示节点纯度,我们可以清晰看到:
- 首要分裂特征是性别(sex_female)
- 二等舱及以上乘客生存率更高
- 儿童和携带家人的乘客有生存优势
4. 模型解释与特征重要性
决策树最强大的优势在于其可解释性。Scikit-learn提供了两种特征重要性计算方法:
4.1 Gini重要性分析
import matplotlib.pyplot as plt # 获取特征重要性 importances = dt_clf.feature_importances_ indices = np.argsort(importances)[::-1] # 绘制重要性图表 plt.figure(figsize=(12, 6)) plt.title("特征重要性 (Gini)") plt.bar(range(X_train.shape[1]), importances[indices], align="center") plt.xticks(range(X_train.shape[1]), [feature_names[i] for i in indices], rotation=90) plt.xlim([-1, X_train.shape[1]]) plt.tight_layout() plt.show()4.2 Permutation重要性
这种方法通过打乱特征值观察模型性能下降程度计算重要性:
from sklearn.inspection import permutation_importance result = permutation_importance( dt_clf, X_test, y_test, n_repeats=10, random_state=42 ) sorted_idx = result.importances_mean.argsort()[::-1] plt.figure(figsize=(12, 6)) plt.boxplot( result.importances[sorted_idx].T, vert=False, labels=[feature_names[i] for i in sorted_idx] ) plt.title("Permutation重要性") plt.tight_layout() plt.show()两种方法通常显示一致的重要特征排序:
- 性别(女性更可能幸存)
- 船舱等级(头等舱优先)
- 年龄(儿童优先)
- 票价(高票价乘客优先)
5. 决策树的局限性与改进方案
虽然我们的模型达到了82%的准确率,但决策树仍有明显缺陷:
5.1 过拟合问题
通过观察学习曲线可以发现过拟合迹象:
from sklearn.model_selection import learning_curve train_sizes, train_scores, test_scores = learning_curve( dt_clf, X_features, titanic['Survived'], cv=5, train_sizes=np.linspace(0.1, 1.0, 10), scoring='accuracy') plt.plot(train_sizes, np.mean(train_scores, axis=1), label='训练得分') plt.plot(train_sizes, np.mean(test_scores, axis=1), label='交叉验证得分') plt.xlabel('训练样本数') plt.ylabel('准确率') plt.legend() plt.show()5.2 集成方法改进
使用随机森林可以显著提升性能:
from sklearn.ensemble import RandomForestClassifier rf_clf = RandomForestClassifier( n_estimators=100, max_depth=5, random_state=42 ) rf_clf.fit(X_train, y_train) rf_test_acc = accuracy_score(y_test, rf_clf.predict(X_test)) print(f"随机森林测试准确率: {rf_test_acc:.2%}")典型结果:
随机森林测试准确率: 84.36%5.3 业务规则提取
决策树可以转化为if-then规则,用于业务系统:
from sklearn.tree import _tree def tree_to_rules(tree, feature_names): tree_ = tree.tree_ feature_name = [ feature_names[i] if i != _tree.TREE_UNDEFINED else "undefined!" for i in tree_.feature ] def recurse(node, depth, rules): if tree_.feature[node] != _tree.TREE_UNDEFINED: name = feature_name[node] threshold = tree_.threshold[node] rules.append(f"如果 {name} ≤ {threshold:.2f}:") recurse(tree_.children_left[node], depth + 1, rules) rules.append("否则:") recurse(tree_.children_right[node], depth + 1, rules) else: rules.append(f"→ 预测为 {class_names[np.argmax(tree_.value[node])]}") rules = [] recurse(0, 1, rules) return rules rules = tree_to_rules(dt_clf, feature_names) print("\n".join(rules[:10])) # 打印前10条规则示例输出:
如果 sex_female ≤ 0.50: 如果 pclass_3 ≤ 0.50: → 预测为 Survived 否则: 如果 age ≤ 9.50: → 预测为 Survived 否则: 如果 fare ≤ 23.35: → 预测为 Died 否则: → 预测为 Survived 否则: 如果 age ≤ 3.50: → 预测为 Survived在实际项目中,这种白盒特性使得决策树成为需要解释性的场景(如金融风控、医疗诊断)的首选算法。虽然深度学习在某些领域表现更优,但决策树凭借其直观性和可解释性,仍然是数据科学家工具箱中不可或缺的利器。