拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

python的先进制造技术工业场景模拟第六十三篇:加载3D打印孔隙试验数据,筛选影响内部孔隙率的关键工艺参数。

python的先进制造技术工业场景模拟第六十三篇:加载3D打印孔隙试验数据,筛选影响内部孔隙率的关键工艺参数。

周三下午,增材制造实验室,CT 扫描室门口。

"这批航空支架又废了,"工艺工程师小周把 CT 扫描报告拍在桌上,"激光选区熔化(SLM)打印的 Ti6Al4V 零件,内部孔隙率 2.3%,标准要求 ≤0.5%。拉伸强度直接掉了 30%,根本过不了质检。"

我翻开创口贴盒大小的零件样件。

"打印参数调过吗?"我问。

"调了,"小周调出 Excel 表,"激光功率 200W、扫描速度 1200mm/s、层厚 30μm、 hatch 间距 0.1mm、激光能量密度 68J/mm³、基板预热 80℃、保护气流量 15L/min、扫描策略 条带式、粉末粒径分布 D50=35μm、相对湿度 35%。上次试了功率拉到 250W,孔隙率降到 0.8%,但表面球化严重。又试了扫描速度降到 800,孔隙率 0.6% 但热应力开裂。"

"这表里有什么?"我问。

"每次工艺试验记录的 12 个参数 + CT 测出来的孔隙率(%),"小周说,"但它就是一张参数记录表。你能看到高功率低速度孔隙率低,但 12 个参数互相耦合——能量密度是功率/速度/层厚的组合,扫描间距又跟能量密度交互。工艺窗口窄得像刀刃,凭经验一个一个试,试一次打印 8 小时 + CT 扫描 2 小时,一周最多试 3 组。"

"我就想干一件事,"小周说,"给我一个程序:把过去两年 86 组工艺试验数据灌进去,自动筛出'对孔隙率影响最大的 3-4 个关键参数',告诉我'你别瞎调扫描策略和湿度了,那俩对孔隙率贡献不到 5%,死磕激光功率和扫描速度就行'。我拿去跟领导说'按这个方向缩参,试验次数从 50 组砍到 15 组,两周出最优工艺'。"

"比如这是个高维参数筛选问题——12 个输入 1 个输出,参数间有强相关性,"我接话,"用 pandas 做数据清洗+相关性分析,numpy 做方差分析,scikit-learn 的 RandomForest + Permutation Importance 做全局特征重要性排序,scipy 做偏相关+显著性检验,matplotlib 画相关性热力图+特征重要性+参数 vs 孔隙率散点矩阵+三维参数曲面+孔隙率分布+决策网络,networkx 建'参数→孔隙率→关键因子'推理链路。"

"对,"小周点头,"别给我黑盒,要能说清楚'为什么扫描策略不重要'。我看得懂,能拿去跟评审专家解释'激光功率贡献 38%、扫描速度 24%、层厚 15%,这三个加起来 77%,其余参数贡献均 <5%,p 值 >0.05 不显著'。"

"用 pandas 做特征工程,sklearn RandomForest + PermutationImportance 双保险排序,scipy 偏相关+ANOVA,matplotlib 出 6 图+报告,存 results/,"我开工程,"数据自包含,合成一批 86 组 SLM 工艺试验数据,下载就能跑。"

敲了行原型:

# 目标: 从 12 个工艺参数中筛选对孔隙率贡献最大的关键因子

# 方法: RandomForest 特征重要性 + Permutation Importance + 偏相关检验

# 输出: 关键参数排序 + 显著性标记 + 缩参建议

"完整版 OOP 封好,"我说,"数据加载器、特征分析器、参数筛选器、可视化器、决策链路,输出关键因子排名+6图+报告。"

小周凑近看:"那以后看报告:激光功率贡献 41.2%(p<0.001),扫描速度 22.8%(p<0.01),层厚 13.5%(p<0.01), hatch 间距 8.1%(p<0.05),其余 7 个参数贡献合计 <15% 且不显著。建议:DOE 聚焦功率(180-280W)×速度(800-1500mm/s)×层厚(20-40μm) 三因子响应面,其余参数固定在中值。试验矩阵从 12 因子全析交缩到 3 因子 Box-Behnken,试验组数从 50+ 砍到 15 组。"

"对,"我接话,"增材制造不是'试出来的',是'算出来的'。数字孪生里挂工艺参数敏感度节点,这套就是工艺员的'缩参望远镜'——12 个旋钮,一眼看出哪三个值得拧。"

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

场景设定:金属 3D 打印(SLM/EBM)中,内部孔隙率直接影响零件致密度和力学性能。工艺参数多达 10-15 个(激光功率、扫描速度、层厚、 hatch 间距、能量密度、基板温度、保护气流量、扫描策略、粉末特性、环境湿度等),参数间存在强耦合,传统"单因子轮换试错"效率极低且难以识别关键因子。

现场原话(叙事化):

"不是我们不想系统优化,"小周说,"是参数太多了。激光功率、扫描速度、层厚、扫描间距、基板预热、保护气流量、扫描策略、粉末粒径……12 个旋钮,每个拧 3 档就是 3¹² = 53 万种组合,穷举到宇宙热寂。只能凭经验一个一个试,但试一次 8 小时打印加 2 小时 CT,一周最多 3 组。两年攒了 86 组数据,但没人从里面筛过'到底哪些参数真正影响孔隙率'。"

"最坑的是参数耦合,"小周补充,"能量密度 = 功率/(速度×层厚×间距),你调了功率等于同时动了能量密度。扫描速度快了热输入不够→未熔合孔隙,慢了过热→球化+气孔。 hatch 间距大了层间未熔合,小了热应力累积开裂。这些效应互相打架,凭经验根本分不清谁的贡献大。"

核心矛盾:"12 参数全析交试错 + 凭经验拍脑袋" 与 "数据驱动的参数筛选 + 全局特征重要性排序 + 统计显著性检验 + 缩参聚焦" 之间的断层。

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

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

增材制造(3D打印)技术:工艺参数优化 孔隙率与工艺窗口

先进制造技术基础:材料成型原理 熔池动力学与致密化

智能制造与数字孪生:工艺参数敏感度 高维参数降维筛选

柔性制造系统FMS与先进生产管理:试验设计(DOE) 缩参→聚焦关键因子

一句话总结:我们需要一个"SLM 孔隙试验数据→相关性分析+RandomForest+Permutation Importance+偏相关检验+ANOVA 参数筛选程序",用

"pandas" 做数据清洗/特征构造,

"numpy" 做方差分析,

"scikit-learn" RandomForest + PermutationImportance 全局排序,

"scipy" 偏相关+显著性检验,

"matplotlib" 画热力图+特征重要性+散点矩阵+三维曲面+分布+决策网络,

"networkx" 建推理链路,实现从"12 参数盲调"到"数据驱动的关键因子筛选+缩参建议+DOE 聚焦"。

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

3.1 问题本质:把 3D 打印想成"烤蛋糕"

把工艺参数想成烤蛋糕时调的旋钮:

* 激光功率 = 烤箱温度(高→烤焦/低→夹生)

* 扫描速度 = 烘烤时间(长→干/短→湿)

* 层厚 = 蛋糕胚厚度(厚→里面不熟/薄→太慢)

* 孔隙率 = 蛋糕里的气泡(气泡多→一捏就塌)

* 你的目标 = 从 12 个旋钮里找出"真正影响气泡数量的 3 个",其余别管

3.2 业务逻辑 → 代码映射

加载 SLM 孔隙试验数据

│

▼ SLMDataLoader (pandas)

读取表:

激光功率(W), 扫描速度(mm/s), 层厚(μm),

hatch间距(mm), 能量密度(J/mm³),

基板预热(℃), 保护气流量(L/min),

扫描策略, 粉末D50(μm), 相对湿度(%),

孔隙率(%)

│

▼ FeatureAnalyzer (pandas + numpy)

特征工程:

能量密度 = 功率/(速度×层厚×间距)

比能量 = 功率/速度

热输入指数 = 功率×层厚/速度

扫描策略编码 (条带/棋盘/同心)

粉末粒径分组

│

▼ ParameterSelector (scikit-learn + scipy)

参数筛选(三重保险):

① RandomForest 特征重要性 → 全局排序

② Permutation Importance → 抗过拟合验证

③ 偏相关分析 + ANOVA → 显著性检验(p值)

综合得分 = 0.4×RF + 0.4×Perm + 0.2×偏相关

│

▼ SLMVisualizer (matplotlib + networkx)

可视化:

1. 参数-孔隙率相关性热力图

2. 特征重要性条形图(RF + Permutation)

3. 关键参数 vs 孔隙率散点(带回归线)

4. 三维参数曲面(功率×速度→孔隙率)

5. 孔隙率分布直方图

6. 参数筛选决策网络

│

▼ SyntheticSLMData (numpy)

合成数据:

86组工艺试验

孔隙率 = f(功率,速度,层厚,间距,...) + 噪声

关键因子: 功率(主效)>速度>层厚>间距

可复现

3.3 为什么不能"全参数 DOE"

视角 问题

12 因子全析交 2¹² = 4096 组,打印到明年

单因子轮换 忽略交互效应,找到的是假最优

数据驱动筛选 从历史数据找关键因子

三重排序 RF + Permutation + 统计检验

缩参聚焦 12→3 因子,DOE 组数砍 70%

3.4 分析前后对比

维度 传统方式 本程序

参数筛选 凭经验/文献 数据驱动三重排序

试验效率 盲调 50+ 组 聚焦 3 因子 15 组

置信度 "大概是这个" p 值 + 置信区间

决策依据 拍脑袋 统计显著性量化

四、OOP 代码实现

4.1 项目结构

slm_porosity_selector/

├── slm_porosity_selector/

│ ├── __init__.py

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

│ ├── feature_analyzer.py # 特征工程+相关性

│ ├── parameter_selector.py # 参数筛选(三重保险)

│ ├── slm_visualizer.py # 可视化

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

├── tests/

│ ├── __init__.py

│ └── test_slm.py

├── results/

│ ├── correlation_heatmap.png

│ ├── feature_importance.png

│ ├── key_param_scatter.png

│ ├── parameter_surface.png

│ ├── porosity_distribution.png

│ ├── selection_network.png

│ ├── selection_detail.csv

│ └── porosity_report.txt

└── run_slm.py

4.2 核心源码

<details>

<summary></summary>

"""SLM 孔隙试验数据加载器"""

import pandas as pd

from pathlib import Path

from typing import Optional

class SLMDataLoader:

"""读取 SLM 工艺试验数据"""

def __init__(self, filepath: str = "slm_porosity_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 = ["laser_power_w", "scan_speed_mms", "layer_thickness_um",

"hatch_spacing_mm", "porosity_pct"]

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

if miss:

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

num_cols = ["laser_power_w", "scan_speed_mms", "layer_thickness_um",

"hatch_spacing_mm", "porosity_pct"]

for c in num_cols:

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

df = df.dropna(subset=["porosity_pct"]).reset_index(drop=True)

return df

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

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

s += f"孔隙率范围: {df['porosity_pct'].min():.3f}% - {df['porosity_pct'].max():.3f}%\n"

s += f"功率范围: {df['laser_power_w'].min():.0f} - {df['laser_power_w'].max():.0f} W\n"

s += f"速度范围: {df['scan_speed_mms'].min():.0f} - {df['scan_speed_mms'].max():.0f} mm/s"

return s

</details>

<details>

<summary></summary>

"""特征工程 + 相关性分析 (pandas + numpy)"""

import numpy as np

import pandas as pd

from typing import List, Dict

from scipy import stats

class FeatureAnalyzer:

"""构造 SLM 物理特征 + 相关性矩阵"""

def __init__(self):

pass

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

result = df.copy()

# 能量密度 (J/mm³)

result["energy_density"] = (

result["laser_power_w"] /

(result["scan_speed_mms"] * result["layer_thickness_um"] / 1000 *

result["hatch_spacing_mm"])

)

# 比能量 (J/mm)

result["specific_energy"] = (result["laser_power_w"] /

result["scan_speed_mms"])

# 热输入指数

result["thermal_input"] = (result["laser_power_w"] *

result["layer_thickness_um"] /

result["scan_speed_mms"])

# 扫描策略编码

if "scan_strategy" in result.columns:

strat_map = {"strip": 0, "checker": 1, "spiral": 2, "island": 3}

result["strategy_code"] = result["scan_strategy"].map(

lambda x: strat_map.get(str(x).lower(), 0))

else:

result["strategy_code"] = 0

# 粉末粒径分组

if "powder_d50_um" in result.columns:

result["powder_fine"] = (result["powder_d50_um"] < 30).astype(int)

else:

result["powder_fine"] = 0

# 湿度等级

if "humidity_pct" in result.columns:

result["humidity_high"] = (result["humidity_pct"] > 45).astype(int)

else:

result["humidity_high"] = 0

return result

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

return [

"laser_power_w", "scan_speed_mms", "layer_thickness_um",

"hatch_spacing_mm", "energy_density", "specific_energy",

"thermal_input", "strategy_code", "powder_fine",

"humidity_high",

]

def correlation_matrix(self, df: pd.DataFrame,

features: List[str]) -> pd.DataFrame:

"""Pearson 相关矩阵"""

cols = features + ["porosity_pct"]

return df[cols].corr(method="pearson")

def partial_correlation(self, df: pd.DataFrame,

features: List[str]) -> Dict:

"""偏相关分析(控制其余变量后, 单变量与孔隙率的关系)"""

results = {}

y = df["porosity_pct"].values

for feat in features:

x = df[feat].values

# 简单偏相关: 残差法

other_feats = [f for f in features if f != feat]

if len(other_feats) == 0:

r, p = stats.pearsonr(x, y)

else:

X_other = df[other_feats].values

# 回归 x ~ X_other

beta_x = np.linalg.lstsq(X_other, x, rcond=None)[0]

resid_x = x - X_other @ beta_x

# 回归 y ~ X_other

beta_y = np.linalg.lstsq(X_other, y, rcond=None)[0]

resid_y = y - X_other @ beta_y

r, p = stats.pearsonr(resid_x, resid_y)

results[feat] = {"partial_r": float(r), "p_value": float(p)}

return results

</details>

<details>

<summary></summary>

"""参数筛选 (scikit-learn + scipy)"""

import numpy as np

from typing import Dict, List

from sklearn.ensemble import RandomForestRegressor

from sklearn.inspection import permutation_importance

from sklearn.model_selection import cross_val_score

from scipy import stats

class ParameterSelector:

"""三重保险参数筛选"""

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

self.random_state = random_state

self.rf_model_ = None

def fit_rf(self, X: np.ndarray, y: np.ndarray) -> RandomForestRegressor:

"""RandomForest 训练"""

self.rf_model_ = RandomForestRegressor(

n_estimators=200,

max_depth=8,

min_samples_leaf=3,

random_state=self.random_state,

)

self.rf_model_.fit(X, y)

return self.rf_model_

def rf_importance(self, feature_names: List[str]) -> Dict:

"""RF 特征重要性"""

if self.rf_model_ is None:

raise ValueError("模型未训练")

imp = dict(zip(feature_names,

self.rf_model_.feature_importances_))

return dict(sorted(imp.items(), key=lambda x: x[1], reverse=True))

def permutation_importance_score(self, X: np.ndarray,

y: np.ndarray,

feature_names: List[str]) -> Dict:

"""Permutation Importance"""

if self.rf_model_ is None:

raise ValueError("模型未训练")

perm = permutation_importance(

self.rf_model_, X, y,

n_repeats=20,

random_state=self.random_state,

scoring="r2"

)

result = {}

for i, name in enumerate(feature_names):

result[name] = {

"importance_mean": float(perm.importances_mean[i]),

"importance_std": float(perm.importances_std[i]),

}

return dict(sorted(result.items(),

key=lambda x: x[1]["importance_mean"],

reverse=True))

def anova_f_test(self, X: np.ndarray, y: np.ndarray,

feature_names: List[str]) -> Dict:

"""ANOVA F-test (单变量显著性)"""

results = {}

for i, name in enumerate(feature_names):

f_stat, p_val = stats.f_oneway(

X[:, i], y # 简化: 实际应分组

)

# 用 pearsonr 替代(连续变量)

r, p = stats.pearsonr(X[:, i], y)

results[name] = {

"f_statistic": float(f_stat),

"p_value": float(p),

"pearson_r": float(r),

}

return results

def composite_score(self, rf_imp: Dict, perm_imp: Dict,

partial_corr: Dict,

feature_names: List[str]) -> Dict:

"""综合得分 = 0.4×RF + 0.4×Perm + 0.2×|偏相关|"""

composite = {}

for feat in feature_names:

rf_val = rf_imp.get(feat, 0)

perm_val = perm_imp.get(feat, {}).get("importance_mean", 0)

# 归一化 perm_val

max_perm = max([v.get("importance_mean", 0)

for v in perm_imp.values()] + [1e-6])

perm_norm = perm_val / max_perm

# 偏相关

partial_r = abs(partial_corr.get(feat, {}).get("partial_r", 0))

p_val = partial_corr.get(feat, {}).get("p_value", 1.0)

score = 0.4 * rf_val + 0.4 * perm_norm + 0.2 * partial_r

composite[feat] = {

"score": float(score),

"rf_importance": float(rf_val),

"perm_importance": float(perm_norm),

"partial_r": float(partial_r),

"p_value": float(p_val),

"significant": p_val < 0.05,

}

return dict(sorted(composite.items(),

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

def recommend_doe_factors(self, composite: Dict,

top_n: int = 3) -> List[str]:

"""推荐 DOE 聚焦的关键因子"""

sorted_feats = sorted(composite.items(),

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

return [feat for feat, _ in sorted_feats[:top_n]]

</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

from typing import Dict, List

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

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

class SLMVisualizer:

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

self.results_dir = Path(results_dir)

self.results_dir.mkdir(exist_ok=True)

def correlation_heatmap(self, corr_matrix: pd.DataFrame):

"""相关性热力图"""

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

im = ax.imshow(corr_matrix.values, cmap="RdBu_r",

vmin=-1, vmax=1, aspect="auto")

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

ax.set_yticks(range(len(corr_matrix.columns)))

ax.set_xticklabels(corr_matrix.columns, rotation=45, ha="right",

fontsize=9)

ax.set_yticklabels(corr_matrix.columns, fontsize=9)

# 标注数值

for i in range(len(corr_matrix.columns)):

for j in range(len(corr_matrix.columns)):

val = corr_matrix.values[i, j]

color = "white" if abs(val) > 0.6 else "black"

ax.text(j, i, f"{val:.2f}", ha="center", va="center",

color=color, fontsize=8)

plt.colorbar(im, ax=ax, label="Pearson r")

ax.set_title("参数-孔隙率相关性热力图", fontsize=13, fontweight="bold")

plt.tight_layout()

plt.savefig(self.results_dir/"correlation_heatmap.png",

dpi=150, bbox_inches="tight")

plt.close()

def feature_importance(self, rf_imp: Dict, perm_imp: Dict):

"""特征重要性(RF + Permutation)"""

fig, axes = plt.subplots(1, 2, figsize=(14, 6))

# RF

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

vals = [rf_imp[n] for n in names]

axes[0].barh(range(len(names)), vals[::-1],

color="#3498DB", edgecolor="black", height=0.6)

axes[0].set_yticks(range(len(names)))

axes[0].set_yticklabels(names[::-1], fontsize=9)

axes[0].set_xlabel("RF 特征重要性")

axes[0].set_title("RandomForest 重要性", fontsize=11, fontweight="bold")

axes[0].grid(axis="x", alpha=0.3)

# Permutation

perm_names = list(perm_imp.keys())[:8]

perm_vals = [perm_imp[n]["importance_mean"] for n in perm_names]

perm_errs = [perm_imp[n]["importance_std"] for n in perm_names]

axes[1].barh(range(len(perm_names)), perm_vals[::-1],

xerr=perm_errs[::-1],

color="#E74C3C", edgecolor="black", height=0.6)

axes[1].set_yticks(range(len(perm_names)))

axes[1].set_yticklabels(perm_names[::-1], fontsize=9)

axes[1].set_xlabel("Permutation Importance (±std)")

axes[1].set_title("Permutation 重要性", fontsize=11, fontweight="bold")

axes[1].grid(axis="x", alpha=0.3)

plt.suptitle("参数重要性排序 (双重验证)", fontsize=14, fontweight="bold")

plt.tight_layout()

plt.savefig(self.results_dir/"feature_importance.png",

dpi=150, bbox_inches="tight")

plt.close()

def key_param_scatter(self, df: pd.DataFrame,

key_params: List[str]):

"""关键参数 vs 孔隙率散点"""

n = len(key_params)

fig, axes = plt.subplots(1, min(n, 4), figsize=(5*min(n,4), 5))

if n == 1:

axes = [axes]

for i, param in enumerate(key_params[:4]):

if param not in df.columns:

continue

ax = axes[i]

ax.scatter(df[param], df["porosity_pct"],

c="#3498DB", alpha=0.6, s=40, edgecolors="black")

# 回归线

z = np.polyfit(df[param], df["porosity_pct"], 1)

p = np.poly1d(z)

x_line = np.linspace(df[param].min(), df[param].max(), 100)

ax.plot(x_line, p(x_line), "r--", linewidth=2)

ax.set_xlabel(param, fontsize=10)

ax.set_ylabel("孔隙率 (%)", fontsize=10)

ax.set_title(f"{param} vs 孔隙率\nR²≈{np.corrcoef(df[param], df['porosity_pct'])[0,1]**2:.3f}",

fontsize=10)

ax.grid(alpha=0.3)

plt.tight_layout()

plt.savefig(self.results_dir/"key_param_scatter.png",

dpi=150, bbox_inches="tight")

plt.close()

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

"""三维参数曲面(功率×速度→孔隙率)"""

from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(10, 8))

ax = fig.add_subplot(111, projection="3d")

scatter = ax.scatter(df["laser_power_w"], df["scan_speed_mms"],

df["porosity_pct"],

c=df["porosity_pct"], cmap="viridis",

s=50, edgecolors="black")

ax.set_xlabel("激光功率 (W)")

ax.set_ylabel("扫描速度 (mm/s)")

ax.set_zlabel("孔隙率 (%)")

ax.set_title("功率×速度→孔隙率 三维分布", fontsize=12, fontweight="bold")

plt.colorbar(scatter, ax=ax, label="孔隙率 (%)")

plt.tight_layout()

plt.savefig(self.results_dir/"parameter_surface.png",

dpi=150, bbox_inches="tight")

plt.close()

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

"""孔隙率分布"""

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

ax.hist(df["porosity_pct"], bins=20, color="#3498DB",

edgecolor="black", alpha=0.7, density=True)

mean_p = df["porosity_pct"].mean()

ax.axvline(mean_p, color="red", linestyle="--", linewidth=2,

label=f"均值 {mean_p:.3f}%")

ax.axvline(0.5, color="orange", linestyle="--", linewidth=2,

label="标准要求 ≤0.5%")

ax.set_xlabel("孔隙率 (%)", fontsize=12)

ax.set_ylabel("密度", fontsize=12)

ax.set_title("孔隙率分布", fontsize=13, fontweight="bold")

ax.legend(fontsize=11)

ax.grid(alpha=0.3)

plt.tight_layout()

plt.savefig(self.results_dir/"porosity_distribution.png",

dpi=150, bbox_inches="tight")

plt.close()

def selection_network(self):

"""参数筛选决策网络"""

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

G = nx.DiGraph()

nodes = [

("试验数据", "input"),

("特征工程", "process"),

("RF重要性", "model"),

("Permutation", "model"),

("偏相关检验", "model"),

("综合排序", "optimize"),

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

返回列表