☰
python的先进制造技术工业场景模拟第四十篇:加载3D打印工艺数据,遍历层厚,填充率组合,寻找抗拉强度最优工艺方案。
2026/10/3 6:13:12 网站建设 项目流程

周四下午,增材制造试制间。

"这批 PA12 功能件,要挂到工装夹具上受力,"工艺员小宋拿着拉伸试样报告,"层厚 0.1、填充 30%,拉出来 38MPa;换 0.2 层厚填充 50%,掉到 31MPa。现在就是拿工艺卡挨个试,试一组烧半天,还不知道是不是真最优。"

我点开他导出的 3D 打印工艺日志。

"这表里有什么?"小宋问。

"每条是打印参数+实测抗拉强度:层厚、填充率、打印温度、速度、光栅角、后处理,"我指着屏幕,"但它就是实验记录本,没做组合寻优。现在靠老师傅经验定层厚填充,比如'受力件就填密点',可有时候 0.12mm+45% 反而比 0.1mm+60% 强,因为层间结合和内部孔隙是博弈的。"

"我就想干一件事,"小宋说,"把层厚×填充率当搜索空间,用历史数据建模型,自动遍历组合,找出抗拉强度最高的那组,同时别让打印时间爆掉,出个帕累托前沿给我。"

"比如层厚 0.12mm、填充 45%、光栅±45°、后处理蒸汽抛光,模型预测 46.2MPa,比现工艺高 21%,打印时间只多 9%,"我接话,"再画个层厚-填充热力图,用 networkx 把'参数-强度'影响路径连起来,接数字孪生做工艺推荐。"

"对,"小宋点头,"还想看不同层厚下填充率敏感度曲线,别只给一个点,给一条可工艺落地的带。"

"用 pandas 读工艺数据,numpy 做网格遍历与张量组合,scipy 做响应面拟合与置信区间,scikit-learn 建回归模型对照预测强度,matplotlib 画热力图+帕累托前沿+敏感度曲线,networkx 建参数影响网,"我开工程,"数据自包含,合成一批 FDM 工艺数据,下载就能跑。"

敲了行原型:

# 强度 = f(层厚, 填充率, 温度, 光栅角) + 层间结合惩罚项

grid = np.meshgrid(layer_grid, infill_grid)

strength = model.predict(np.c_[grid[0].ravel(), grid[1].ravel(), ...])

# 帕累托: 强度↑ vs 打印时间↓

"完整版 OOP 封好,"我说,"加载器、工艺网格器、响应面模型器、帕累托求解器、影响网、出图器,输出最优工艺包 + 6图 + 报告,存 results/。"

小宋凑近看:"那以后看报告:最优 0.12mm/45%填充,预测 46.2MPa;帕累托前沿 8 组可选项;层厚>0.15 后强度陡降;影响网里'层厚→层间结合→强度'边最粗;工艺卡直接挂推荐组合+置信区间。"

"对,"我接话,"工艺不是试出来的,是带物理约束算出来的最优解。数字孪生里挂工艺推荐引擎,这套就是增材工艺大脑。"

一、实际应用场景(真实痛点)

场景设定:FDM/工业级增材制造试制阶段,功能件需满足抗拉强度指标,工艺参数(层厚、填充率、温度、光栅角、后处理)靠经验组合试错,实验成本高、周期长,且层间结合与孔隙率存在博弈关系。需基于历史工艺数据,构建层厚×填充率组合空间→抗拉强度预测+多目标寻优程序,输出最优工艺包及帕累托前沿,兼顾强度与打印效率。

现场原话(叙事化):

"不是我们不会打样,"小宋说,"是会打但打不出最优。层厚调细强度上去,可时间翻倍;填充加密也上去,可孔隙没少多少还重。老师傅说'受力件填密点',结果 60% 填充比 45% 只强 0.8MPa,时间多 25%,不划算。"

"还有层间结合的事,"小宋补充,"层厚一超 0.15,不管填多密,Z向强度都掉,因为层间接触面积小了。想让程序把这种非线性拐弯也学进去,别给我线性外推。"

核心矛盾:"工艺记录表 + 人工试错" 与 "层厚×填充率组合遍历 + 响应面模型 + 强度/时间帕累托寻优 + 可落地工艺包" 之间的断层。

二、痛点分析(映射到滨州职业学院《先进制造技术》课程模型)

《先进制造技术》模块 本篇痛点对应

增材制造(3D打印)技术:层厚、填充率、光栅策略、层间结合、孔隙率、后处理 层厚×填充率组合寻优

先进制造技术基础:材料力学性能、抗拉强度、精度与可靠性 强度预测+置信区间

FMS与先进生产管理:工艺效率、单件节拍 强度vs打印时间帕累托

智能制造与数字孪生:增材工艺数字镜像 工艺推荐引擎底座

先进制造新模式:数据驱动工艺寻优 从试错→模型寻优

一句话总结:我们需要一个"3D打印工艺数据→抗拉强度最优工艺寻优程序",用

"pandas" 读工艺日志,

"numpy" 做层厚×填充率网格遍历,

"scipy" 做响应面拟合与置信带,

"scikit-learn" 建回归模型对照,

"matplotlib" 画热力图/帕累托前沿/敏感度曲线,

"networkx" 建参数影响网,实现从"经验试错"到"组合空间寻优 + 帕累托工艺包 + 可下发工艺卡"。

三、核心逻辑讲解(大白话)

3.1 问题本质:把3D打印想成"和面做千层饼"

把 FDM 打印想成做千层饼:

* 层厚 = 每层饼皮多厚(薄了结合好但慢,厚了快但易分层)

* 填充率 = 饼里夹多少馅(多了结实但重且慢,少了空)

* 层间结合 = 两层皮粘得牢不牢(层厚一大就粘不牢)

* 孔隙 = 馅里的气泡(填充不合理反而多)

* 抗拉强度 = 这饼能吊多重的钩子

* 打印时间 = 做这张饼要多久

* 人工试错 = 做十张饼尝十次

* 模型寻优 = 先算好哪张饼最扛拉,再做那一张

* 帕累托前沿 = 给一排选择:最扛拉的、最省时的、折中的

* 影响网 = 看清楚是层厚还是填充在主导强度

3.2 业务逻辑 → 代码映射

导入3D打印工艺数据

│

▼ ProcessLoader (pandas)

读取 CSV:

layer_mm, infill_pct, nozzle_temp, speed, raster_deg,

post_process, print_time_min, tensile_MPa

清洗异常值, 标记材料/后处理

│

▼ ProcessGrid (numpy)

组合遍历:

层厚网格 [0.08,0.10,0.12,0.15,0.20]

填充率网格 [20,30,40,50,60,70]

笛卡尔积 -> 全组合矩阵

含光栅角/温度默认中值填充

│

▼ ResponseModeler (sklearn + scipy)

强度预测:

LinearRegression # 响应面基线

RandomForestRegressor # 非线性(层厚拐点)

GradientBoosting # 对照

scipy.optimize.curve_fit 做二次响应面参照

输出预测强度 + 预测方差(置信带)

│

▼ ParetoSolver (numpy)

多目标寻优:

目标1: 抗拉强度最大

目标2: 打印时间最小

求解帕累托前沿(非支配解)

│

▼ SensitivityAnalyzer (numpy/scipy)

敏感度:

固定其他, 扫层厚看强度斜率

扫填充率看边际收益拐点

│

▼ ParamInfluenceGraph (networkx)

参数影响网:

节点=参数/中间量(层间结合)/强度

边权=模型特征重要性或偏依赖贡献

│

▼ AmVisualizer (matplotlib)

可视化:

1. 层厚×填充率 强度热力图

2. 帕累托前沿(强度-时间散点)

3. 层厚敏感度曲线(含拐点标注)

4. 填充率边际收益曲线

5. 模型对照散点(预测vs实测)

6. 参数影响网

│

▼ SyntheticAMGenerator (numpy)

合成数据:

FDM PA12近似, 含层厚拐点惩罚

含孔隙-填充饱和效应

3.3 为什么不能只看"填密点就强"

视角 问题

固定层厚0.1+填密 时间爆炸,边际收益递减

只看强度 忽略打印节拍,落地难

层厚×填充网格+响应面 捕捉非线性拐点

帕累托前沿 给工艺选型空间

影响网 说清物理主导因子

3.4 优化前后对比

维度 现工艺(0.1/30%) 本程序推荐

层厚/填充 0.10mm / 30% 0.12mm / 45%

预测抗拉强度 38MPa 46.2MPa (+21%)

打印时间 基准 +9%

层厚>0.15处理 仍按经验用 模型标红禁区

输出 单点工艺 帕累托8组+置信区间

可下发 工艺员手填 工艺卡自动生成

四、OOP 代码实现

4.1 项目结构

am_strength_optimizer/

├── am_strength_optimizer/

│ ├── __init__.py

│ ├── process_loader.py # 工艺数据加载

│ ├── process_grid.py # 层厚×填充网格(numpy)

│ ├── response_modeler.py # 强度预测模型(sklearn+scipy)

│ ├── pareto_solver.py # 帕累托前沿(numpy)

│ ├── sensitivity.py # 敏感度分析

│ ├── influence_graph.py # 参数影响网(networkx)

│ ├── visualizer.py # 可视化

│ └── synthetic_data.py # 合成FDM数据

├── tests/

│ ├── __init__.py

│ └── test_am_strength.py

├── results/

│ ├── strength_heatmap.png

│ ├── pareto_front.png

│ ├── layer_sensitivity.png

│ ├── infill_marginal.png

│ ├── model_compare.png

│ ├── param_graph.png

│ ├── best_process.csv

│ ├── pareto_set.csv

│ ├── grid_predictions.csv

│ └ optimize_report.txt

└── run_am_strength.py

4.2 核心源码

<details>

<summary></summary>

"""3D打印工艺数据加载器"""

import pandas as pd

from pathlib import Path

from typing import Optional

class ProcessLoader:

"""读取FDM工艺日志CSV"""

def __init__(self, filepath: str = "am_process.csv",

encoding: str = "utf-8"):

self.filepath = Path(filepath)

self.encoding = encoding

def load(self) -> pd.DataFrame:

if not self.filepath.exists():

raise FileNotFoundError(f"文件不存在: {self.filepath}")

df = pd.read_csv(self.filepath, encoding=self.encoding)

req = ["layer_mm", "infill_pct", "tensile_MPa"]

miss = [c for c in req if c not in df.columns]

if miss:

raise ValueError(f"缺少必要列: {miss}")

# 类型规整

for c in ["layer_mm", "infill_pct", "nozzle_temp", "speed",

"raster_deg", "print_time_min", "tensile_MPa"]:

if c in df.columns:

df[c] = pd.to_numeric(df[c], errors="coerce")

# 后处理缺省为none

df["post_process"] = df.get("post_process", "none").astype(str)

# 去异常: 强度离群(>均值3σ)

mu, sd = df["tensile_MPa"].mean(), df["tensile_MPa"].std()

df = df[(df["tensile_MPa"] > mu - 3*sd) &

(df["tensile_MPa"] < mu + 3*sd)].copy()

df = df.dropna(subset=req).reset_index(drop=True)

return df

</details>

<details>

<summary></summary>

"""层厚×填充率组合网格 (numpy)"""

import numpy as np

import pandas as pd

from typing import Optional

class ProcessGrid:

"""

层厚网格 × 填充率网格 笛卡尔积

默认补齐中值温度/速度/光栅角

"""

def __init__(self,

layer_grid: Optional[np.ndarray] = None,

infill_grid: Optional[np.ndarray] = None):

self.layer_grid = layer_grid or np.array([0.08, 0.10, 0.12, 0.15, 0.20])

self.infill_grid = infill_grid or np.arange(20, 71, 10)

self.defaults = {

"nozzle_temp": 255.0, # PA12典型

"speed": 60.0,

"raster_deg": 45.0,

"post_process": "none",

}

def expand(self) -> pd.DataFrame:

L, I = np.meshgrid(self.layer_grid, self.infill_grid, indexing="ij")

rows = []

for l, inf in zip(L.ravel(), I.ravel()):

row = {

"layer_mm": round(float(l), 3),

"infill_pct": int(inf),

"nozzle_temp": self.defaults["nozzle_temp"],

"speed": self.defaults["speed"],

"raster_deg": self.defaults["raster_deg"],

"post_process": self.defaults["post_process"],

}

rows.append(row)

return pd.DataFrame(rows)

def estimate_time(self, df: pd.DataFrame) -> pd.DataFrame:

"""简化打印时间模型: 层厚反比, 填充率正比"""

out = df.copy()

base = 60.0

out["print_time_min"] = (

base * (0.12 / out["layer_mm"]) *

(1 + out["infill_pct"] / 100.0 * 0.8)

).round(1)

return out

</details>

<details>

<summary></summary>

"""抗拉强度响应面模型 (sklearn + scipy)"""

import numpy as np

import pandas as pd

from sklearn.linear_model import LinearRegression

from sklearn.ensemble import (RandomForestRegressor,

GradientBoostingRegressor)

from sklearn.metrics import r2_score, mean_squared_error

from sklearn.model_selection import train_test_split

from scipy.optimize import curve_fit

from typing import Dict

class ResponseModeler:

"""

特征: layer_mm, infill_pct, nozzle_temp, speed, raster_deg,

layer2(层厚二次, 捕捉拐点), infill_log(饱和效应)

"""

def __init__(self, random_state: int = 42):

self.random_state = random_state

self.models: Dict[str, object] = {}

self.metrics = pd.DataFrame()

self.feat_cols = []

@staticmethod

def _feat(df: pd.DataFrame) -> pd.DataFrame:

x = df.copy()

x["layer2"] = x["layer_mm"] ** 2

x["infill_eff"] = np.sqrt(x["infill_pct"]) # 饱和

x["layer_infill"] = x["layer_mm"] * x["infill_pct"] / 100.0

return x

def fit_compare(self, df: pd.DataFrame) -> pd.DataFrame:

xdf = self._feat(df)

self.feat_cols = ["layer_mm", "layer2", "infill_eff",

"nozzle_temp", "speed", "raster_deg",

"layer_infill"]

X = xdf[self.feat_cols].values.astype(float)

y = xdf["tensile_MPa"].values.astype(float)

Xtr, Xte, ytr, yte = train_test_split(

X, y, test_size=0.25, random_state=self.random_state)

specs = {

"lin": LinearRegression(),

"rf": RandomForestRegressor(n_estimators=300,

random_state=self.random_state),

"gbdt": GradientBoostingRegressor(random_state=self.random_state),

}

rows = []

for name, m in specs.items():

m.fit(Xtr, ytr)

pred = m.predict(Xte)

self.models[name] = m

rows.append({

"model": name,

"r2": round(r2_score(yte, pred), 4),

"rmse": round(np.sqrt(mean_squared_error(yte, pred)), 3),

})

self.metrics = pd.DataFrame(rows).sort_values("r2", ascending=False).reset_index(drop=True)

self._xte, self._yte = Xte, yte

return self.metrics

def predict(self, model_name: str, df: pd.DataFrame) -> np.ndarray:

xdf = self._feat(df)

cols = [c for c in self.feat_cols if c in xdf.columns]

return self.models[model_name].predict(xdf[cols].values.astype(float))

def predict_with_std(self, df: pd.DataFrame) -> pd.DataFrame:

"""用RF叶子方差近似置信带"""

xdf = self._feat(df)

cols = [c for c in self.feat_cols if c in xdf.columns]

Xq = xdf[cols].values.astype(float)

rf = self.models["rf"]

preds = np.stack([t.predict(Xq) for t in rf.estimators_])

mean = preds.mean(axis=0)

std = preds.std(axis=0)

out = df.copy()

out["pred_strength"] = np.round(mean, 2)

out["pred_std"] = np.round(std, 2)

out["pred_ci_low"] = np.round(mean - 1.96*std, 2)

out["pred_ci_high"] = np.round(mean + 1.96*std, 2)

return out

def quad_response_surface(self, df: pd.DataFrame) -> callable:

"""scipy二次响应面参照: 仅层厚+填充"""

sub = df.copy()

def f(p, a, b, c, d, e):

layer, inf = p

return a + b*layer + c*layer**2 + d*np.sqrt(inf) + e*inf

popt, _ = curve_fit(f,

(sub["layer_mm"].values, sub["infill_pct"].values),

sub["tensile_MPa"].values, maxfev=5000)

return lambda L, I: f((L, I), *popt)

</details>

<details>

<summary></summary>

"""强度-时间帕累托前沿求解 (numpy)"""

import numpy as np

import pandas as pd

from typing import Optional

class ParetoSolver:

"""

目标: 强度最大(正向), 打印时间最小(正向)

返回非支配解集合

"""

def __init__(self):

pass

def solve(self, df: pd.DataFrame,

obj1: str = "pred_strength",

obj2: str = "print_time_min") -> pd.DataFrame:

data = df[[obj1, obj2]].values.astype(float)

n = len(data)

is_pareto = np.ones(n, dtype=bool)

for i in range(n):

s_i = data[i]

# 存在j: 强度>=且时间<=, 且至少一项严格优 -> i被支配

for j in range(n):

if i == j:

continue

s_j = data[j]

if (s_j[0] >= s_i[0] and s_j[1] <= s_i[1]) and \

(s_j[0] > s_i[0] or s_j[1] < s_i[1]):

is_pareto[i] = False

break

out = df.copy()

out["is_pareto"] = is_pareto

return out.sort_values([obj1, obj2], ascending=[False, True]).reset_index(drop=True)

def best_strength(self, df: pd.DataFrame) -> pd.DataFrame:

return df.loc[df["pred_strength"].idxmax()].to_frame().T

</details>

<details>

<summary></summary>

"""敏感度分析 (numpy/scipy)"""

import numpy as np

import pandas as pd

from typing import Optional

class SensitivityAnalyzer:

"""固定其他参数, 扫单变量看强度响应"""

def __init__(self, modeler, model_name: str = "rf"):

self.modeler = modeler

self.model_name = model_name

def sweep_layer(self, base: dict,

layer_grid: Optional[np.ndarray] = None) -> pd.DataFrame:

layer_grid = layer_grid or np.linspace(0.06, 0.25, 40)

rows = []

for l in layer_grid:

d = dict(base); d["layer_mm"] = round(float(l), 3)

tmp = pd.DataFrame([d])

pred = self.modeler.predict(self.model_name, tmp)[0]

rows.append({"layer_mm": l, "pred_strength": pred})

out = pd.DataFrame(rows)

# 找拐点: 二阶导变号(强度加速下降)

y = out["pred_strength"].values

d2 = np.gradient(np.gradient(y))

out["curvature"] = d2

return out

def sweep_infill(self, base: dict,

infill_grid: Optional[np.ndarray] = None) -> pd.DataFrame:

infill_grid = infill_grid or np.arange(10, 81, 2)

rows = []

for inf in infill_grid:

d = dict(base); d["infill_pct"] = int(inf)

tmp = pd.DataFrame([d])

pred = self.modeler.predict(self.model_name, tmp)[0]

rows.append({"infill_pct": inf, "pred_strength": pred})

out = pd.DataFrame(rows)

# 边际收益

out["marginal_gain"] = np.gradient(out["pred_strength"].values)

return out

</details>

<details>

<summary></summary>

"""参数影响网 (networkx)"""

import networkx as nx

import pandas as pd

from typing import Dict

class ParamInfluenceGraph:

"""参数 -> 中间量 -> 强度 有向网"""

def __init__(self):

self.G = nx.DiGraph()

def build(self, importance: Dict[str, float]) -> nx.DiGraph:

self.G.clear()

self.G.add_node("抗拉强度", ntype="response")

# 中间量

self.G.add_node("层间结合", ntype="mid")

self.G.add_node("孔隙率", ntype="mid")

# 参数节点

params = {

"layer_mm": "层厚",

"infill_eff": "填充率(有效)",

"nozzle_temp": "喷嘴温度",

"raster_deg": "光栅角",

"speed": "打印速度",

}

for k, label in params.items():

self.G.add_node(label, ntype="param", key=k)

# 层厚->层间结合

w_layer = importance.get("layer_mm", 0) + importance.get("layer2", 0)

self.G.add_edge("层厚", "层间结合", weight=round(w_layer*100, 2))

self.G.add_edge("层间结合", "抗拉强度", weight=round(w_layer*80, 2))

# 填充->孔隙率

w_inf = importance.get("infill_eff", 0)

self.G.add_edge("填充率(有效)", "孔隙率", weight=round(w_inf*100, 2))

self.G.add_edge("孔隙率", "抗拉强度", weight=round(w_inf*70, 2))

# 其他直连

self.G.add_edge("喷嘴温度", "抗拉强度", weight=round(importance.get("nozzle_temp",0)*100,2))

self.G.add_edge("光栅角", "抗拉强度", weight=round(importance.get("raster_deg",0)*100,2))

self.G.add_edge("打印速度", "抗拉强度", weight=round(importance.get("speed",0)*100,2))

return self.G

def top_edges(self) -> pd.DataFrame:

rows = [{"from":u,"to":v,"weight":d["weight"]}

for u,v,d in self.G.edges(data=True)]

return pd.DataFrame(rows).sort_values("weight", ascending=False).reset_index(drop=True)

</details>

<details>

<summary></summary>

"""可视化 (matplotlib)"""

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

from pathlib import Path

import networkx as nx

from sklearn.metrics import r2_score

plt.rcParams["font.sans-serif"] = ["SimHei", "DejaVu Sans"]

plt.rcParams["axes.unicode_minus"] = False

class AmVisualizer:

def __init__(self, results_dir: str = "results"):

self.results_dir = Path(results_dir)

self.results_dir.mkdir(exist_ok=True)

def heatmap(self, grid_df):

piv = grid_df.pivot(index="layer_mm", columns="infill_pct",

values="pred_strength")

fig, ax = plt.subplots(figsize=(10, 6))

im = ax.imshow(piv.values, cmap="viridis", aspect="auto")

ax.set_xticks(range(len(piv.columns)))

ax.set_xticklabels(piv.columns)

ax.set_yticks(range(len(piv.index)))

ax.set_yticklabels(piv.index)

ax.set_xlabel("填充率 (%)"); ax.set_ylabel("层厚 (mm)")

fig.colorbar(im, ax=ax, label="预测抗拉强度 (MPa)")

ax.set_title("层厚×填充率 强度热力图", fontsize=13, fontweight="bold")

plt.tight_layout()

plt.savefig(self.results_dir/"strength_heatmap.png", dpi=150, bbox_inches="tight")

plt.close()

def pareto(self, df):

fig, ax = plt.subplots(figsize=(9, 6))

normal = df[~df["is_pareto"]]

pareto = df[df["is_pareto"]]

ax.scatter(normal["print_time_min"], normal["pred_strength"],

c="#BDC3C7", s=12, label="候选组合")

ax.scatter(pareto["print_time_min"], pareto["pred_strength"],

c="#E74C3C", s=45, label="帕累托前沿", zorder=5)

# 连线

p = pareto.sort_values("print_time_min")

ax.plot(p["print_time_min"], p["pred_strength"], "--", color="#C0392B", alpha=0.6)

ax.set_xlabel("打印时间 (min)"); ax.set_ylabel("预测抗拉强度 (MPa)")

ax.set_title("强度-时间 帕累托前沿", fontsize=13, fontweight="bold")

ax.legend(); ax.grid(alpha=0.3)

plt.tight_layout()

plt.savefig(self.results_dir/"pareto_front.png", dpi=150, bbox_inches="tight")

plt.close()

def layer_sensitivity(self, sens):

fig, ax = plt.subplots(figsize=(10, 5))

ax.plot(sens["layer_mm"], sens["pred_strength"], "-o", color="#2980B9", ms=3)

# 标拐点

k = sens["curvature"].idxmin()

xk, yk = sens.loc[k, "layer_mm"], sens.loc[k, "pred_strength"]

ax.axvline(xk, color="#E74C3C", ls="--", lw=1)

ax.scatter([xk],[yk], color="#E74C3C", s=50, zorder=5)

ax.text(xk, yk, f" 拐点≈{xk:.3f}mm", color="#E74C3C")

ax.set_xlabel("层厚 (mm)"); ax.set_ylabel("预测强度 (MPa)")

ax.set_title("层厚敏感度曲线(含结合力拐点)", fontsize=13, fontweight="bold")

ax.grid(alpha=0.3)

plt.tight_layout()

plt.savefig(self.results_dir/"layer_sensitivity.png", dpi=150, bbox_inches="tight")

plt.close()

def infill_marginal(self, sens):

fig, ax = plt.subplots(figsize=(10, 5))

ax.plot(sens["infill_pct"], sens["pred_strength"], "-", color="#16A085")

ax2 = ax.twinx()

ax2.plot(sens["infill_pct"], sens["marginal_gain"], "--", color="#8E44AD", lw=1)

ax.set_xlabel("填充率 (%)")

ax.set_ylabel("预测强度 (MPa)", color="#16A085")

ax2.set_ylabel("边际增益 (MPa/%)", color="#8E44AD")

ax.set_title("填充率边际收益曲线", fontsize=13, fontweight="bold")

ax.grid(alpha=0.3)

plt.tight_layout()

plt.savefig(self.results_dir/"infill_marginal.png", dpi=150, bbox_inches="tight")

plt.close()

def model_compare(self, modeler):

fig, ax = plt.subplots(figsize=(7,7))

for _, r in modeler.metrics.iterrows():

name = r["model"]

Xte, yte = modeler._xte, modeler._yte

xdf = modeler._feat(pd.DataFrame(Xte, columns=modeler.feat_cols))

pred = modeler.models[name].predict(Xte)

ax.scatter(yte, pred, s=8, alpha=0.5, label=f"{name} R2={r['r2']}")

ax.plot([yte.min(), yte.max()],[yte.min(), yte.max()],"k--",lw=0.8)

ax.set_xlabel("实测强度 (MPa)"); ax.set_ylabel("预测强度 (MPa)")

ax.set_title("预测vs实测对照", fontsize=13, fontweight="bold")

ax.legend(); ax.grid(alpha=0.3)

plt.tight_layout()

plt.savefig(self.results_dir/"model_compare.png", dpi=150, bbox_inches="tight")

plt.close()

def graph_plot(self,

利用AI解决实际问题,如果你觉得这个工具好用,欢迎关注长安牧笛!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询