第六节:决策树------让模型自动发现力学失效阈值
本节摘要
前面两节学习的线性回归与正则化回归,主要通过数学公式描述输入参数和力学响应之间的整体关系。但裂纹扩展、接触状态变化和材料失效往往具有明显的临界特征。
本节以裂纹长度与J积分数据为案例,学习决策树如何通过一系列条件判断,自动发现力学响应中的关键阈值,并分别完成连续响应预测和失效风险分类。

一、本节学习目标
完成本节后,你将能够:
-
理解决策树的节点、分支和叶节点;
-
了解CART算法的基本划分思想;
-
区分回归树和分类树;
-
使用回归树预测J积分;
-
使用分类树识别裂纹风险;
-
从树结构中读取工程判断规则;
-
使用树深度和叶节点样本数控制过拟合;
-
正确理解决策树的特征重要性。
二、为什么力学问题适合使用决策树?
许多工程问题并不表现为简单的线性关系。
例如:
-
裂纹较短时,J积分增长缓慢;
-
裂纹超过一定长度后,J积分快速增大;
-
接触压力达到某一水平后,接触状态发生变化;
-
应力超过屈服强度后,材料进入塑性阶段;
-
Courant数超过限制后,CFD计算可能发散。
这类问题常常包含"如果......那么......"的判断逻辑:
如果裂纹长度小于某个值,结构处于低风险状态;如果裂纹继续增大,则需要结合载荷判断是否进入临界状态。
决策树正是通过这种分层判断建立模型。
三、决策树的基本结构
决策树由三类节点组成:
-
根节点:第一次划分全部样本;
-
内部节点:继续对样本进行判断;
-
叶节点:给出最终预测结果。

图6-1 裂纹风险的决策树判断流程
一条决策路径可能写成:
且:
那么模型判断结构处于低风险区域。
树模型的优势是判断规则可以直接阅读,不需要把模型当成完全无法解释的"黑箱"。
四、CART算法在做什么?
CART是Classification and Regression Tree的缩写,即分类与回归树。
它的基本过程是:
-
选择一个候选特征;
-
尝试多个候选阈值;
-
将样本分成左右两个子集;
-
计算划分后的不纯度或误差;
-
选择效果最好的特征和阈值;
-
在子节点中重复以上过程。
决策树每次只进行二叉划分:
或者:
其中j为第
个特征,
为划分阈值。
五、分类树如何选择划分条件?
分类树常使用基尼不纯度:
其中表示节点中第
类样本所占的比例。
假设一个节点中有10个样本:
-
5个安全;
-
5个临界。
则:
0.5
如果一个节点中10个样本全部属于安全类:
因此:
-
基尼不纯度越大,类别越混杂;
-
基尼不纯度越小,节点越纯;
-
表示节点中只有一个类别。
决策树倾向于选择能够使子节点更加纯净的划分条件。
六、回归树如何选择划分条件?
回归树的输出是连续数值,例如:
-
位移;
-
应力;
-
温度;
-
J积分;
-
疲劳寿命。
回归树通常使用均方误差评价节点内部的离散程度:
每个叶节点的预测值通常是该节点所有训练样本的平均值:
因此,回归树的预测曲线通常不是光滑曲线,而是阶梯形状。
七、建立裂纹长度---J积分数据集
假设通过Abaqus参数化计算,得到以下裂纹长度和J积分结果。
import numpy as np
import pandas as pd
crack_length = np.array([
1, 2, 3, 4, 5, 6, 7, 8, 9
], dtype=float)
j_integral = np.array([
15, 22, 31, 43, 60,
85, 118, 160, 215
], dtype=float)
data = pd.DataFrame({
"裂纹长度_mm": crack_length,
"J积分_N每mm": j_integral
})
print(data.to_string(index=False))
预期输出
裂纹长度_mm J积分_N每mm
1.0 15.0
2.0 22.0
3.0 31.0
4.0 43.0
5.0 60.0
6.0 85.0
7.0 118.0
8.0 160.0
9.0 215.0
可以看到,裂纹较短时J积分增长相对缓慢;随着裂纹增大,其增长速度明显加快。
八、训练J积分回归树
from sklearn.tree import DecisionTreeRegressor
X = data[["裂纹长度_mm"]]
y = data["J积分_N每mm"]
regression_tree = DecisionTreeRegressor(
max_depth=3,
min_samples_leaf=1,
random_state=42
)
regression_tree.fit(X, y)
new_cases = pd.DataFrame({
"裂纹长度_mm": [2.5, 5.5, 8.5]
})
prediction = regression_tree.predict(
new_cases
)
for crack, value in zip(
new_cases["裂纹长度_mm"],
prediction
):
print(
f"裂纹长度={crack:.1f} mm,"
f"预测J积分={value:.1f} N/mm"
)
预期输出
裂纹长度=2.5 mm,预测J积分=18.5 N/mm
裂纹长度=5.5 mm,预测J积分=60.0 N/mm
裂纹长度=8.5 mm,预测J积分=160.0 N/mm
模型不会像多项式那样输出连续变化的光滑函数,而是先判断新样本落入哪个叶节点,再使用该叶节点的平均值作为预测结果。
九、绘制回归树预测结果
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = [
"Microsoft YaHei",
"SimHei"
]
plt.rcParams["axes.unicode_minus"] = False
x_curve = np.linspace(
1.0, 9.0, 400
).reshape(-1, 1)
x_curve_frame = pd.DataFrame(
x_curve,
columns=["裂纹长度_mm"]
)
y_curve = regression_tree.predict(
x_curve_frame
)
plt.scatter(
crack_length,
j_integral,
s=70,
color="#1769aa",
label="仿真样本"
)
plt.plot(
x_curve,
y_curve,
color="#f28e2b",
linewidth=2.8,
label="回归树预测"
)
plt.xlabel("裂纹长度 a(mm)")
plt.ylabel("J积分(N/mm)")
plt.title("回归树对J积分的阶梯式预测")
plt.grid(alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
预期绘图结果
-
蓝色圆点表示有限元仿真数据;
-
橙色阶梯线表示回归树预测;
-
每个平台对应一个叶节点;
-
阶梯发生变化的位置就是树模型发现的划分阈值。

图6-2 J积分的回归树预测结果
十、把连续响应转化为风险分类
假设工程上规定:
为安全状态,而:
进入临界状态。
data["风险等级"] = np.where(
data["J积分_N每mm"] >= 100,
"临界",
"安全"
)
print(
data[
["裂纹长度_mm", "风险等级"]
].to_string(index=False)
)
预期输出
裂纹长度_mm 风险等级
1.0 安全
2.0 安全
3.0 安全
4.0 安全
5.0 安全
6.0 安全
7.0 临界
8.0 临界
9.0 临界
十一、训练裂纹风险分类树
from sklearn.tree import (
DecisionTreeClassifier,
export_text
)
classification_tree = DecisionTreeClassifier(
max_depth=2,
criterion="gini",
random_state=42
)
classification_tree.fit(
X,
data["风险等级"]
)
rules = export_text(
classification_tree,
feature_names=["裂纹长度_mm"]
)
print(rules)
预期输出
|--- 裂纹长度_mm <= 6.50
| |--- class: 安全
|--- 裂纹长度_mm > 6.50
| |--- class: 临界
模型自动发现的关键阈值为:
这不是说真实结构一定会在处突然失效,而是表示在当前样本和风险定义下,这个阈值最能区分安全与临界样本。
十二、预测新的裂纹风险
risk_cases = pd.DataFrame({
"裂纹长度_mm": [4.5, 6.2, 7.5]
})
risk_prediction = classification_tree.predict(
risk_cases
)
for crack, risk in zip(
risk_cases["裂纹长度_mm"],
risk_prediction
):
print(
f"裂纹长度={crack:.1f} mm,"
f"预测状态={risk}"
)
预期输出
裂纹长度=4.5 mm,预测状态=安全
裂纹长度=6.2 mm,预测状态=安全
裂纹长度=7.5 mm,预测状态=临界
分类结果应结合安全系数、材料断裂韧度和适用规范解释,不能直接替代工程安全判定。
十三、树深度与过拟合
max_depth控制决策树最多可以生长多少层。
树太浅
-
规则较少;
-
容易解释;
-
可能遗漏重要的非线性变化;
-
容易欠拟合。
树太深
-
可以记住大量训练样本;
-
训练误差很低;
-
阈值数量过多;
-
对数据扰动敏感;
-
容易过拟合。
例如:
for depth in [1, 2, 3, 8]:
model = DecisionTreeRegressor(
max_depth=depth,
random_state=42
)
model.fit(X, y)
score = model.score(X, y)
print(
f"max_depth={depth},"
f"训练集R²={score:.4f}"
)
预期现象
随着树深度增加,训练集通常不断提高。但训练集表现提高,并不意味着新工况预测一定更可靠。
十四、控制决策树复杂度的参数
1. max_depth
限制树的最大深度。
2. min_samples_split
规定一个节点至少包含多少样本才允许继续分裂。
3. min_samples_leaf
规定每个叶节点至少保留多少样本。
4. max_leaf_nodes
限制叶节点总数。
5. ccp_alpha
通过代价复杂度剪枝删除贡献较小的分支。
工程小样本数据中,可以优先尝试:
DecisionTreeRegressor(
max_depth=3,
min_samples_leaf=3,
random_state=42
)
这样可以避免模型为个别异常样本建立专门分支。
十五、特征重要性
如果模型包含多个输入:
可以查看特征重要性:
importance = pd.Series(
regression_tree.feature_importances_,
index=X.columns
).sort_values(ascending=False)
print(importance)
当前案例只有裂纹长度一个特征,因此预期输出为:
裂纹长度_mm 1.0
dtype: float64
特征重要性表示该变量对降低节点误差的贡献,但不代表严格的因果关系。
连续变量、取值较多的变量还可能更容易获得较高的重要性,因此后续最好结合置换重要性或SHAP进行验证。
十六、决策树的优点与局限
主要优点
-
不要求输入与输出满足线性关系;
-
不需要进行特征标准化;
-
可以处理明显的阈值效应;
-
分类与回归都能使用;
-
判断路径容易解释;
-
能够处理特征之间的交互。
主要局限
-
单棵树容易过拟合;
-
数据轻微变化可能改变树结构;
-
回归结果呈阶梯状,不够光滑;
-
外推能力较弱;
-
深树的规则可能变得复杂;
-
特征重要性可能存在偏差。
因此,决策树通常还是随机森林、梯度提升树和XGBoost等集成算法的基础组件。
十七、不能把数据阈值直接当成物理定律
分类树得到:
它只在以下条件下成立:
-
当前材料;
-
当前载荷范围;
-
当前几何尺寸;
-
当前边界条件;
-
当前J积分临界值;
-
当前有限元建模方法。
如果载荷、材料或结构尺寸改变,阈值也可能改变。
因此,更严谨的表达应当是:
在本数据集覆盖的工况范围内,裂纹长度约为6.5 mm时,样本的风险类别发生明显分离。
十八、本节练习
基础练习
分别设置:
max_depth = 1
max_depth = 2
max_depth = 3
max_depth = None
观察树结构和阶梯预测曲线的变化。
进阶练习
增加载荷特征,建立:
并检查树模型优先使用裂纹长度还是载荷进行划分。
工程挑战
将风险划分为三级:
-
:安全;
-
:预警;
-
:临界。
训练多分类决策树,并将每条路径改写成工程判断规则。
十九、本节小结
本节完成了两个决策树模型:
以及:
决策树的核心价值不只是预测结果,还在于自动发现数据中的关键划分条件:
但必须记住:
下一节将进入Bagging与随机森林,学习如何组合多棵不同的决策树,降低单棵树的不稳定性,并量化载荷、几何和材料参数对力学响应的贡献。