news 2026/10/4 6:41:29

python的先进制造技术工业场景模拟第五十六篇:加载3D打印翘边试验数据集,建立分类模型,识别容易产生翘边的参数组合。

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python的先进制造技术工业场景模拟第五十六篇:加载3D打印翘边试验数据集,建立分类模型,识别容易产生翘边的参数组合。

周三早上,增材制造实验室,FDM 桌面级 3D 打印机刚跑完一轮 ABS 材料翘边对比试验。

"这批测试件,12 组参数组合,每组打 5 件,翘边率从 0% 到 80% 不等,"实验室助教小林指着打印平台,"你能看到床温 80℃、环境温度 25℃、首层速度 30mm/s、层高 0.3mm 那组翘了 4 件,但床温 100℃、关着机箱门、首层速度 15mm/s 的那组一件没翘。问题是——到底是哪个参数在起作用?是床温、是环境温度、还是首层速度?它们之间有没有组合效应?"

我点开他导出的 CSV。

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

"每组试验的编号、材料类型(ABS/PLA/PA)、喷嘴温度(℃)、热床温度(℃)、环境温度(℃)、首层打印速度(mm/s)、首层层高(mm)、填充密度(%)、有无 enclosure(机箱门)、冷却风扇转速(%)、材料是否烘干、翘边结果(翘边/未翘边),以及翘边发生位置(角落/边缘/整体),"我指着屏幕,"但它就是一张试验记录表。你能看到床温高+关门的组翘边少,但说不清:床温从 80℃ 提到 100℃ 贡献了多少? enclosure 是必要条件还是充分条件?首层速度从 30 降到 15 是不是边际递减?下次换 PA 材料,这套参数还能用吗?"

"我就想干一件事,"小林说,"给我一个程序:把这堆试验数据灌进去,自动告诉我'翘边的 Top 5 关键参数',最好还能量化'哪种参数组合最容易翘边'。我拿去跟学生说'做 ABS 打印,床温必须 ≥95℃ 且首层速度 ≤20mm/s,否则翘边概率 >60%',而不是靠试。"

"比如材料类型决定了收缩应力大小,床温决定了第一层附着力,环境温度决定了冷却梯度——这三个是主因,但首层速度和层高会放大或缩小效应,"我接话,"用 pandas 做参数编码和特征工程,scikit-learn 的随机森林分类做特征重要性+决策边界,scipy 做卡方检验确认离散参数的显著性,matplotlib 画参数组合散点+翘边分布+ROC+混淆矩阵+特征重要性+参数交互热图+因果网络,networkx 建'工艺参数→翘边风险'的因果链路。"

"对,"小林点头,"别给我黑盒,要能说清楚'为什么床温比喷嘴温度影响大'。我看得懂,能拿去跟学生讲'ABS 的玻璃化转变温度 105℃,床温不到 100℃ 第一层就处于玻璃态收缩,粘不住'。"

"用 pandas 做特征工程,随机森林分类+卡方双管齐下,scipy 做显著性检验,matplotlib 出 6 图+报告,存 results/,"我开工程,"数据自包含,合成一批含 10 个工艺参数、180 组试验的翘边数据,下载就能跑。"

敲了行原型:

# 翘边 = 第一层收缩应力 > 附着力

# 收缩应力 = f(材料收缩率, 冷却梯度, 层厚)

# 附着力 = f(床温, 环境温度, 首层速度, 有无 enclosure)

# 随机森林: 捕捉非线性 + 参数组合效应

# 卡方检验: 确认离散参数(enclosure/材料)的显著性

"完整版 OOP 封好,"我说,"数据加载器、特征工程器、翘边分类器(随机森林+卡方)、交互分析器、因果网络、可视化器,输出关键参数排序+参数组合风险矩阵+6图+报告。"

小林凑近看:"那以后看报告:随机森林特征重要性排第一的是'热床温度'(26%),第二是'环境温度'(18%),第三是'首层打印速度'(15%),第四是'有无 enclosure'(12%),第五是'材料类型'(11%)。卡方确认 enclosure(p<0.001)和材料类型(p=0.003)显著。交互热图显示:床温<90℃ 且 环境温度<28℃ 时翘边率 78%。结论:ABS 打印必须床温≥95℃ + 关门 + 首层速度≤20mm/s,翘边率可压到 5%以下。"

"对,"我接话,"3D 打印不是'打出来就行',是'每一层的热历史都要可控'。数字孪生里挂打印质量节点,这套就是工艺员的'翘边预警器'。"

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

场景设定:FDM/FFF 3D 打印实验室或小型生产单元,使用 ABS、PLA、PA 等材料打印功能件。翘边(warping/curling)是首层冷却收缩导致的最常见缺陷,直接影响零件尺寸精度和后续堆叠成功率。

现场原话(叙事化):

"不是我们调不好,"小林说,"是参数太多了。喷嘴温度、床温、环境温度、首层速度、层高、填充、风扇、enclosure——你让我调哪个?上次我把床温从 80 提到 100,翘边好了,但表面拉丝严重。后来发现关门(enclosure)效果更明显,床温 90℃+关门 翘边率就 3%。那我到底该提床温还是关门?哪个性价比高?换 PA 材料又不一样了。"

"最坑的是组合效应,"小林补充,"床温 85℃ 时开风扇翘边率 60%,关风扇就 15%。但床温 100℃ 时开不开风扇都差不多。你单看床温或单看风扇都看不出问题,得两个放一起看。以前没人系统做这个分析,全凭经验试。"

核心矛盾:"多参数试错 + 凭经验调参" 与 "数据驱动的参数重要性排序 + 卡方显著性 + 组合风险矩阵 + 可解释工艺窗口" 之间的断层。

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

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

增材制造(3D打印)技术:FDM 工艺原理与缺陷 翘边机理+工艺参数优化

先进制造技术基础:材料热物理性能 收缩应力+玻璃化转变

智能制造与数字孪生:工艺数据驱动 试验数据挖掘+质量预测

柔性制造系统FMS:过程质量控制 参数组合风险分级

一句话总结:我们需要一个"3D打印翘边试验数据→特征工程+随机森林分类+卡方检验+交互热图+因果网络程序",用

"pandas" 做数据清洗/参数编码,

"scikit-learn" 随机森林分类+特征重要性,

"scipy" 卡方检验+显著性验证,

"matplotlib" 画参数分布+ROC+混淆矩阵+特征重要性+交互热图+因果网络,

"networkx" 建因果链路,实现从"凭经验试参数"到"数据归因+组合风险量化+工艺窗口推荐"。

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

3.1 问题本质:把翘边想成"披萨饼底卷边"

把 3D 打印翘边想成披萨饼底在烤盘上卷起来:

* 翘边 = 饼底边缘翘起来了,粘不住烤盘

* 收缩应力 = 饼底受热膨胀再冷却收缩,边缘往外拉

* 附着力 = 饼底和烤盘之间的粘合力

* 翘边条件 = 收缩应力 > 附着力

* 床温 = 烤盘预热温度(越热饼底越软越粘)

* 环境温度 = 烤箱里整体温度(越热冷却越慢,收缩越小)

* 首层速度 = 你铺饼底的快慢(越慢铺得越实,粘得越牢)

* Enclosure = 烤箱门(关门=保温,开门=冷风灌进来)

* 材料类型 = 面饼种类(有的面本身弹性大,有的容易缩)

* 分类器 = 看了 180 个"参数组合→翘没翘"的试验结果,学会了"什么组合最容易翘"

3.2 业务逻辑 → 代码映射

加载3D打印翘边试验数据

│

▼ WarpDataLoader (pandas)

读取表:

试验编号, 材料类型, 喷嘴温度, 热床温度,

环境温度, 首层速度, 首层层高, 填充密度,

有无enclosure, 冷却风扇转速, 材料是否烘干,

翘边结果(翘边/未翘边), 翘边位置

│

▼ WarpFeatureEngineer (pandas + numpy)

特征工程:

材料类型 → one-hot (ABS/PLA/PA)

enclosure → 二值(0/1)

材料烘干 → 二值(0/1)

数值特征 → 标准化

特征矩阵 X, 目标 y(翘边=1/未翘边=0)

│

▼ WarpClassifier (scikit-learn + scipy)

双模型归因:

随机森林分类 → 特征重要性(全局)

卡方检验(scipy) → 离散参数显著性

逻辑回归(基线) → 效应方向

│

▼ WarpInteractionAnalyzer (numpy)

交互效应:

床温 × 环境温度 网格 → 翘边率热图

首层速度 × 风扇转速 网格 → 翘边率热图

│

▼ WarpCausalNetwork (networkx)

因果网络:

节点: 10个工艺参数 + 翘边风险

边: 影响方向 + 重要性权重

│

▼ WarpVisualizer (matplotlib)

可视化:

1. 参数组合散点图(颜色=翘边)

2. 翘边率随关键参数变化曲线

3. ROC曲线

4. 混淆矩阵

5. 特征重要性柱状图

6. 床温×环境温度交互热图

7. 因果网络图

│

▼ SyntheticWarpData (numpy)

合成数据:

10参数 × 180组试验, 含噪声和交互效应

可复现

3.3 为什么不能只看"哪个参数影响最大"

视角 问题

单因素改参数 忽略了参数间的交互(床温×环境)

凭经验设窗口 不同材料完全不同

随机森林 捕捉非线性+组合效应

卡方检验 确认离散参数(材料/enclosure)的真实贡献

交互热图 揭示"两个参数一起调才有效"

3.4 分析前后对比

维度 传统方式 本程序

参数选择 凭经验逐个试 随机森林+卡方双验证排序

工艺窗口 "大概 100℃ 差不多" 床温≥95℃ + 关门 + 首层≤20mm/s

组合效应 看不见 热图量化风险矩阵

置信度 "应该没问题" p值+交叉验证 AUC

输出 报废件 6图+报告+工艺窗口推荐

四、OOP 代码实现

4.1 项目结构

warp_risk_analyzer/

├── warp_risk_analyzer/

│ ├── __init__.py

│ ├── warp_data_loader.py # 数据加载

│ ├── warp_feature_engineer.py # 特征工程

│ ├── warp_classifier.py # 翘边分类+卡方

│ ├── warp_interaction_analyzer.py # 交互分析

│ ├── warp_causal_network.py # 因果网络

│ ├── visualizer.py # 可视化

│ └── synthetic_warp_data.py # 合成数据

├── tests/

│ ├── __init__.py

│ └── test_warp.py

├── results/

│ ├── param_scatter.png

│ ├── warp_rate_curve.png

│ ├── roc_curve.png

│ ├── confusion_matrix.png

│ ├── feature_importance.png

│ ├── interaction_heatmap.png

│ ├── causal_network.png

│ ├── warp_detail.csv

│ └── warp_report.txt

└── run_warp.py

4.2 核心源码

<details>

<summary></summary>

"""3D打印翘边试验数据加载器"""

import pandas as pd

from pathlib import Path

from typing import Optional

class WarpDataLoader:

"""读取翘边试验数据集"""

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

encoding: str = "utf-8"):

self.filepath = Path(filepath)

self.encoding = encoding

def load(self) -> pd.DataFrame:

if not self.filepath.exists():

raise FileNotFoundError(self.filepath)

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

req = ["test_id", "material", "nozzle_temp_c", "bed_temp_c",

"ambient_temp_c", "first_layer_speed_mm_s",

"first_layer_height_mm", "infill_percent",

"has_enclosure", "fan_speed_percent",

"material_dried", "warp_result", "warp_location"]

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

if miss:

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

# 类型转换

num_cols = ["nozzle_temp_c", "bed_temp_c", "ambient_temp_c",

"first_layer_speed_mm_s", "first_layer_height_mm",

"infill_percent", "fan_speed_percent"]

for c in num_cols:

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

# 二值化目标

df["is_warp"] = (df["warp_result"] == "翘边").astype(int)

# 二值化离散特征

df["has_enclosure"] = df["has_enclosure"].map(

{"是": 1, "否": 0, True: 1, False: 0}).fillna(0).astype(int)

df["material_dried"] = df["material_dried"].map(

{"是": 1, "否": 0, True: 1, False: 0}).fillna(0).astype(int)

df = df.dropna(subset=["bed_temp_c", "is_warp"]).reset_index(drop=True)

return df

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

s = f"试验组数: {len(df)}\n"

s += f"翘边率: {df['is_warp'].mean()*100:.1f}%\n"

s += f"材料分布: {df['material'].value_counts().to_dict()}\n"

s += f"有enclosure: {df['has_enclosure'].sum()}/{len(df)}"

return s

</details>

<details>

<summary></summary>

"""特征工程 (pandas + numpy)"""

import numpy as np

import pandas as pd

from typing import Tuple, Dict, List

class WarpFeatureEngineer:

"""构建特征矩阵"""

def __init__(self):

self.material_categories_ = None

self.feature_names_ = None

def fit(self, df: pd.DataFrame):

self.material_categories_ = sorted(df["material"].unique())

def transform(self, df: pd.DataFrame) -> Tuple[np.ndarray, np.ndarray]:

X_list = []

for _, row in df.iterrows():

features = []

# 材料 one-hot

for mat in self.material_categories_:

features.append(1.0 if row["material"] == mat else 0.0)

# 离散参数

features.append(float(row["has_enclosure"]))

features.append(float(row["material_dried"]))

# 数值特征

features.append(float(row["nozzle_temp_c"]) / 10.0)

features.append(float(row["bed_temp_c"]) / 10.0)

features.append(float(row["ambient_temp_c"]) / 10.0)

features.append(float(row["first_layer_speed_mm_s"]))

features.append(float(row["first_layer_height_mm"]) * 100)

features.append(float(row["infill_percent"]) / 10.0)

features.append(float(row["fan_speed_percent"]) / 10.0)

X_list.append(features)

X = np.array(X_list)

y = df["is_warp"].values

self.feature_names_ = (

[f"mat_{m}" for m in self.material_categories_] +

["enclosure", "dried", "nozzle_temp", "bed_temp",

"ambient_temp", "first_layer_speed", "first_layer_height",

"infill", "fan_speed"]

)

return X, y

def get_feature_names(self) -> List[str]:

return self.feature_names_

</details>

<details>

<summary></summary>

"""翘边分类器 (scikit-learn + scipy)"""

import numpy as np

from typing import Dict

from sklearn.ensemble import RandomForestClassifier

from sklearn.linear_model import LogisticRegression

from sklearn.model_selection import cross_val_score, StratifiedKFold

from sklearn.metrics import (roc_auc_score, roc_curve, confusion_matrix,

accuracy_score, classification_report)

from scipy.stats import chi2_contingency

import warnings

warnings.filterwarnings("ignore")

class WarpClassifier:

"""随机森林分类 + 卡方检验"""

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

self.random_state = random_state

self.rf = RandomForestClassifier(

n_estimators=200, max_depth=8, class_weight="balanced",

random_state=random_state)

self.lr = LogisticRegression(class_weight="balanced",

random_state=random_state)

self.feature_names_ = None

self.rf_importance_ = None

def fit(self, X: np.ndarray, y: np.ndarray, feature_names: list):

self.feature_names_ = feature_names

self.rf.fit(X, y)

self.lr.fit(X, y)

importances = self.rf.feature_importances_

self.rf_importance_ = dict(

sorted(zip(feature_names, importances),

key=lambda x: x[1], reverse=True))

def evaluate(self, X: np.ndarray, y: np.ndarray) -> Dict:

skf = StratifiedKFold(n_splits=5, shuffle=True,

random_state=self.random_state)

cv_auc = cross_val_score(self.rf, X, y, cv=skf, scoring="roc_auc")

cv_f1 = cross_val_score(self.rf, X, y, cv=skf, scoring="f1")

y_pred = self.rf.predict(X)

y_prob = self.rf.predict_proba(X)[:, 1]

fpr, tpr, _ = roc_curve(y, y_prob)

cm = confusion_matrix(y, y_pred)

return {

"cv_auc_mean": round(cv_auc.mean(), 3),

"cv_auc_std": round(cv_auc.std(), 3),

"cv_f1_mean": round(cv_f1.mean(), 3),

"train_accuracy": round(accuracy_score(y, y_pred), 3),

"fpr": fpr,

"tpr": tpr,

"y_pred": y_pred,

"y_prob": y_prob,

"confusion_matrix": cm,

}

def chi_square_test(self, df: "pd.DataFrame") -> Dict:

"""卡方检验: 离散参数与翘边的关联显著性"""

from scipy import stats

import pandas as pd

results = {}

discrete_params = ["material", "has_enclosure", "material_dried"]

for param in discrete_params:

if param not in df.columns:

continue

ct = pd.crosstab(df[param], df["is_warp"])

if ct.shape[0] >= 2 and ct.shape[1] >= 2:

chi2, p, dof, expected = stats.chi2_contingency(ct)

results[param] = {

"chi2": round(chi2, 3),

"p_value": round(p, 6),

"significant": p < 0.05,

"dof": dof,

}

return results

def predict_proba_warp(self, X: np.ndarray) -> np.ndarray:

return self.rf.predict_proba(X)[:, 1]

def get_top_factors(self, n: int = 5) -> list:

return list(self.rf_importance_.items())[:n]

</details>

<details>

<summary></summary>

"""交互效应分析 (numpy)"""

import numpy as np

import pandas as pd

from typing import Dict

class WarpInteractionAnalyzer:

"""分析两个参数的交互效应对翘边率的影响"""

def __init__(self):

pass

def warp_rate_heatmap(self, df: pd.DataFrame,

x_col: str, y_col: str,

x_bins: int = 5, y_bins: int = 5) -> Dict:

"""生成翘边率交互热图数据"""

x_edges = np.linspace(df[x_col].min(), df[x_col].max(), x_bins + 1)

y_edges = np.linspace(df[y_col].min(), df[y_col].max(), y_bins + 1)

heatmap = np.zeros((y_bins, x_bins))

counts = np.zeros((y_bins, x_bins))

for i in range(y_bins):

for j in range(x_bins):

mask = (

(df[x_col] >= x_edges[j]) & (df[x_col] < x_edges[j+1]) &

(df[y_col] >= y_edges[i]) & (df[y_col] < y_edges[i+1])

)

if mask.sum() > 0:

heatmap[i, j] = df[mask]["is_warp"].mean() * 100

counts[i, j] = mask.sum()

else:

heatmap[i, j] = np.nan

return {

"heatmap": heatmap,

"counts": counts,

"x_edges": x_edges,

"y_edges": y_edges,

}

</details>

<details>

<summary></summary>

"""翘边因果网络 (networkx)"""

import networkx as nx

import numpy as np

from typing import Dict

class WarpCausalNetwork:

"""构建工艺参数→翘边风险因果网络"""

def __init__(self):

self.G = nx.DiGraph()

def build(self, feature_importance: Dict,

chi2_results: Dict,

df: pd.DataFrame) -> nx.DiGraph:

self.G.clear()

self.G.add_node("翘边风险", ntype="defect", weight=2.0)

for feat, imp in feature_importance.items():

chi2_sig = chi2_results.get(feat, {}).get("significant", False)

self.G.add_node(feat, ntype="param",

weight=imp, sig=chi2_sig)

edge_weight = imp * 1.2 if chi2_sig else imp * 0.6

self.G.add_edge(feat, "翘边风险", weight=round(edge_weight, 4))

return self.G

</details>

<details>

<summary></summary>

"""可视化 (matplotlib + networkx)"""

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

from pathlib import Path

import networkx as nx

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

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

class WarpVisualizer:

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

self.results_dir = Path(results_dir)

self.results_dir.mkdir(exist_ok=True)

def param_scatter(self, df: pd.DataFrame):

"""参数组合散点图(颜色=翘边)"""

fig, axes = plt.subplots(2, 3, figsize=(16, 10))

axes = axes.flatten()

params = ["bed_temp_c", "ambient_temp_c", "first_layer_speed_mm_s",

"nozzle_temp_c", "first_layer_height_mm", "fan_speed_percent"]

titles = ["热床温度", "环境温度", "首层速度", "喷嘴温度", "首层层高", "风扇转速"]

for i, (param, title) in enumerate(zip(params, titles)):

if i >= 6:

break

ax = axes[i]

ok = df[df["is_warp"] == 0]

bad = df[df["is_warp"] == 1]

ax.scatter(ok[param], [0]*len(ok), c="#27AE60", alpha=0.6,

s=30, label="未翘边", zorder=3)

ax.scatter(bad[param], [1]*len(bad), c="#E74C3C", alpha=0.6,

s=30, label="翘边", zorder=3)

ax.set_xlabel(title)

ax.set_yticks([0, 1])

ax.set_yticklabels(["未翘边", "翘边"])

ax.set_title(f"{title} vs 翘边", fontsize=11)

ax.grid(axis="x", alpha=0.3)

if i == 0:

ax.legend(fontsize=8)

plt.suptitle("关键参数 vs 翘边结果", fontsize=14, fontweight="bold")

plt.tight_layout()

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

plt.close()

def warp_rate_curve(self, df: pd.DataFrame):

"""翘边率随关键参数变化曲线"""

fig, axes = plt.subplots(1, 3, figsize=(15, 5))

params = ["bed_temp_c", "ambient_temp_c", "first_layer_speed_mm_s"]

xlabels = ["热床温度 (℃)", "环境温度 (℃)", "首层速度 (mm/s)"]

for i, (param, xlabel) in enumerate(zip(params, xlabels)):

ax = axes[i]

df_copy = df.copy()

df_copy["bin"] = pd.cut(df_copy[param], bins=8)

warp_rates = df_copy.groupby("bin")["is_warp"].mean() * 100

bin_centers = [interval.mid for interval in warp_rates.index]

ax.plot(bin_centers, warp_rates.values, "o-", color="#E74C3C",

linewidth=2, markersize=6)

ax.fill_between(bin_centers, warp_rates.values, alpha=0.2,

color="#E74C3C")

ax.set_xlabel(xlabel)

ax.set_ylabel("翘边率 (%)")

ax.set_title(f"翘边率 vs {xlabel}", fontsize=11)

ax.grid(alpha=0.3)

plt.suptitle("翘边率随关键参数变化趋势", fontsize=13, fontweight="bold")

plt.tight_layout()

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

plt.close()

def roc_curve(self, fpr, tpr, auc_score: float):

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

ax.plot(fpr, tpr, "b-", linewidth=2.5, label=f"ROC (AUC={auc_score:.3f})")

ax.plot([0,1], [0,1], "k--", linewidth=1.5)

ax.set_xlabel("假阳性率 (FPR)")

ax.set_ylabel("真阳性率 (TPR)")

ax.set_title("ROC 曲线 - 翘边风险预判", fontsize=13, fontweight="bold")

ax.legend(loc="lower right")

ax.grid(alpha=0.3)

plt.tight_layout()

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

plt.close()

def confusion_matrix(self, cm: np.ndarray):

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

im = ax.imshow(cm, cmap="Blues", aspect="auto")

ax.set_xticks([0, 1])

ax.set_yticks([0, 1])

ax.set_xticklabels(["未翘边", "翘边"])

ax.set_yticklabels(["未翘边", "翘边"])

ax.set_xlabel("预测")

ax.set_ylabel("实际")

for i in range(2):

for j in range(2):

ax.text(j, i, str(cm[i, j]), ha="center", va="center",

fontsize=16, fontweight="bold",

color="white" if cm[i, j] > cm.max()/2 else "black")

plt.colorbar(im, ax=ax)

ax.set_title("混淆矩阵", fontsize=13, fontweight="bold")

plt.tight_layout()

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

plt.close()

def feature_importance(self, importance: Dict):

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

names = list(importance.keys())[:8]

vals = list(importance.values())[:8]

colors = plt.cm.Reds(np.array(vals) / max(vals))

ax.barh(range(len(names)), vals[::-1], color=colors[::-1],

edgecolor="black", height=0.6)

ax.set_yticks(range(len(names)))

ax.set_yticklabels(names[::-1], fontsize=10)

ax.set_xlabel("特征重要性")

ax.set_title("翘边关键因素排序", fontsize=13, fontweight="bold")

ax.grid(axis="x", alpha=0.3)

plt.tight_layout()

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

plt.close()

def interaction_heatmap(self, heatmap_data: Dict,

x_label: str = "热床温度(℃)",

y_label: str = "环境温度(℃)"):

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

heatmap = heatmap_data["heatmap"]

im = ax.imshow(heatmap, cmap="RdYlGn_r", aspect="auto", origin="lower")

ax.set_xticks(range(heatmap.shape[1]))

ax.set_yticks(range(heatmap.shape[0]))

x_edges = heatmap_data["x_edges"]

y_edges = heatmap_data["y_edges"]

ax.set_xticklabels([f"{x_edges[i]:.0f}" for i in range(len(x_edges)-1)])

ax.set_yticklabels([f"{y_edges[i]:.0f}" for i in range(len(y_edges)-1)])

ax.set_xlabel(x_label)

ax.set_ylabel(y_label)

ax.set_title("热床温度 × 环境温度 → 翘边率(%)", fontsize=13, fontweight="bold")

plt.colorbar(im, ax=ax, label="翘边率 (%)")

plt.tight_layout()

plt.savefig(

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/4 6:41:14

Azure KARS:让编码智能体走出代码库的多运行时基础设施

1. 编码智能体走出代码库这件事&#xff0c;到底在解决什么问题编码智能体这两年火得一塌糊涂&#xff0c;从最早的代码补全&#xff0c;到后来能自主拆解任务、读写文件、跑测试、提交 PR&#xff0c;能力边界一直在往外扩。但真正在工程里落地过的人都知道一个尴尬的现实&…

作者头像 李华
网站建设 2026/10/4 6:40:44

AIGC 驱动的内容生产力变革:Vidu 多模态大模型工程实践指南

&#x1f44b; Hi&#xff0c;我擅长 AI 大模型应用落地、意识解码与 AI 开发工具链 。 &#x1f4a1; 创业路上&#xff0c;用技术换时间&#xff0c;一起把 AI 变成生产力 &#x1f680; >AIGC 驱动的内容生产力变革&#xff1a;Vidu 多模态大模型工程实践指南 在多模态大…

作者头像 李华
网站建设 2026/10/4 6:35:38

Abaqus结构有限元分析全流程:从模型简化到结果验收

做结构有限元分析这行的朋友&#xff0c;多半都在某个深夜对着 Abaqus 的报错框怀疑过人生。我见过太多人花了半小时照着教程点出一个应力云图&#xff0c;换到自己的工程问题上却寸步难行。原因不是 Abaqus 难学&#xff0c;而是多数教程只教了“点击顺序”&#xff0c;没讲清…

作者头像 李华
网站建设 2026/10/4 6:34:27

Scan Chain实战解析:从原理到流片的DFT关键路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 6:32:53

插件激活失败怎么办:透过报错理解插件系统与排查方法

项目部署的时候&#xff0c;终端里突然冒出一行failed to load plugins web boot: 2 entries did not activate linxin666/dsh-p。第一次见到这种报错的人&#xff0c;多半会以为自己哪里配置错了&#xff0c;然后在网上搜 plugins&#xff0c;搜半天也搜不到一个明确答案。作为…

作者头像 李华