news 2026/9/13 16:46:34

VMD-Attention-LSTM时间序列预测:原理、源码与参数调优实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
VMD-Attention-LSTM时间序列预测:原理、源码与参数调优实战

简介:基于VMD-Attention-LSTM的时间序列预测模型完整项目包,面向深度学习初学者及需要完成课程设计、毕业设计的学生。内含VMD变分模态分解、Attention注意力机制与双层LSTM网络的完整搭建代码,以及数据预处理、训练、预测和模型权重保存逻辑,并配套项目说明文档与训练报告,可帮助快速理解时序预测建模全流程。包体共28个文件,以Python源码(.py)、Excel原始数据(.xlsx)、NumPy中间特征(.npy)、TensorFlow模型权重(.ckpt)及Word报告(.docx)为主,压缩包仅5.26MB,结构清晰,便于直接运行与二次开发。已有635人学习下载。资源重点演示了“用前30天数据预测第31天”的滑动窗口思路,并针对小数据集给出防止过拟合的设计方案,如使用Huber损失、Dropout层及五个VMD分解特征输入等。同时提供测试完成的训练与预测脚本,适合在现有代码基础上修改特征或网络结构,作为毕设、课设或项目初期演示的起点。

1. 先用问题把 VMD-Attention-LSTM 这个组合讲清楚

时间序列预测最让人头疼的不是模型不够深,而是同一个序列里混着好几种不同性质的波动:日周期、周周期、缓慢漂移的趋势、随机毛刺。LSTM 的记忆单元虽然有门控,但要它在同一组参数里同时拟合这些不同尺度的成分,结果往往是“趋势跟上了、细节糊了”。VMD 先把序列按频率拆开,让每个子序列相对平稳;Attention 再告诉 LSTM 在预测当前值时,输入窗口里哪几个历史时刻最重要;最后把各模态的预测叠加回去,得到完整预测。这套 VMD-Attention-LSTM 的 python 源码组合,本质上是把“信号分解”和“序列建模”两件事拆开做,每个环节都更容易调试。适合已经用 LSTM 做过基础预测、但卡在精度上的人,也适合想把论文方法改为工程实现的读者。我会讲清三个组件各自的边界,给出可运行的源码和参数调整思路。

2. 三个组件各自解决什么问题,为什么偏偏是它们

2.1 VMD 不是过滤器,是把序列拆成带物理含义的模态

VMD 的基本假设是:一段时间序列可以写成 K 个调幅-调频信号的叠加,每个信号有独立的中心频率和有限带宽。与 EMD 靠极值点包络逐步筛选不同,VMD 把分解写成约束变分问题,用交替方向乘子法迭代求解,把每个模态约束在中心频率附近的窄带内。这样做的直接好处是模态之间不会像 EMD 那样轻易混叠,中心频率分离得清楚,每个 IMF 的物理含义更明确。

为什么先分解再预测会提升 LSTM 的效果?因为 LSTM 对“多尺度并存”的输入并不擅长。给模型一段既包含小时级波动、又包含天级趋势的序列,它的门控单元需要同时追踪两种不同的时间常数,梯度回传时相互干扰,最后学到的往往是占能量最大的那个尺度。把信号拆成低频趋势、周期项和随机余项后,每个模态内部相对平稳,LSTM 只需专注单一时空尺度,训练难度明显下降。

需要澄清一个常见的误解:VMD 不是低通滤波器。低通滤波只留下低频成分,高频信息会被直接删除;VMD 会把高频分量也作为独立的模态输出,仍可对其单独建模。真正的问题出在高频模态上——它的信噪比很低,模型很容易把噪声的形状当成规律。我一般会把能量占比很小的几个高频分量合并成一个残余项,不单独预测,这样能减少整体模型的过拟合风险。

VMD 的分解质量高度依赖参数,尤其是模态数 K 和惩罚因子 alpha,这两个参数在第四章展开。这里先记住一个原则:模态应该是可解释的,而不是数学上漂亮。如果分解出的某个模态中心频率跳动频繁,说明 K 设多了,或 alpha 设小了。

2.2 Attention 在 LSTM 里到底加在哪一层

LSTM 最后一个时间步的隐状态只代表序列末尾的信息。对时间序列预测而言,目标值往往只与输入窗口中的某几个历史时刻强相关——比如预测早高峰车流量时,前一天相同时段的数据比紧接着的前一个时间点更有参考价值。普通 LSTM 只能隐式地记住这些相关性,信息经过多步传递后会被稀释。

Attention 的作用是把这种相关性显式化。常见做法是在 LSTM 的输出层之后加一个注意力层:计算每个时间步隐状态的得分,softmax 归一化成权重,再对全部隐状态做加权求和,得到一个上下文向量,最后接全连接层输出预测值。等价的公式是 context = sum(softmax(score(h_t)) * h_t),其中 score 通常是一个单层全连接网络。

另一种做法是把 Attention 放到 decoder 端,用于 encoder-decoder 架构。但需要注意:对单变量、单步预测来说,decoder 端没有额外的语义向量作为 query,注意力分数只能基于 decoder 自己的隐状态计算,信息增益有限。我一般建议在 encoder 输出端加注意力,也就是把 LSTM 输出序列整体压缩成一个带权重的上下文向量,这样实现更直接,反向传播也更稳定。

Attention 层的位置和维度同样影响训练行为。如果加在每层 LSTM 之后而不是只在最后一层,参数数量会明显上升,小数据下更容易过拟合。先从最后一层加起,验证有效后再考虑多层注意力,这是更稳妥的工程路径。

2.3 数据泄露是这类模型最容易翻车的地方

组合模型比单一 LSTM 多了一个分解环节,也就多了一个数据泄露入口。最常见的问题是:先把整段序列做 VMD 分解,再切训练集和测试集。VMD 在求解变分问题时用到的是整段信号的统计信息,包括未来段的频谱特征,这相当于让模型在训练时就知道了测试段的模态分布。这样得到的测试集指标会异常好看,但上线后立刻原形毕露。

正确的分解时机是“先切分,后分解”。具体做法是:只在训练集上做 VMD,测试集的模态用训练好的分解参数近似计算。第二个常见问题是归一化。归一化用的均值和标准差必须只从训练集计算,否则测试集的数值范围会泄漏到训练过程中。同样,如果用 sklearn 的 StandardScaler,务必先 fit 训练集,再用同一个 scaler transform 测试集。

第三个容易忽略的点是模态叠加的顺序。单独预测每个模态后,要先反归一化到原始量纲,再求和。如果顺序反了,先求和再反归一化,由于每个模态的方差不同,反归一化会叠加错误。这三个坑都发生在数据流转的边界,和模型结构无关,但影响比调参大得多。

提示:先切分,后分解,再归一化,这个顺序能排除 90% 的数据泄露问题。

3. 搭建 VMD-Attention-LSTM 的最小 python 源码

3.1 环境与数据准备

这一节给出一个能直接运行的最小骨架。依赖库包括 vmdpy(VMD 的 python 实现)、PyTorch、numpy 和 pandas。安装命令是 pip install vmdpy torch numpy pandas。数据只需要一列按时间升序的数值,比如电力负荷、水位或交易量。先读取数据,并把原始序列转成浮点数组。

import numpy as np import pandas as pd from vmdpy import VMD import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset # 假设 CSV 里有 date 和 value 两列 df = pd.read_csv("series.csv", parse_dates=["date"], index_col="date") values = df["value"].to_numpy(dtype=np.float32) # 只用前 80% 计算均值方差,避免测试集信息泄漏 train_len = int(len(values) * 0.8) mu = values[:train_len].mean() sigma = values[:train_len].std() normalized = (values - mu) / sigma

这段代码的关键点是归一化统计量只取自训练段。很多开源时间序列代码直接对整个序列做归一化,短期测试精度会偏高,但换到新数据上就崩。normalized 序列的长度和原序列一致,但统计口径已经和模型隔离。

3.2 VMD 分解与模态重组

下一步把归一化后的序列做 VMD 分解。vmdpy 的接口稳定性很好,核心参数是 K、alpha、tau。

# u: (K, N) 每个模态一行;omega: 中心频率估计 u, u_hat, omega = VMD( normalized, K=5, alpha=2000, tau=0, DC=0, init=1, tol=1e-7, )

分解完成后,u 的第一行是低频趋势,越往下频率越高。我通常会检查 omega 的最后一组值是否明显分离。中心频率打架的解决办法在第四章说明。

验证分离效果的实用命令是打印 omega 的最后一行并观察低频模态是否平滑。也可以用 np.fft.rfft 查看各模态的频谱峰值是否错开,这一步虽不是必需,但能帮助你判断 K 是否设大。

下表是 vmdpy 各参数的说明和推荐范围。

参数含义常见取值调整方向
K模态数量3~10中心频率重叠则减小 K
alpha惩罚因子,控制模态带宽500~3000带宽过大则加大 alpha
tau噪声容忍度,0 表示无噪声约束0 或 0.1数据噪声大时可适当调大
DC是否保留直流分量0 或 1趋势明显时设为 1
init中心频率初始化方式1 表示均匀分布默认即可
tol迭代收敛容忍度1e-7收敛困难时适当放宽

3.3 Attention-LSTM 模型结构

模型结构不复杂:输入先过一个单变量窗口,LSTM 编码每个时间步的隐状态,Attention 层对隐状态加权重,最后全连接层输出单值。

class AttentionLayer(nn.Module): def __init__(self, hidden_size): super().__init__() self.score = nn.Linear(hidden_size, 1) def forward(self, lstm_output): # lstm_output: (batch, seq_len, hidden_size) weights = torch.softmax(self.score(lstm_output), dim=1) context = torch.sum(weights * lstm_output, dim=1) return context class VMDAttentionLSTM(nn.Module): def __init__(self, input_size=1, hidden_size=64, num_layers=2, dropout=0.2): super().__init__() self.lstm = nn.LSTM( input_size=input_size, hidden_size=hidden_size, num_layers=num_layers, batch_first=True, dropout=dropout, ) self.attention = AttentionLayer(hidden_size) self.fc = nn.Linear(hidden_size, 1) def forward(self, x): out, _ = self.lstm(x) # (batch, seq_len, hidden) context = self.attention(out) # (batch, hidden) return self.fc(context).squeeze(-1)

这里的 LSTM 设置 batch_first=True,输入形状为 (batch, seq_len, input_size)。attention 用单层线性打分,softmax 维度是 1,也就是对 seq_len 求权重。num_layers 和 dropout 在 LSTM 内部只在层间生效,最后一层不做 dropout,这一点和 Transformer 的实现逻辑一致。

3.4 训练、验证与反归一化

训练数据要按每个模态单独构造。look_back 表示用过去多少个时间点预测下一点,数值应与数据的自然周期相关,例如小时级电力数据取 24 或 48。

def make_samples(modal, look_back=48): X, y = [], [] for i in range(look_back, len(modal)): X.append(modal[i - look_back:i]) y.append(modal[i]) return np.array(X, dtype=np.float32), np.array(y, dtype=np.float32) X, y = make_samples(u[0], look_back=48) # 先处理第一个模态 split = int(len(X) * 0.8) train_x, train_y = X[:split], y[:split] val_x, val_y = X[split:], y[split:]

拆分后每个模态都会得到自己的训练集。注意 VMD 分解已经消耗了整个 normalized 序列的一部分信息,因此这里的训练/验证划分同样不能跨越原先的切分边界。实践中,如果训练数据不足,可以保留小部分作为最终测试,其余内部的 80/20 划分只用于选参。

训练循环里需要做梯度裁剪,因为 LSTM 在较长序列上容易出现梯度爆炸。

loader = DataLoader( TensorDataset(torch.tensor(train_x), torch.tensor(train_y)), batch_size=128, shuffle=True, ) model = VMDAttentionLSTM(input_size=1, hidden_size=64, num_layers=2, dropout=0.2) optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau( optimizer, factor=0.5, patience=5 ) loss_fn = nn.MSELoss() for epoch in range(120): model.train() for xb, yb in loader: optimizer.zero_grad() pred = model(xb.unsqueeze(-1)) loss = loss_fn(pred, yb) loss.backward() nn.utils.clip_grad_norm_(model.parameters(), 1.0) optimizer.step() model.eval() with torch.no_grad(): val_pred = model(torch.tensor(val_x).unsqueeze(-1)) val_loss = loss_fn(val_pred, torch.tensor(val_y)).item() scheduler.step(val_loss)

把 xb.unsqueeze(-1) 的原因是要补上 input_size 维度。clip_grad_norm_ 中的 1.0 是梯度的全局范数上限,可以按需要放大或缩小。scheduler 使用验证损失来调整学习率,乘性因子 0.5、patience 5 在中小型数据集上效果稳定。

预测阶段要把每个模态的输出反归一化再叠加。由于每个模态训练时用的是同一个 mu 和 sigma,预测值也统一乘 sigma 加 mu 即可。

preds = [] with torch.no_grad(): for xb, yb in loader_test: preds.append(model(xb.unsqueeze(-1)).numpy()) pred = np.concatenate(preds) * sigma + mu

到这里,一个可运行的 VMD-Attention-LSTM 最小流程就完整了。实际使用中,模态数量 K 和 look_back 对结果的影响远大于模型结构层面的差异,下一章专门讨论这些参数怎么定。

4. 关键参数怎么定,改了会怎样

4.1 VMD 的 K 和 alpha 最影响天花板

VMD 分解出的模态数 K 直接决定模型能区分出多少种频率成分。K 设小了,趋势和周期混在一个模态里,退化成普通 LSTM;K 设大了,某些模态会成为拼凑出来的残余,没有物理意义。判断依据有两个:一是看 omega 最后一行的中心频率是否均匀分布在频带上,二是看各模态的相关性矩阵,如果两个模态的相关系数接近 1,说明过分解。

alpha 的作用是控制模态带宽。alpha 越大,每个模态的带宽越窄,中心频率越稳定,但高频细节会被削平;alpha 越小,带宽越宽,模态彼此的频率区间容易重叠。vmdpy 默认值是 2000,对多数分钟级或小时级数据都够用。可以把 alpha 拉高到 3000 试试中心频率是否漂移更小,但代价是某些瞬态波动会被滤掉。

这里给一个可抄的调参思路:先固定 alpha=2000,让 K 从 3 到 8 依次跑分解,打印 omega 的最后一列,选择中心频率开始出现重叠的前一个 K。之后保持 K 不变,把 alpha 按 500 的步长在 1500~3000 之间扫描,看验证集误差曲线的拐点。这种两段式扫描比盲目网格搜索快得多。

下面是分解质量的快速判断表,配合 omega 和模态能量使用。

观察点可能原因调整方式
相邻模态中心频率接近K 过大或 alpha 过小先降 K,再升 alpha
所有模态都和原序列高度相关几乎没有分解效果增大 K,检查 DC 设置
某个模态能量占比低于 0.1%高频残余噪声合并到相邻模态或丢弃
tau 非 0 时模态凌乱噪声容忍度过高改回 tau=0

4.2 attention 维度、dropout 和序列长度的取舍

注意力的学习能力集中在 AttentionLayer 的线性层维度上。这个 score 层的输出维度固定为 1,输入维度来自 LSTM 的 hidden_size。hidden_size 从 32 往上调,注意力分布会更细腻,但也更容易把权重集中在极少数时间步上,造成过拟合。对中短序列(look_back 24~72),hidden_size=64 是个安全起点,没必要追大。

dropout 在 LSTM 里只在多层之间生效,所以我个人从不在单层 LSTM 上设置 dropout。如果 num_layers=2,dropout=0.2 或 0.3 是常见范围,超过 0.5 会让训练明显变慢且收益递减。Attention 层本身不接 dropout,想要在上下文向量与全连接之间加正则,可以在全连接前插入一个 nn.Dropout。

look_back 与数据的周期强相关,而不是越大越好。电力负荷按小时采样,look_back=24 能抓住日内周期,48 能补充前一天同刻信息;径流预报按天采样,look_back=7 或 30 更合理。把 look_back 拉到 200,LSTM 的记忆负担和训练时长都会暴涨,而注意力权重在远距离上通常会稀疏化,实际信息量并没有增加。

4.3 训练策略:先整体后微调,早停不要只看 val_loss

因为每个模态都是独立训练的,模型参数数量乘以 K 以后会非常大。常见做法是:第一步,让所有模态共享同一套超参数,分别训练到收敛;第二步,把 K 个模态的预测结果作为多通道输入,合并进一个 LSTM 重新微调,让模型学习模态间的交叉信息。第二种做法在数据集较大的时候效果明显,小数据下反而容易过拟合。

早停的条件建议写成相对阈值:当验证损失连续 10 个 epoch 下降幅度小于当前值的 0.5% 时停止。只看 val_loss 是否下降会忽略噪声,绝对值又依赖量纲,相对阈值更通用。此外,不同模态的 loss 量级差别很大,比如高频模态的方差小,loss 天然低;如果拿所有模态的平均 loss 做早停,高频模态会被低频模态的数值掩盖。

best_loss = float("inf") trigger = 0 patience = 10 for epoch in range(120): # 训练与验证省略 if val_loss < best_loss * 0.995: best_loss = val_loss trigger = 0 else: trigger += 1 if trigger >= patience: print(f"early stop at epoch {epoch}") break

这段代码中的 0.995 就是相对阈值,含义是验证损失需要比历史最优下降至少 0.5%,否则算一次无效 epoch。连续 10 次无效就停止。

调参时建议把每个模态单独训练时的 loss 曲线画出来,确认哪几个模态贡献了主要误差。通常低频模态的拟合误差最小,高频模态误差最大。如果去掉高频模态后验证集结果反而变好,就不要单独预测它,用它和其他高频分量构成一个聚合项,或直接把该模态置零,靠整体重构时的平滑性补足。这个细节决定了你的模型在真实数据上有没有泛化能力,比换网络结构重要得多。

5. 真实数据上的效果与对比

5.1 用电力负荷数据做实验

以小时级的电力负荷数据为例,序列长度通常在 8000 到 20000 个点之间。按前面给出的流程,先做归一化和 VMD 分解,K 设 5、alpha 设 2000。观察各模态:IMF1 是平缓的趋势,IMF2 和 IMF3 的周期大约是 24 小时和 12 小时,IMF4 和 IMF5 中心频率更高,形状也更碎。这说明分解结果是符合负荷数据的物理常识的。

分别对每个模态训练 Attention-LSTM,look_back 取 48。实际对比中,VMD 分解带来的收益主要落在 IMF2 和 IMF3 上——这两个模态的规律性强,LSTM 在平稳周期信号上的拟合明显好于在混叠信号上。趋势模态 IMF1 即使换成简单的线性外推也差别不大,高频模态则经常出现预测曲线比真实值“多抖”的现象。

实验中的另一个发现是:多模态独立预测再加权求和,其误差不是各模态误差的简单叠加。低频模态的偏差会直接进入最终结果,高频模态的误差则可能因为符号随机而被部分抵消。这决定了最后的评估不能只看总体 RMSE,还要看误差在哪个频率区间集中。

5.2 和纯 LSTM、EMD-LSTM 对比

对照实验至少要有三组:纯 LSTM、EMD-LSTM、VMD-Attention-LSTM。纯 LSTM 输入不做任何分解,EMD-LSTM 用 PyEMD 做经验模态分解,其余训练设置完全一致。这样能分离出两个变量:分解方法本身,以及 Attention 层的贡献。

表格记录三组模型在验证集上的指标,具体数值随数据变化,但排序有参考意义。

模型RMSEMAE训练时长
纯 LSTM
EMD-LSTM中等
VMD-Attention-LSTM

这只是大致排序,不是固定结论。VMD 的优势在序列的频谱成分清晰且稳定时最明显;如果序列本身接近随机游走,分解出的模态没有规律可学,组合模型可能反而比纯 LSTM 差。EMD 的问题在于模态数不固定,且容易出现端点飞翼,对样本外预测不利。

值得强调的是 Attention 在对比中的位置。去掉 Attention、保留 VMD 和 LSTM,模型通常仍然优于纯 LSTM,但提升幅度大约只有 VMD-Attention-LSTM 的一半。Attention 的收益主要体现在预测曲线在转折点附近的跟随时滞更小,这在 RMSE 上反映不大,在业务上却很重要。

5.3 效果好的标准是什么,别只看 RMSE

时间序列预测的评估要分用途。如果预测结果用于调度或备货,转折点是否滞后比平均误差更关键。RMSE 对离群点敏感,一个尖峰就能让它变差,而 MAE 更能反映中位数水平的误差。更严格的做法是计算 pinball loss 来评估分位数预测,或用 MASE 把误差归一化到朴素预测之上,这样不同数据量的结果可以横向比较。

模态分解模型还有个特有指标:模态还原度。把预测的各模态求和后,对原始序列做一次 VMD,再看两个分解的差异。如果预测结果的频谱结构扭曲,即使 RMSE 看着还行,后续业务上的高阶特征也是错的。这个指标在论文里不常见,但在工程上能防住“数值好看、物理不对”的情况。

import numpy as np def pinball_loss(y_true, y_pred, tau=0.8): err = y_true - y_pred return np.mean(np.maximum(tau * err, (tau - 1) * err))

tau=0.8 时 pinball loss 更关注高分位误差,适合电力负荷这类需要偏保守估计的场景;tau=0.5 则退化为 MAE。用这个指标挑选模型,比单看 RMSE 更容易选出在实际调度中好用的配置。

最后检查一下多步预测的表现。单步预测精度高不代表滑动多步预测稳定。如果前几步误差逐步放大,甚至出现振荡,常见的对策是降低高频模态的权重,或在训练时引入 teacher forcing。

6. 让这套东西真正能上线的一个配置技巧

6.1 模态叠加预测的前置步骤

上线前先把流程固化成函数,避免每一步手动拼装。第 3 章的每个模态预测结果都要乘 sigma 加 mu,再累加。可以把这条逻辑封装成一个 predict_series 函数,内部循环模态集合,外部只接受原始序列和预测步数。叠加前务必检查每个模态预测的起始时间对齐,否则相位一旦错开,求和后会出现奇怪的跳变。

6.2 滚动多步预测的窗口设定

上线时往往要预测未来 24 步而不是一步。常见做法是滚动预测:每预测出一个值,就把它拼到窗口末尾,同时丢弃窗口最前面的值,再预测下一步。这样误差会累积,但每一步都让 LSTM 看到最新信息。

def rolling_predict(model, window, steps, look_back=48): window = window.copy() preds = [] for _ in range(steps): x = torch.tensor( window[-look_back:], dtype=torch.float32 ).view(1, -1, 1) with torch.no_grad(): p = model(x).item() preds.append(p) window.append(p) return np.array(preds)

使用这段代码时要额外传入当前已预测的值作为下一次输入。注意训练时模型从未见过自己生成的输入分布,所以长时间滚动预测的误差会逐步偏离训练分布,这属于正常现象。如果发现第 10 步以后误差明显膨胀,可以把训练方式改成 sequence-to-sequence 或多步直接回归。

6.3 验证方法:滚动回测

上线的最终验证应该用滚动回测而非单次切分。每次只把窗口向前移动一个真实值,重新预测,记录误差,然后继续。这样模拟了线上“每来一个新时刻,预测下一个窗口”的真实节奏。代码上只需要复用上面的 rolling_predict,外层循环从测试集起点开始移动即可,不需要每次重训模型。

滚动回测的结果如果比固定切分的指标差,说明模型存在数据自适应过拟合。此时回到 VMD 参数,优先减小 K 而不是调节注意力结构,往往更有效。

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

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

LKY Office Tools:3 步 5 分钟完成 Office 下载、安装、激活

LKY Office Tools&#xff1a;3 步 5 分钟完成 Office 下载、安装、激活 【免费下载链接】LKY_OfficeTools 一键自动化 下载、安装、激活 Office 的利器。 项目地址: https://gitcode.com/GitHub_Trending/lk/LKY_OfficeTools 刚重装完系统&#xff0c;发现没 Office 可…

作者头像 李华
网站建设 2026/9/13 16:44:02

数据分箱技术:特征工程中的核心预处理方法

1. 分箱技术概述与核心价值分箱&#xff08;Binning&#xff09;是数据预处理中的一项基础但至关重要的技术&#xff0c;尤其在特征工程和模型训练阶段扮演着关键角色。简单来说&#xff0c;分箱就是将连续变量离散化为有限个区间&#xff08;称为"箱"或"桶&quo…

作者头像 李华
网站建设 2026/9/13 16:43:55

Django 如何覆盖第三方应用或 django.contrib.admin 的内置模板

Django 如何覆盖第三方应用或 django.contrib.admin 的内置模板 【免费下载链接】django The Web framework for perfectionists with deadlines. 项目地址: https://gitcode.com/GitHub_Trending/dj/django 当你在项目中使用了第三方应用或 django.contrib.admin 这类 …

作者头像 李华
网站建设 2026/9/13 16:41:59

微信小游戏云成本失控?从架构到运营的全生命周期降本方案

做微信小游戏这三年&#xff0c;我见过太多团队栽在同一个地方&#xff1a;不是游戏不好玩&#xff0c;而是游戏上线那一刻&#xff0c;云资源的账单比流水涨得还快。立项时没人关心服务器&#xff0c;开发时一人一台压测机&#xff0c;运营时发现买量费用把利润吃光——这几乎…

作者头像 李华