news 2026/9/25 15:06:37

Bagging集成深度学习模型提升财务造假预测AUC的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Bagging集成深度学习模型提升财务造假预测AUC的完整实践

简介:面向机器学习与财务风控从业者,这套基于Bagging与深度学习的上市公司财务数据造假预测方案,完整覆盖从制造业、其他行业特征工程到二分类模型训练与预测的全流程,适合数据挖掘竞赛、毕业设计或企业财务异常识别场景的复现与二次开发。包内共33个文件,以15个CSV数据文件、9个Python源码脚本、3张效果图片为主,另附Excel附件、PDF说明与运行文档,整体约35.46MB,目录按数据、特征、模型、预测等模块组织,便于按需取用。已有191人学习。资源实现了SMOTE过采样与四种树模型的特征重要性集成筛选,并给出多层感知机、残差网络与Cross网络组成的DCRN模型及Bagging集成代码,包含特征榜单、ROC曲线、训练好的模型文件与运行说明,可帮助读者理解特征筛选、交叉组合、梯度消失缓解和降方差集成的完整思路,快速迁移到真实财务异常检测场景。

1. 财务造假预测为什么是 Bagging + 深度学习的舞台:一个基模型不够用的真实原因

先说结论:单靠一个深度学习模型去识别上市公司财务造假,在公开数据集上通常只能做到 0.75~0.78 的 AUC;而用 Bagging 把 8~12 个结构相同但训练子集不同的基模型集成起来,同一个测试集上 AUC 能抬到 0.85 以上,预测分数的方差还能缩减一半左右。这个差距不是玄学,而是财务造假数据本身的分布特征决定的:正样本占比通常不到 3%,造假样本和正常样本在指标空间里高度重叠,造假手段还会随年份和市场规则漂移。这些恰好是单个高容量深度模型最容易过拟合、最容易把记忆当成泛化的场景。

本文要拆解的,是一套“源码 + 数据集 + 模型 + 运行说明”式的完整方案。我会从监管处罚公告和三大报表出发,一步步构造监督学习数据集,训练一个以深度神经网络为基学习器的 Bagging 集成模型,给出可直接复现的基线参数,并把最容易翻车的五个位置写透。适合手里握着审计线索或风控诉求、准备实际投入这个方向的从业者;如果你是第一次接触财务造假预测,这篇也能让你少走一个月的弯路。

2. 把造假预测切成监督问题:标签、特征与时间线设计

2.1 造假标签的生成:处罚公告、追溯期与窗口对齐

构造数据集的第一步,是从监管处罚公告里提取“谁、从哪一年、到哪一年”。我既用过手工整理版,也写过解析公告的脚本,核心逻辑是相通的:公告里通常有一句“涉嫌信息披露违法违规——在 XXXX 年至 XXXX 年定期报告中存在虚假记载”,这句话就决定了正样本的区间。需要特别注意的是:一个处罚决定覆盖多个年度时,要为每个年度各生成一条正样本,而不是只给一条。

import pandas as pd # penalties.csv 字段:stock_code, begin_dt, end_dt # 该表来自处罚公告的结构化结果,不是原始公告文本 penalties = pd.read_csv("penalties.csv", parse_dates=["begin_dt", "end_dt"]) records = [] for _, row in penalties.iterrows(): # 造假区间覆盖到的每一个财年,各生成一个正样本 for year in range(row["begin_dt"].year, row["end_dt"].year + 1): records.append({ "stock_code": row["stock_code"], "fiscal_year": year, "target": 1, }) positives = pd.DataFrame(records)

这段代码的关键是窗口对齐。处罚公告公布的造假年份,和模型真正能看到的报表数据之间存在时间差:比如一家公司 2018 年和 2019 年造假,2021 年才被处罚,那么模型在 2019 年底并不知道这个事实,只能用截至 2019 年年报披露日的数据做特征。后续合并特征时,必须把披露日期作为 join 的锚点,而不是把标签和特征简单地按年份对齐,否则就会出现用自己的“未来”去预测自己的“过去”这种标签泄漏——这是造假预测项目里最常见、也最隐蔽的错误。

正样本构造完,负样本就是样本池里所有未被处罚的(stock_code, fiscal_year)组合。一个容易忽视的问题是:有些公司造假没被发现,不等于没有造假,它们被当成负样本只是给定数据集约束下的近似。这个问题没有完美解法,但对模型的影响有限,因为漏网的“假阴性”样本在全部负样本里占比很小,而且单个噪声样本对 Bagging 集成的干扰远小于它对单模型的干扰。

2.2 特征工程:从三大报表和审计意见里抽取 40 个指标

标签定好后,就要把每个(stock_code, fiscal_year)变成定长的数值向量。我的经验是:不要直接把原始会计科目喂给深度网络,哪怕深度模型理论上能自己学出组合特征。原因有两个:一是原始科目分布长尾极重,个别公司营收几十亿上百亿,多数公司只有几亿,不取对数或不做比率归一化,网络注意力会被头部样本带走;二是原始科目之间线性相关性太高,深度模型在这种输入上容易学到表层规律,而不是造假行为的结构性信号。

常见做法是构造比率特征和差分特征。我习惯把基线特征集控制在 40 个左右,核心包括:应收账款 / 营业收入、存货 / 营业收入、经营现金流净额 / 净利润、非经常性损益 / 净利润、应收账款增速与营收增速之差、毛利率的跨年波动、存货周转天数变化、资产负债率、流动比率、审计意见类型(虚拟变量)、高管是否变更、是否收到过问询函。

import numpy as np def build_features(statements: pd.DataFrame, external: pd.DataFrame) -> pd.DataFrame: # statements: 长表,每行是 (stock_code, report_date, item, value) # external: 审计意见、高管变更、问询函数字表 pivoted = statements.pivot_table( index=["stock_code", "report_date"], columns="item", values="value", aggfunc="first" ).reset_index() eps = 1e-6 pivoted["ar_to_revenue"] = ( pivoted["accounts_receivable"] / (pivoted["revenue"] + eps) ) pivoted["inventory_to_revenue"] = ( pivoted["inventory"] / (pivoted["revenue"] + eps) ) pivoted["op_cashflow_to_profit"] = ( pivoted["op_cash_flow"] / (pivoted["net_profit"] + eps) ) pivoted["nonrecurring_ratio"] = ( pivoted["nonrecurring_gain_loss"] / (pivoted["net_profit"] + eps) ) pivoted["gross_margin"] = ( (pivoted["revenue"] - pivoted["operating_cost"]) / (pivoted["revenue"] + eps) ) pivoted["debt_ratio"] = ( pivoted["total_liabilities"] / (pivoted["total_assets"] + eps) ) pivoted["quick_ratio"] = ( (pivoted["current_assets"] - pivoted["inventory"]) / (pivoted["current_liabilities"] + eps) ) return pivoted.merge( external, on=["stock_code", "report_date"], how="left" ).fillna(0.0)

这段代码背后的逻辑是:把绝对数值换成比值,消除公司规模的影响。eps = 1e-6是为了分母为零时不会直接出inf,这是财务数据处理里最常见的细节问题。所有比率列拼接后,还要做一步跨年差分——例如 T 年应收账款增速与 T-1 年营收增速的差,这个差在真实造假样本上往往显著为正,因为它捕捉的是“收入没怎么涨、应收账款先涨了”的异常信号。这一步常用groupby("stock_code").diff()实现,建议在训练集和测试集上分别执行,避免把全局统计量混入训练过程。

2.3 样本划分与类别不平衡:先定时间线再讲算法

财务数据预测最忌讳随机划分训练集和测试集。同一家公司的两个年度样本高度相关——2018 年的报表数据一定是 2019 年样本的输入一部分,随机划分会把这种序列相关性带进验证结果,造成 AUC 虚高。常见做法是:按自然年切分,某年之前的所有样本进训练,之后的进测试,并且保证同一个股票代码的所有样本只出现在一侧。

train_year_max = 2017 train_df = samples[samples["fiscal_year"] <= train_year_max] test_df = samples[samples["fiscal_year"] > train_year_max]

这个切分看起来简单,实际上是最重要的一道防线。造假预测场景里,正样本质量远比数量重要:几千个正常样本加上 80 个真实造假样本,信息量远大于加上 800 个疑似但不干净的样本。类别不平衡的处理我一般分两步走:先让训练集里正样本的比重控制在 10%~20%(通过负样本欠采样),再用集成中每个基模型使用不同随机子集的方式保留多样性。我不太会在数据层做 SMOTE 这种插值,因为财务指标的造假信号很稀薄,插值容易生成“跨界样本”,骗得过模型但骗不过真实场景。

3. 用 Bagging 包装深度模型:训练、集成与预测的最小实现

3.1 为什么 Bagging 能压住深度模型在财务数据上的方差

单个深度神经网络是高方差估计器:同样的数据、换个随机种子,训练出来的预测分数可以差 0.05 个 AUC。这在风控场景里很要命,因为风控需要一个稳定的分数,不是“这次碰巧跑出来的好成绩”。Bagging 的核心思想是构造多个分布近似的子数据集,分别训练基模型,再把预测结果做平均或投票,最终预测的方差随基模型数量近似线性下降。财务造假数据正样本少、数据分布不对称,这种场景下 Bagging 比 Boosting 更稳:Boosting 会在异常样本上不断放大权重,而造假样本本身噪声很大,权重放大到最后往往拟合的是处罚边界的不确定部分,而不是造假行为本身。

从另一个角度看,Bagging 也天然适配深度网络的“随机性”本质。每个基模型用不同子集启动,相当于在模型空间里做了一次采样;最后平均时,每个模型的偏置被保留,方差被抵消。对于造假预测这种需要给出稳定概率分数的任务,集成后的输出排序更稳定,阈值也更跟手。

3.2 构造子训练集:自助采样与分层采样

实现 Bagging 深度模型最常见有两种构造子集的方式:纯自助采样和分层采样。纯自助每次从原始训练集随机有放回地抽 n 个样本,正样本占比会随抽样波动,基模型之间差异大,但有些基模型可能正样本占比过低,学不到造假信号。我一般用分层采样:每次固定从正样本里抽 70%~80%,负样本按正样本数量的 4~6 倍随机抽取,这样每个基模型都有足够且相似的正样本。

from sklearn.utils import resample n_models = 10 base_sample_ratio = 0.8 n_positive = int(train_df["target"].sum()) n_negative_per_model = n_positive * 5 sub_sets = [] for i in range(n_models): pos = train_df[train_df["target"] == 1] neg = train_df[train_df["target"] == 0] pos_sub = resample( pos, replace=False, n_samples=int(len(pos) * base_sample_ratio), random_state=42 + i ) neg_sub = resample( neg, replace=False, n_samples=min(n_negative_per_model, len(neg)), random_state=100 + i ) sub_sets.append(pd.concat([pos_sub, neg_sub]))

这段代码有两个参数值得单独说。base_sample_ratio控制每个基模型看到了多少比例的正样本,选 0.8 是平衡精度和召回率的常用值;n_negative_per_model控制类别不平衡程度,设成正样本的 5 倍,是为了让每个基模型不会被少数几个异常样本牵制,也不会因为负样本太多把训练时间拖到不可接受。random_state=42 + i这个细节最容易被忽略——如果不给每次抽样不同的随机种子,十个基模型拿到的是完全相同的子集,Bagging 就会退化成训练了十个一样的模型,预测平均之后毫无增益。这不仅浪费算力,还会让模型的稳定性和单体模型完全一致,等于白绕了一圈。

3.3 基分类器设计:用 MLP 和 TCN 各做一版再融合

基学习器选型上,财务造假预测最常用的是多层感知机(MLP),因为特征已经是定长向量,不需要卷积或序列模型。MLP 的优势在于实现简单、训练稳定、超参数敏感度低;缺点是忽略了特征之间的时间结构。如果你想更进一步,可以把连续三年的特征拼成序列,用 TCN(时间卷积网络)作为基学习器,但 TCN 的训练时间会翻好几倍,在小样本上并不一定比 MLP 更好。

这里给出一个完整的 MLP 基模型定义,包含两个连续的线性层、批归一化、Dropout 和输出层。

import tensorflow as tf from tensorflow.keras import layers, models, regularizers def build_mlp(input_dim: int) -> tf.keras.Model: inputs = layers.Input(shape=(input_dim,), name="financial_features") x = layers.BatchNormalization()(inputs) x = layers.Dense( 128, activation="relu", kernel_regularizer=regularizers.l2(1e-5) )(x) x = layers.Dropout(0.3)(x) x = layers.Dense( 64, activation="relu", kernel_regularizer=regularizers.l2(1e-5) )(x) x = layers.Dropout(0.3)(x) outputs = layers.Dense(1, activation="sigmoid")(x) model = models.Model(inputs, outputs) model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3), loss="binary_crossentropy", metrics=[tf.keras.metrics.AUC(name="auc")] ) return model

结构上没有特别花哨的地方,但每个组件都有针对性。BatchNormalization 放在输入端,是因为财务特征经过标准化后仍可能有小批量内的分布偏移,它能避免模型在训练初期被少数极端样本带偏。两个 Dropout 层分别放在中间层之后,是为了在基模型内部做正则化,让 Bagging 之外再叠加一层抗过拟合能力。L2 正则的系数只给 1e-5,不能太大,否则在造假样本占比极低的情况下,模型会倾向于把所有样本预测成 0,网络结构再好也学不到有效信号。

3.4 训练循环、模型保存与投票/平均策略

Bagging 训练循环比较直接:依次在子集上调用基模型 fit,然后存到一张列表里,最终预测时对所有模型输出的概率做算术平均。需要强调的细节是:在下采样后的子集上训练时,每个基模型的验证集必须用原始测试集,不能用子集里分出来的验证集;否则验证分数会严重高估。

models = [] for i, sub in enumerate(sub_sets): sub = sub.sample(frac=1.0, random_state=1000 + i) X_sub = sub.drop(columns=["target"]).values.astype("float32") y_sub = sub["target"].values.astype("float32") base_model = build_mlp(input_dim=X_sub.shape[1]) base_model.fit( X_sub, y_sub, validation_data=(X_val, y_val), epochs=200, batch_size=64, callbacks=[ tf.keras.callbacks.EarlyStopping( monitor="val_auc", patience=15, mode="max", restore_best_weights=True ) ], verbose=0 ) models.append(base_model) base_model.save(f"models/bagging_mlp_{i:02d}.h5")

训练时用了早停,监控的是验证集 AUC 而不是 loss。原因是binary_crossentropy在严重不平衡的数据上数值上偏向多数类,loss 下降不直接等于分类能力提升;AUC 对类别比例不敏感,更适合作为早停的监控量。patience=15是财务小样本上比较常用的值,数据量足够大时可以缩小到 10。注意每个基模型都用不同的 shuffle 种子,虽然 MLP 对样本顺序不敏感,但复现时多一重随机性控制,就少一个不确定性来源。

预测阶段的常见做法是对每个模型输出的概率取平均。这里用mean而不是硬投票,因为财务造假打分场景要的是概率意义上的排序,硬投票会把许多打分 0.5 附近的样本直接判给多数类;平均概率保留连续分数,方便之后设定阈值做不同风险等级分类。

import numpy as np def ensemble_predict(models, X): preds = np.column_stack([m.predict(X, verbose=0).ravel() for m in models]) return preds.mean(axis=1)

4. 参数应该怎么设:一组可直接复现的基线参数

4.1 网络结构与正则化:Dropout、早停、BatchNorm

我的调参习惯是:先把网络结构固定下来,再调 Bagging 层面的参数,避免两层超参互相干扰。基线网络固定为:输入层 -> 128 个神经元 -> 64 个神经元 -> 输出层,激活函数用 ReLU,输出层用 Sigmoid。128 这个宽度是兼顾表达能力和过拟合风险的常用起点;财务特征通常只有 40 维左右,128 个神经元已经能拟合很复杂的非线性边界,再增加宽度对 AUC 的提升非常有限,训练时间倒是近似线性增长。

正则化三件套是 BatchNormalization、Dropout(0.3)、L2(1e-5)。如果训练集正样本数量只有几十个,Dropout 建议从 0.3 提高到 0.5,L2 保持不变;如果发现验证集 AUC 在小样本下波动很大,优先调整 BatchNormalization 的 momentum——默认 0.99 在小批量上不稳定,可以降到 0.9。训练轮数和早停配合使用,patience 设置在 15~20 比较合适;太小的 patience 在财务数据上太敏感,经常因为一个 mini-batch 的波动过早停止。

# 正则化参数基线速查(作者常用值) # -------------------------------------------- # 隐藏层:2 层,128 -> 64 个神经元 # Dropout 率:0.3(正样本极少时提到 0.5) # L2 系数:1e-5 # BatchNorm momentum:0.9(默认 0.99 小批量不稳) # 学习率:1e-3 # 早停 patience:15,监控 val_auc # batch_size:64(数据量小可用 32) # --------------------------------------------

4.2 Bagging 轮数与采样率:算算你的训练成本

Bagging 轮数从 10 起步,先小规模跑通流程,再往 30 加。多数公开实验结果表明,基模型数量超过 15~20 个后,预测分数平均的方差下降幅度逐渐趋缓,继续增加模型主要带来训练时间和磁盘占用。考虑到财务造假数据集通常只有几千到几万行样本,单个 MLP 在 CPU 上 30 秒内就能训练完,跑 30 个模型也就是 15 分钟左右;如果运行环境有 GPU,这个时间会缩短到一两分钟。

采样率直接决定每个基模型看到的正样本数量和负样本比例。前面用了base_sample_ratio=0.8、正负比例 1:5,这个组合适合正样本数量在 80~200 之间的场景。正样本少于 50 时,建议把采样比例调到 0.9,正负比例放宽到 1:3,因为此时每个基模型能看到的正样本太少,即使有 Bagging,单个基模型也很容易把仅有的正样本当成噪声记下来。正负比例在 1:5 到 1:7 之间通常是最稳定的区间;过高的负样本比例会让每个基模型的训练时间变长,AUC 提升有限,而且会让阈值选择阶段过度偏向精确率,漏掉真正的造假公司。

4.3 决策阈值怎么定:召回率优先还是精确率优先

模型输出是一个 0~1 之间的概率,拿多少作为“疑似造假”的分界点,需要在验证集上单独选。选阈值之前先明确业务目标:审计场景宁可多一些疑似线索,把阈值压低一点,用召回率换人工核查成本;投资风控场景则相反,建议优先精确率,避免公开名单出现过多误报造成声誉成本。这两种目标对应不同的阈值选择方法。

from sklearn.metrics import precision_recall_curve probs_val = ensemble_predict(models, X_val) precision, recall, thresholds = precision_recall_curve(y_val, probs_val) f1_scores = 2 * precision * recall / np.maximum(precision + recall, 1e-6) best_idx = np.argmax(f1_scores) best_threshold = thresholds[best_idx]

用 F1 选阈值是中性默认值;如果业务画像更匹配审计场景,可以在 F1 阈值基础上向低阈值移动 0.05~0.1,让召回率优先。这里用precision_recall_curve而不是 ROC,是因为财务造假标签占比极低,ROC 曲线在假阳性率很低的一段非常乐观,无法反映少数类预测的真实困境;PR 曲线对正样本的预测质量更敏感,也更符合审计复核的直觉。

5. 复现过程中最容易踩的五个坑:现象、根因与解决

5.1 标签泄漏:把未来信息混进特征

现象:训练 AUC 0.99、测试 AUC 0.98,漂亮得可疑;一换到新年度数据上预测,AUC 直接掉到 0.65。

原因:特征构造时把处罚公告日期之后的报表数据也放进特征了,或者用全样本均值做了标准化。模型学到的是“处罚后调整过的报表长什么样”,而不是“造假行为长什么样”。

解决:严格按披露日期拼接数据,所有特征必须在样本截止日之前可见。用时间切分能挡住一部分泄漏,但泄漏的产生点在特征工程前端,必须在构造特征时就控制住,不能只靠样本划分兜底。

5.2 类别不平衡下模型全部预测为正常

现象:验证集 AUC 有 0.82,但预测分数分布明显压在 0.3 以下,没有任何一家公司被判定为疑似造假;检查每个基模型,发现输出概率的均值连 0.5 都不到。

原因:欠采样后正负比例还是 1:10,负样本绝对量太大,交叉熵损失主导了训练方向,模型学到的最优解就是全部输出低概率。

解决:把正负采样比调到 1:5 以内,并给损失函数增加class_weight。经验上class_weight={0: 1.0, 1: 3.0}是比较不容易过头的起点;同时确保早停监控的是val_auc而不是val_loss。val_loss在负样本主导的验证集上会误导早停时机。

5.3 时间穿越:标准化参数用全量样本拟合

现象:测试集 AUC 很高,但模型上线后每个月分数都在漂,方向越来越差。

原因:归一化时用了全样本的均值和标准差,把未来几个月的分布信息泄漏进了历史预测。

解决:StandardScaler 或任何归一化器只能用训练集 fit,再 transform 验证集和测试集。比较稳妥的做法是把归一化步骤写进 sklearn Pipeline,用同一个 pipeline 处理训练、验证、测试三份数据。

from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_val_scaled = scaler.transform(X_val) X_test_scaled = scaler.transform(X_test)

5.4 财务数据的分布漂移:旧模型在新年份失效

现象:模型在 2008~2017 年数据上 AUC 有 0.87,在 2018~2021 年数据上只有 0.71;进一步看,错判的样本集中在某些行业或新会计政策下的公司。

原因:财务造假手法和会计准则都在演化。比如新收入准则实施后,收入确认方式变化导致多个收入和应收类比率的统计分布整体下移,旧模型学到的是旧准则下的特征边界。

解决:训练集里固定加入最近 N 年数据的滚动窗口,不要用全部历史数据一次训完。我一般把窗口设为 8~10 年,每年重新训练一次,并保留最近一年的 Bagging 模型作为线上版本。这是维护这类模型最朴素也最有效的方案。

5.5 复现失败:随机种子与依赖版本

现象:按说明跑源码,每次结果都对不上;甚至同一台机器上两次运行,AUC 都有明显差异。

原因:train_test_split、resample、numpy 操作、TensorFlow 初始化,每一处都引入随机性。最常见的复现失败是:保存了模型,但没有同步保存每个基模型的采样索引。

解决:在全流程入口设置三个种子:random.seed(42)、np.random.seed(42)、tf.random.set_seed(42),每次resample固定 random_state。如果已经保存了模型但没保存子集索引,基线很难完全复现。所以源码包里的模型、数据集、运行说明必须一起交付,缺了任何一部分,结果都可能变成另一套行为。依赖版本上,TensorFlow 2.x 在 GPU 下有非确定性算法问题,如果必须精确保留训练过程,说明里冻结tensorflow-cpu和numpy的具体版本号,比只写“TensorFlow 2.x”靠谱得多。

6. 进阶验证:滚动回测、可解释性与部署注意点

6.1 用滚动时间窗口回测替代随机划分

随机划分对财务时序数据来说基本不可信。更接近线上真实表现的验证方式是滚动窗口回测:第一次用 2010~2014 训练、2015 做测试;第二次用 2010~2015 训练、2016 做测试;依此类推,把每年的预测分数拼在一起画 PR 曲线。这种方式得到的指标通常会低于随机划分,但它更接近模型上线后的真实水平。滚动回测还能暴露一个隐藏问题:在造假处罚率高的年份,模型指标表现往往更好;到了处罚率低的年份,PR 曲线会剧烈下探。这不是模型退化,而是样本先验概率变化导致的。汇报效果时把每年的正样本数量一起报告,接手的人就不会被单年指标误导。

6.2 从黑匣子到可解释:用 SHAP 找到关键造假特征

财务造假预测在审计场景落地时,办案人员不会接受一个完全不能解释的黑匣子。我一般会在 Bagging 预测概率上做 SHAP 分析,输出每个样本的特征贡献排序。因为 Bagging 集成了多个模型,SHAP 值要传模型列表逐个计算再取平均,这个做法理论上只是近似,实践上却非常好用。

import shap import numpy as np def shap_for_bagging(models, X_reference, X_explain): all_shap = [] for m in models: explainer = shap.Explainer(m, X_reference) all_shap.append(explainer(X_explain).values) return np.mean(all_shap, axis=0) shap_values = shap_for_bagging(models, X_train_scaled, X_test_scaled)

SHAP 结果常见的呈现方式是 beeswarm 图和单样本 force plot。结合我实际复核过的项目,排名靠前的特征通常包括经营现金流净额 / 净利润、应收账款增速与营收增速之差、非经常性损益占比,这跟审计实务里“利润与现金流长期背离”的关注点吻合。这种一致性反过来也能验证模型学到的确是真信号,而不是某种偶然模式。

6.3 部署与运行说明里必须写清楚的三件事

其一是依赖清单。TensorFlow、numpy、pandas、scikit-learn 的版本要逐项锁死,requirements.txt里用==而不是>=。其二是目录结构。源码、数据集、模型、运行说明四个部分要互相独立,模型文件单独放——深度学习模型常有.h5和.keras两种版本,混在源码里容易在版本迁移时踩坑。其三是数据检查脚本。主流程运行前先做缺失值比例、异常日期、跨年重复计数、目标列占比统计,这些跟模型无关的小事,决定了一个方案能不能顺利交接给别人长期维护。

交付一份工程方案,最负责的方式不是把数据和模型打包了事,而是把上面三件事写进运行说明的开头,让接手的人按说明从原始数据到预测结果完整跑通一遍,再把预测结果与说明里的示例输出逐位对比。能对得上,才说明这个方案真正可复现。这也是我自己交付财务模型时反复踩坑换来的习惯,希望帮到你。

本文还有配套的精品资源,点击获取

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

C# 网络相关 API 汇总:Socket / TcpListener / TcpClient / UdpClient

一、整体层级架构&#xff08;核心认知&#xff09;从底层到上层依次递进&#xff0c;所有高层类均基于原生Socket封装&#xff1a;原生底层&#xff1a;Socket&#xff08;TCP/UDP通用&#xff0c;自由度最高&#xff09;高层封装&#xff1a;TCP体系&#xff1a;TcpListener&…

作者头像 李华
网站建设 2026/9/25 14:57:12

江苏食品级螺杆泵正规厂商源头工厂企业全景分析:省心选择指南

江苏食品级螺杆泵正规厂商源头工厂省心选择指南 食品级螺杆泵是食品生产加工领域用于高粘度、含颗粒食品介质输送的核心卫生级泵类设备&#xff0c;浙江久江泵业作为专业的食品级螺杆泵生产制造源头工厂&#xff0c;可提供合规稳定、适配多元食品加工场景的卫生级泵类产品与全流…

作者头像 李华
网站建设 2026/9/25 14:56:48

实测19个免费PPT工具:模板、在线编辑与AI生成怎么选

做汇报最头疼的从来不是内容本身&#xff0c;而是把内容塞进一个看起来不寒碜的PPT里。我见过太多同事对着空白幻灯片发呆两小时&#xff0c;最后交出来的东西还不如用Word直接投屏。过去半年我因为各种汇报需求&#xff0c;把市面上能搜到的免费PPT工具几乎试了个遍&#xff0…

作者头像 李华
网站建设 2026/9/25 14:53:04

昇腾Atlas 300V 24G部署YOLO:从硬件认知到工程实践

最近后台好几个朋友在同一个词上卡住了——atlas。有人以为是共享单车那个地图App&#xff0c;有人以为是某个开源数据库&#xff0c;结果点进来一看&#xff0c;好家伙&#xff0c;全是在问两件事&#xff1a;Atlas怎么部署YOLO&#xff0c;以及Atlas 300V 24G到底算不算运算加…

作者头像 李华