STAR Decomposition 一种针对极端事件的信号分解方法 论文精读加复现
STAR 分解🚀
在时序预测任务中,为了情绪化信号的各种成分,例如趋势信息季节信息等往往都需要对信号进行分解。目前熟知的分解方式有很多种,经验模态分解 EMD 变分模态分解 VMD ,还有 集合经验模态分解 EEMD,自适应噪声完备集合经验模态分解 CEEMDAN 等等,但这些和小波变换分解类似,一般都不会针对异常信号和极端事件进行分解。STAR 是一个比较冷门的分解方式,是我在Paper with Code 淘宝的时候发现的,他来源于 2022 年的 一篇叫 AA-Forecast: Anomaly-Aware Forecast for Extreme Events。中提出的,个人认为这块是一个比较容易拼出一个创新点的内容。
文章目录
- STAR 分解🚀
- 1.STAR Decomposition 论文精读部分
- 2.STAR 代码复现 手搓版
- 2.1 数据读取
- 2.2 提取趋势成分
- 2.3 提取季节成分
- 2.4 提取残差成分
- 2.5 提取异常成分
- 3.项目 GitHub 地址
- 4.结束
根据论文结构图,整个论文是分 STAR 分解,异常感知模型 Anomaly-Aware Model ,动态不确定性优化 Dynamic Uncertainty Optimization 三个部分,这里就先值关注第一个 STAR 分解的部分。

1.STAR Decomposition 论文精读部分
对于这个分解方法的描述写在了论文的 3.1 部分,也不是很长,但我也是整体精读了下来,也从 Paper with Code 的官方链接上下载了代码进行对照,可以说如果其实有一些核心的地方是没有讲清楚的,所以导致看上去挺不错的东西,没啥人用,接下来就直接对 3.1 的部分精读一下,翻译的话是结合 DeepSeek 初步翻译,然后加上我自己的理解精调的。
-
STAR decomposition is used as a strategy to not only extract the anomalies and sudden changes of data but also decompose the complex time series to its essential components.
STAR分解被用作一种策略,不仅用于提取数据的异常值和突变,而且还用于将复杂的时间序列分解为其基本组成部分。 -
Unfortunately, widely popular decomposition method such as STL [14] does not extract anomalies.
不幸的是,广泛使用的 STL 方法不适用于去提取异常值。
STL 信号分解方法即基于局部加权回归的季节性趋势分解法(Seasonal and Trend decomposition using Loess)。
-
Although recent works such as STR [15] and RobustSTL [16] are designed to be robust to the extreme effect of anomalies in their decomposition, they are not used to explicitly extract anomalies from the residual component.
尽管最近的工作,如STR [15] 和 RobustSTL [16] 被设计为在其分解过程中对异常的极端效应具有鲁棒性,但它们并未被用来明确地从残差分量中提取异常。 -
To alleviate these issues, we propose STAR decomposition that are decomposes the original time series x ( k ) x^{(k)} x(k) in multiplicative manner to its seasonal s ( k ) s^{(k)} s(k) ,trend t ( k ) t^{(k)} t(k),anomalies a ( k ) a^{(k)} a(k), and residual r ( k ) r^{(k)} r(k) components:
为了解决这个问题我们提出了 STAR 分解 ,将原始信号 x ( k ) x^{(k)} x(k) 分解为 季节成分 s ( k ) s^{(k)} s(k) ,趋势成分 t ( k ) t^{(k)} t(k),异常成分 a ( k ) a^{(k)} a(k),残差成分 r ( k ) r^{(k)} r(k) 的相乘。
x ( k ) = s ( k ) × t ( k ) × a ( k ) × r ( k ) x^{(k)} = s^{(k)}×t^{(k)}×a^{(k)}×r^{(k)} x(k)=s(k)×t(k)×a(k)×r(k)
季节成分:是指时间序列数据中呈现出的周期性、重复性的模式,其周期通常是固定的,与季节、月份、星期、甚至一天中的不同时段等时间因素相关。
-
Such decomposition not only increases the dimensions of the original data but also supplies us withextracted anomalies.
这种分解不仅增加了原始的数据维度,还为我们提供了提取出的异常值。 -
As shown in Figure 1:
分解效果如图1所示:
-
we begin the decomposition by approximating the trend line t ( k ) t^{(k)} t(k) with the locally weighted scatterplot smoothing (i.e. LOESS).
我们通过局部加权散点点平滑来近似趋势线 t ( k ) t^{(k)} t(k),开始进行分解。
LOESS 算法,即局部加权散点平滑法(Locally Weighted Scatterplot Smoothing),是一种用于数据拟合和曲线平滑的非参数统计方法。它通过对每个数据点附近的局部数据进行加权回归,来估计该点的平滑值。其优点是不需要对数据的分布形式做出先验假设,能够自适应地根据数据的局部特征进行拟合,对于具有复杂非线性关系的数据有较好的拟合效果,能有效去除数据中的噪声,展现出数据的潜在趋势。
-
Then, we divide the original data x ( k ) x^{(k)} x(k) by the approximated trend line to derive the detrended time series.
接下来我门用原始信号 x ( k ) x^{(k)} x(k)除以趋势信号 t ( k ) t^{(k)} t(k),得到去除时间趋势之后的序列。 -
We then partition the detrended time series into periods of cyclic sub-series where the cycle size is determined by the time interval of the dataset.
然后我们将去趋势的时间序列分割成周期性的子序列,其中周期大小由数据集的时间间隔决定。 -
As an example, the cycle size for a monthly dataset would be 12. Then we obtain the seasonal component
举一个例子,假设是一个月度数据,则周期大小将是12。 -
Subsequently, the residual component r ( k ) r^{(k)} r(k) is derived by dividing the seasonal and trend segments from the original series.
之后,残留的残差成分 r ( k ) r^{(k)} r(k) 是原始信号 x ( k ) x^{(k)} x(k) 除以趋势成分 t ( k ) t^{(k)} t(k) 和季节成分 s ( k ) s^{(k)} s(k) 得到的。 -
Note that the anomaly component a ( k ) a^{(k)} a(k) can be considered as the oddities of the dataset, which do not follow the extracted trend or seasonal components.
值得注意的是 a ( k ) a^{(k)} a(k) 可以被视为数据集中的异常情况,这个异常情况不随季节和趋势的变化而变化。 -
Intuitively, anomalies are spread out through residual components, which also contain noise and other real-world effects.
直观上,异常值通常在分布残差成分中,这些异常值包含噪声和其他显示的现实世界的影响。
残差成分 Residuals 和异常成分的区别 Anomalies 的区别。
残差 (Residuals) | 异常 (Anomalies) | |
---|---|---|
定义 | 模型无法解释的所有剩余波动 | 显著偏离正常模式的极端值 |
组成 | 噪声 + 未建模因素 + 潜在异常 | 残差中的特殊子集 |
性质 | 必然存在(模型不可能完美) | 偶然出现(需要特别检测) |
处理 | 分析分布特征 | 需要单独识别和调查 |
示例 | 日销售额波动 ±5% | 某天销售额突然暴涨200% |
- 残差 = 浪花(包含正常涟漪、小鱼跃出水面、偶尔的垃圾漂浮)
- 异常 = 突然出现的巨型漩涡(需要立即关注的特殊现象)
- To distinguish the anomalies from residual components, statistical metrics such as mean and variance are not the appropriate measure as they are highly sensitive to the severity level of anomaly values.
为了区分异常值和残差分量,均值和方差等统计度量不是适当的衡量方法,因为他们对异常值的异常程度非常敏感。
假设你是班主任,要找出考试作弊的学生(异常检测):
- 班级平均分(mean) = 所有学生分数的平均值
- 分数波动(variance) = 学生们分数的分散程度
现在有两个作弊情况:
- 张三:偷偷抄答案考了100分(极端异常值)
- 李四:偶尔偷看考了75分(轻度异常值)
如果只用均值和方差判断:
- 张三的100分会大幅拉高班级平均分(比如从70→78)
- 方差也会急剧增大(分数范围从50-80变成50-100)
通过均值和方差判则无法找出李四的异常
-
As one expects, the severity of the anomalies can change the mean and variance values which are unwanted.
正如所设想的内样,异常的严重程度会以我们不期望的形式改变均值和方式。 -
To resolve this issue, we leverage the median of the residuals, which is immune to the severity of the outliers in the residual components.
为了解决这个问题,我们利用残差的中位数,它对残差分量中的异常值的严重程度具有免疫力。 -
Next,we define robustness score ρ t ( k ) \rho_t^{(k)} ρt(k) for each observation at time t t t as:
接下来我们为在各个 t t t 时刻的每一个观察值定义了鲁棒性因子 ρ t ( k ) \rho_t^{(k)} ρt(k) 公式如下:
ρ t ( k ) = ∣ r t ( k ) − r ˙ ( k ) ∣ ∑ t = 1 T ∣ r t ( k ) − r ˙ ( k ) ∣ T − 1 \rho_t^{(k)} = \frac{\left| r_t^{(k)} - \dot{r}^{(k)} \right|}{\sqrt{\frac{\sum_{t = 1}^{T} \left| r_t^{(k)} - \dot{r}^{(k)} \right|}{T - 1}}} ρt(k)=T−1∑t=1T rt(k)−r˙(k) rt(k)−r˙(k) -
where ρ t ( k ) \rho_t^{(k)} ρt(k) stand for the strength of the anomalies, r t ( k ) r_t^{(k)} rt(k) is the residual at time step t t t and r ˙ ( k ) \dot{r}^{(k)} r˙(k) is the median of the residuals.
其中 ρ t ( k ) \rho_t^{(k)} ρt(k) 代表异常强度, r t ( k ) r_t^{(k)} rt(k) 时间步 t t t 时刻的残差值, r ˙ ( k ) \dot{r}^{(k)} r˙(k) 是残差成分的中位数。 -
Note that the larger ρ t \rho_t ρt indicates that a drastic change has occurred in the trend and seasonal components. We then extract the anomalies from residuals as below:
ρ t \rho_t ρt 较大表明趋势和季节性成分发生了剧烈的变化,我们从残差中提取异常如下。
a t ( k ) = { 1 , ρ t ( k ) < ρ c ( k ) r t ( k ) , ρ t ( k ) ≥ ρ c ( k ) \mathbf{a}_t^{(k)} = \begin{cases} 1, & \rho_t^{(k)} < \rho_c^{(k)} \\ r_t^{(k)}, & \rho_t^{(k)} \geq \rho_c^{(k)} \end{cases} at(k)={1,rt(k),ρt(k)<ρc(k)ρt(k)≥ρc(k) -
where ρ c ( k ) \rho_c^{(k)} ρc(k) is the constant threshold given by the value of a robustness score ranked in the p − p- p−value 0.05 while the values of elements in ρ ( k ) \rho^{(k)} ρ(k) are ranked in descending order from large to small.
其中 ρ c ( k ) \rho_c^{(k)} ρc(k) 是在降序排列的 ρ ( k ) \rho^{(k)} ρ(k) 序列中分位值为 0.05 的时候确定的。
假设有 ρ ( k ) \rho^{(k)} ρ(k) 有100个数,阈值 ρ c ( k ) \rho_c^{(k)} ρc(k) 就是第5(100×0.05)大的数字
-
Notably, when the value of the anomaly component ( a ( k ) a^{(k)} a(k)) deviates further from the value 1, it indicates an abrupt change in the trend and the seasonal component (no sign of anomalies).
这里要明确的是,当异常值 a ( k ) a^{(k)} a(k) 的值距离 1 很远时候,它表面确实和季节性成分发生了突然的变化,但不一定是异常。 -
On the contrary, when both anomaly and residual values are equal 1 ( r t ( k ) r_t^{(k)} rt(k) = 1 and a t ( k ) a_t^{(k)} at(k) = 1), it indicates that the observed signal at time t t t explicitly follows the trend and seasonal component.
可以对比来看的是,当异常值和残差值都等于1时,表明在时间 t t t 观察到的信号明确地遵循了趋势和季节成分。 -
Note that such important information might not be automatically inferred when additive decomposition methods are being used. This due to the fact that the values of residual components can differ from one dataset to another which requires manual effort in their detection.
当使用加法分解方法时,这样的重要信息可能不会被自动推断出来,这是因为残差分量的值可能因数据集而异,因此需要手动筛选出异常。(个人补充:加法分解一般只能直接通过幅度大小判定异常,但由于各个数据集的数据情况不同,无法直接通过对幅度加上阈值进行直接筛选) -
A sample result of anomaly decomposition is shown in the left-most part of Figure 1, where the observed time series data is decomposed into tis seasonal, trend, anomalies, and residual .
异常分解的一个示例结果显示在图最左侧的部分,其中观察到的时间序列数据被分别分解为季节性、趋势、异常和残差分量。(还是开头内个图不放来他又说了一遍) -
Each of these components holds essential information about the characteristics of the time and will be leveraged to train the forecast model.
这些成分中的每一个都包含了关于时间序列特征的重要信息,并将被我们使用来预测模型。 -
To this end, we concatenate the derived decomposed vector of time series with the input, which includes the observed time series and its labeled extreme event.
最终,我们将这些时间序列进行拼接作为一个输入模型的训练的特征样本,这个样本包含观测到的时间序列及标记的极端事件还有我们分解出的各个成分。
读完之后其实我是带着疑惑的,就是实际上 x ( k ) = s ( k ) × t ( k ) × a ( k ) × r ( k ) x^{(k)} = s^{(k)}×t^{(k)}×a^{(k)}×r^{(k)} x(k)=s(k)×t(k)×a(k)×r(k) 在这个乘法项的分解里 a ( k ) a^{(k)} a(k) 这一项是怎么乘进去的其实是没有清晰给出的,如果不看代码我觉得但从这段的写作上来看,有故意隐藏核心细节的嫌疑。好在代码虽然没有注释但我也复现出来了。
2.STAR 代码复现 手搓版
为了保证复现结果的可验证性,我这里用了一个阿里的开源功率数据集。
https://tianchi.aliyun.com/dataset/159885
下载之后数据如下一个非常标准的风电数据集,之后我们就分解和使用实际发电功率这一项。
2.1 数据读取
import pandas as pd
import matplotlib.pyplot as pltdata = pd.read_excel("data.xlsx")
print(data.head())power = data["实际发电功率"].valuesplt.plot(power)
plt.show()
2.2 提取趋势成分
# 导入必要的库
import pandas as pd # 数据处理库
import matplotlib.pyplot as plt # 绘图库
import numpy as np # 数值计算库
from statsmodels.nonparametric.smoothers_lowess import lowess # 非参数平滑方法# 设置中文字体(以 Windows 的 SimHei 为例)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置全局字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题# 读取Excel数据文件
data = pd.read_excel("data.xlsx") # 从Excel文件加载数据
power = data["实际发电功率"].values # 提取"实际发电功率"列的值转为numpy数组
x = np.arange(len(power)) # 创建与功率数据长度相同的索引数组作为x轴# 使用LOWESS进行平滑处理(非参数局部回归)
# frac: 平滑窗口比例(0.3表示使用30%的数据点进行局部拟合)
# it: 执行3次稳健拟合迭代(消除异常值影响)
smoothed = lowess(power, x, frac=0.3, it=3)# 提取并处理平滑结果
rt = smoothed[:, 1] # 提取平滑后的趋势分量(第二列为拟合值)
data_d_rt = power / rt # 计算原始功率与趋势分量的比值(分解周期分量)# 创建绘图画布(宽20英寸,高4英寸)
plt.figure(figsize=(20, 4))# 绘制原始功率曲线
plt.plot(power,label="功率",color='blue',linestyle='-', # 实线linewidth=2) # 线宽2磅# 绘制趋势分量曲线
plt.plot(rt,label="趋势分量 $r^{(k)}$", # LaTeX格式的数学符号color='green',linestyle='--', # 虚线linewidth=2)# 保存图形到文件
plt.savefig("2.获得趋势分量.png",bbox_inches="tight") # 紧凑型边界框# 显示图形
plt.legend(loc="upper left") # 在左上角显示图例
plt.grid(True) # 添加网格线
plt.show()
2.3 提取季节成分
在季节分量这里,我们选择的周期的以天为周期,由于数据本身颗粒度为15分钟,所以就是96个一循环。
# 导入所需库
import pandas as pd # 数据处理库
import matplotlib.pyplot as plt # 绘图库
import numpy as np # 数值计算库
from statsmodels.nonparametric.smoothers_lowess import lowess # LOWESS平滑算法# 设置中文字体显示(针对Windows系统)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示异常问题# 数据读取与预处理
data = pd.read_excel("data.xlsx") # 从Excel文件加载数据集
power = data["实际发电功率"].values # 将功率列转换为numpy数组
x = np.arange(len(power)) # 创建与数据长度相同的索引序列# LOWESS趋势提取
smoothed = lowess(power, x, frac=0.3, it=3) # 执行局部加权回归
rt = smoothed[:, 1] # 提取趋势分量(第二列为拟合值)# 去趋势处理
data_d_rt = power / rt # 通过除法去除趋势(适用于乘法分解模型)# 周期特征提取
son_sequence = data_d_rt.copy().reshape(96, -1) # 按日周期(15分钟间隔)重塑数据为96行
sequence_len = son_sequence.shape[-1] # 获取每个周期的天数(列数)# 中位数计算(注意:此处实际使用均值计算,建议修改为np.median)
column_medians = np.mean(son_sequence, axis=1) # 计算每个时间点的均值(应使用中位数)
column_medians = column_medians[:, np.newaxis] # 添加新轴便于矩阵运算# 季节分量重构
st = np.tile(column_medians, (1, sequence_len)).T.reshape(-1) # 将均值延展为完整序列
# 操作解析:
# 1. np.tile进行矩阵复制 (1列→sequence_len列)
# 2. .T转置矩阵适配后续操作
# 3. reshape(-1)展平为一维季节分量# 可视化设置
plt.figure(figsize=(20, 4)) # 创建20英寸宽、4英寸高的画布
plt.plot(st, # 绘制季节分量label="中位数延展结果", # 图例标签color='blue', # 线条颜色linewidth=2) # 线宽设置# 图表美化
plt.title("中位数延展结果可视化", fontsize=16) # 设置标题及字号
plt.xlabel("时间/索引", fontsize=14) # X轴标签设置
plt.ylabel("中位数延展值", fontsize=14) # Y轴标签设置(实际为均值)
plt.legend(loc='upper right', fontsize=12) # 右上角图例
plt.grid(True, linestyle='--', alpha=0.6) # 半透明虚线网格
plt.tight_layout() # 自动调整元素间距
plt.show() # 显示图形
2.4 提取残差成分
# 导入必要的库
import pandas as pd # 数据处理库
import matplotlib.pyplot as plt # 绘图库
import numpy as np # 数值计算库
from statsmodels.nonparametric.smoothers_lowess import lowess # LOWESS平滑算法# 设置中文显示(适用于Windows系统)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示异常问题# 数据加载与预处理
data = pd.read_excel("data.xlsx") # 从Excel文件加载数据集
power = data["实际发电功率"].values # 提取功率列数据为numpy数组
x = np.arange(len(power)) # 创建时间索引序列(0,1,2,...n)# 趋势分量提取(LOWESS平滑)
smoothed = lowess(power, x, frac=0.3, it=3) # 执行局部加权回归
tk = smoothed[:, 1] # 提取趋势分量(第二列为拟合值)# 去趋势处理(乘法分解模型)
data_d_tk = power / tk # 原始信号/趋势分量 = 季节分量 × 残差分量# 周期特征提取(假设每日96个15分钟间隔)
son_sequence = data_d_tk.copy().reshape(96, -1) # 重塑为(96,天数)矩阵
sequence_len = son_sequence.shape[-1] # 获取周期天数(列数)# 季节分量计算(行中位数)
column_means = np.mean(son_sequence, axis=1) # 计算每个时间点的平均值
column_means = column_means[:, np.newaxis] # 转换为列向量便于矩阵运算# 季节分量重构
sk = np.tile(column_means, (1, sequence_len)).T.reshape(-1) # 延展中位数序列
# 操作分解:
# 1. np.tile复制列向量为(96,天数)矩阵
# 2. .T转置为(天数,96)
# 3. reshape(-1)展平为原始长度# 残差分量计算
rk = data_d_tk / sk # 残差 = 去趋势信号 / 季节分量# 可视化设置(创建4行1列的子图布局)
plt.figure(figsize=(20, 10)) # 设置画布尺寸(宽20英寸,高10英寸)# ---------------------------
# 子图1:原始功率信号
# ---------------------------
plt.subplot(4, 1, 1) # 定位到第1个子图
plt.plot(x, power,label="原始功率信号", # 图例标签color='blue', # 信号颜色linewidth=2) # 线宽设置
plt.title("原始功率信号", fontsize=14) # 子图标题
plt.xlabel("时间/索引", fontsize=12) # X轴标签
plt.ylabel("功率值", fontsize=12) # Y轴标签
plt.legend(loc='upper right', fontsize=10) # 图例位置与字号
plt.grid(True, linestyle='--', alpha=0.6) # 半透明虚线网格# ---------------------------
# 子图2:趋势分量 (tk)
# ---------------------------
plt.subplot(4, 1, 2) # 定位到第2个子图
plt.plot(x, tk,label="趋势分量 (tk)", # 分量名称color='green', # 趋势线颜色linewidth=2)
plt.title("趋势分量 (tk)", fontsize=14)
plt.xlabel("时间/索引", fontsize=12)
plt.ylabel("趋势值", fontsize=12)
plt.legend(loc='upper right', fontsize=10)
plt.grid(True, linestyle='--', alpha=0.6)# ---------------------------
# 子图3:季节分量 (sk)
# ---------------------------
plt.subplot(4, 1, 3) # 定位到第3个子图
plt.plot(x, sk,label="季节分量 (sk)", # 周期特征color='red', # 季节线颜色linewidth=2)
plt.title("季节分量 (sk)", fontsize=14)
plt.xlabel("时间/索引", fontsize=12)
plt.ylabel("季节值", fontsize=12)
plt.legend(loc='upper right', fontsize=10)
plt.grid(True, linestyle='--', alpha=0.6)# ---------------------------
# 子图4:残差分量 (rk)
# ---------------------------
plt.subplot(4, 1, 4) # 定位到第4个子图
plt.plot(x, rk,label="残差分量 (rk)", # 剩余波动color='purple', # 残差线颜色linewidth=2)
plt.title("残差分量 (rk)", fontsize=14)
plt.xlabel("时间/索引", fontsize=12)
plt.ylabel("残差值", fontsize=12)
plt.legend(loc='upper right', fontsize=10)
plt.grid(True, linestyle='--', alpha=0.6)# 全局布局调整
plt.tight_layout() # 自动调整子图间距
plt.show() # 渲染显示图像
2.5 提取异常成分
这里要说一下的是,在原文中没有给出的残差成分和提取异常成分相乘的关系以及如何作用到原始信号上,在我阅读了他的代码之后,其实是通过赋1值实现的,也就是说异常成分就是残差成分中鲁棒因子大于等于阈值的点组成的,其他地方都是1,然后残差成分中的鲁棒因子小于阈值的点给变成了1,这样的话,经过这一步之后,得到的异常成分和残差成分相乘,其实就是上一步的残差成分,这部分关键逻辑在原文中被掩盖了。
# 导入所需库
from statistics import median # 提供中位数计算函数
import pandas as pd # 数据处理库
import matplotlib.pyplot as plt # 绘图库
import numpy as np # 数值计算库
from statsmodels.nonparametric.smoothers_lowess import lowess # LOWESS平滑算法# 设置中文显示(适用于Windows系统)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题# 数据加载与预处理
data = pd.read_excel("data.xlsx") # 加载Excel数据集
power = data["实际发电功率"].values # 提取功率数据为numpy数组
x = np.arange(len(power)) # 创建时间索引序列(0,1,2,...n)# 趋势分量提取(LOWESS平滑)
smoothed = lowess(power, x, frac=0.3, it=3) # 执行局部加权回归
tk = smoothed[:, 1] # 提取趋势分量(第二列为拟合值)# 去趋势处理(乘法分解模型)
data_d_tk = power / tk # 原始信号/趋势分量 = 季节分量 × 残差分量# 周期特征提取(假设每日96个15分钟间隔)
son_sequence = data_d_tk.copy().reshape(96, -1) # 重塑为(96,天数)矩阵
sequence_len = son_sequence.shape[-1] # 获取周期天数(列数)# 季节分量计算(注意此处实际使用均值,建议修改为np.median)
column_medians = np.mean(son_sequence, axis=1) # 计算每个时间点的均值
column_medians = column_medians[:, np.newaxis] # 转换为列向量# 季节分量重构
sk = np.tile(column_medians, (1, sequence_len)).T.reshape(-1) # 延展为完整序列# 残差分量计算
rk = data_d_tk / sk # 残差 = 去趋势信号 / 季节分量# 异常检测算法 --------------------------------------------------
# 计算残差中位数
rk_median = np.median(rk) # 获取残差的中位数值# 计算绝对离差(Median Absolute Deviation, MAD)
rou_abs = np.abs(rk - rk_median) # 每个残差与中位数的绝对距离# 计算标准化离差(类似Z-score标准化)
rou_k = rou_abs / np.sqrt(np.sum(rou_abs)/(len(rou_abs)-1)) # 自定义标准化方法# 确定异常阈值(取95%分位数)
sorted_data = sorted(rou_k, reverse=True) # 降序排列离差值
rou_c = sorted_data[int(0.05*len(sorted_data))-1] # 取前5%作为异常阈值# 生成异常指示向量
ak = rk.copy() # 创建副本
ak[np.where(rou_k < rou_c)] = 1 # 正常点标记为1
rk[np.where(rou_k >= rou_c)] = 1 # 异常点残差设为1(需验证逻辑合理性)# 可视化设置 ---------------------------------------------------
fig, axes = plt.subplots(5, 1, figsize=(20, 14)) # 创建5行子图布局# 子图1:原始功率数据
axes[0].plot(power,label='原始功率数据',color='blue')
axes[0].set_ylabel('原始功率数据')
axes[0].legend()
axes[0].grid(True)# 子图2:趋势分量
axes[1].plot(tk,label='趋势信息 (tk)',color='orange')
axes[1].set_ylabel('趋势成分')
axes[1].legend()
axes[1].grid(True)# 子图3:季节分量
axes[2].plot(sk,label='季节信息分量 (sk)',color='green')
axes[2].set_ylabel('季节成分')
axes[2].legend()
axes[2].grid(True)# 子图4:异常分量(需注意标记逻辑)
axes[3].plot(ak,label='异常分量 (ak)',color='red')
axes[3].set_ylabel('异常成分')
axes[3].legend()
axes[3].grid(True)# 子图5:修正后的残差分量
axes[4].plot(rk,label='残差分量 (rk)',color='purple')
axes[4].set_ylabel('残差成分')
axes[4].legend()
axes[4].grid(True)# 布局调整
plt.tight_layout()
plt.show()
3.项目 GitHub 地址
代码也顺手传上去了,如果懒得复制了就上去 GitHub 上直接去下一下吧。
https://github.com/StChenHaoGitHub/STAR_Decomposition
4.结束
这篇内容写的也是比较累的,确实难度也不小,而且实用性也存疑,但是我要是用不了给师弟拿去整个花活凑个不实用的创新点也是可以的。这个就先这样吧。
相关文章:
STAR Decomposition 一种针对极端事件的信号分解方法 论文精读加复现
STAR 分解🚀 在时序预测任务中,为了情绪化信号的各种成分,例如趋势信息季节信息等往往都需要对信号进行分解。目前熟知的分解方式有很多种,经验模态分解 EMD 变分模态分解 VMD ,还有 集合经验模态分解 EEMD,…...
matlab中如何集成使用python
在 MATLAB 中集成使用 Python 可以通过调用 Python 脚本或函数来实现。MATLAB 提供了 py 模块来直接调用 Python 代码。以下是一个简单的示例,展示如何在 MATLAB 中调用 Python 函数。 示例:在 MATLAB 中调用 Python 函数 1. 编写 Python 函数 首先&a…...
使用matlab求伴随矩阵
已知三阶方阵: 计算行列式det 计算逆矩阵inv 如何det不等于0,伴随矩阵 行列式det*逆矩阵inv >> A[1 0 0;1 1 -1;-2 0 3]A 1 0 01 1 -1-2 0 3>> det(A)ans 3>> >> A_invinv(A)A_inv 1.0000 …...
音视频处理的“瑞士军刀”与“积木”:FFmpeg 与 GStreamer 的深度揭秘
一、发展历史与生态演进对比 FFmpeg的成长轨迹 诞生背景:2000年由Fabrice Bellard创建,最初为解决视频编码标准化问题而生。早期版本仅支持MPEG-1编码,但凭借开源社区协作,迅速扩展为全格式编解码工具。技术扩张:2004年…...
Debezium日常分享系列之:Debezium 3.1.0.Beta1发布
Debezium日常分享系列之:Debezium 3.1.0.Beta1发布 新特性和改进Debezium 平台的首次发布Percona 的最小锁定新的 Oracle 源信息 SCN 和时间戳字段Vitess Epoch/零日期列解析的变化Vitess 二进制排序的 tiny、medium 和 long 文本列的变化CloudEvent traceparent 支…...
智能汽车图像及视频处理方案,支持视频智能剪辑能力
在智能科技日新月异的今天,汽车已不仅仅是代步工具,它们正逐步进化为集出行、娱乐、生活于一体的智能移动空间。在这场汽车行业的智能化变革中,美摄科技以其卓越的智能汽车图像及视频处理方案,引领了一场前所未有的视觉盛宴&#…...
《从零手写Linux Shell:详解进程控制、环境变量与内建命令实现 --- 持续更新》
承接上文Linux 进程的创建、终止、等待与程序替换保姆级讲解-CSDN博客,涉及所用到的代码,本文所绑定的资源就是上篇文章的主要代码。 完整代码在文章末尾 目录 1.实现编写代码输出一个命令行 a.如何获取自己的用户名,主机名,路径…...
postgresql 高版本pgsql备份在低版本pgsql中恢复失败,报错:“unsupported version”
关键字 PostgreSQL、pg_restore、版本兼容性、数据库迁移、pg_dump、备份恢复、unsupported version in file header 背景环境 系统配置 环境类型操作系统PostgreSQL版本内存工具链测试环境Windows 111616GBNavicat/PgAdmin生产环境Windows Server 2012 R2128GBPgAdmin/命令…...
裸机开发-GPIO外设
重新开始学ZYNQ开发,学完上linux系统 基础知识:ZYNQ 的三种GPIO :MIO、EMIO、AXI - FPGA/ASIC技术 - 电子发烧友网 GPIO是ZYNQ PS端的一个IO外设,用于观测(input)和控制(output)器…...
STM32——独立看门狗(IWDG)
IWDG 简介 独立看门狗本质上是一个 定时器 ,这个定时器有一个输出端,可以输出复位信号。该定时器是一个 12 位的递减计数器 ,当计数器的值减到 0 的时候,就会产生一个复位信号。如果 在计 数没减到 0 之前,重置计…...
使用STM32CubeMX+DMA+空闲中断实现串口接收和发送数据(STM32G070CBT6)
1.STM32CubeMX配置 (1)配置SYS (2)配置RCC (3)配置串口,此处我用的是串口4,其他串口也是一样的 (4)配置DMA,将串口4的TX和RX添加到DMA中 &#…...
连续出现的字符(信息学奥赛一本通-1148)
【题目描述】 给定一个字符串,在字符串中找到第一个连续出现至少k次的字符。 【输入】 第一行包含一个正整数k,表示至少需要连续出现的次数。1 ≤ k ≤ 1000。 第二行包含需要查找的字符串。字符串长度在1到2500之间,且不包含任何空白符。 【…...
matlab 正态分布
目录 一、概述1、参数2、概率密度函数3、累积分布函数二、代码案例1、拟合正态分布对象2、估计参数3、计算并绘制正态分布的概率密度函数4、绘制标准正态分布的正态累积分布函数5、比较 gamma 和正态分布的概率密度函数6、正态分布和对数正态分布之间的关系7、比较 Student t 和…...
C# MVC项目部署II后错误,403禁止访问:访问被拒绝问题处理
C# MVC项目部署II后错误,403禁止访问:访问被拒绝问题处理 问题如下: 解决办法: 1. 应用程序池要选v4.xx,托管模式选“集成” 2. 把asp.net 4.xx安装在iis上,方法: cd \Windows\Microsoft .NE…...
有趣的算法实践:整数反转与回文检测(Java实现)
题目描述:整数反转与回文检测 要求实现两个功能: 将输入的整数反转(保留符号,如输入-123返回-321)判断反转后的数是否为回文数(正反读相同) 示例: 输入:123 → 反转结…...
数学建模:MATLAB循环神经网络
一、简述 1.循环神经网络 循环神经网络(RNN)是一种用于处理序列数据的神经网络。不同于传统的前馈神经网络,RNN在隐藏层中加入了自反馈连接,使得网络能够对序列中的每个元素执行相同的操作,同时保持一个“记忆”状态…...
东隆科技携手PRIMES成立中国校准实验室,开启激光诊断高精度新时代
3月12日,上海慕尼黑光博会期间,东隆科技正式宣布与德国PRIMES共同成立“中国校准实验室”。这一重要合作标志着东隆科技在本地化服务领域的优势与PRIMES在激光光束诊断领域的顶尖技术深度融合,旨在为中国客户提供更快速、更高精度的服务以及本…...
【MySQL】B树和B+树的区别?MySQL为什么选用B+树作为索引数据结构?
B树和B树的区别: 结构方面: 1.节点存储内容: B树: 节点同时存储索引和数据。B树:只有叶子节点存储数据记录或指向数据记录的指针,非叶子节点只存键值,用于索引。 B 树的非叶子节点可以存储更…...
使用yolov8+flask实现精美登录界面+图片视频摄像头检测系统
这个是使用flask实现好看登录界面和友好的检测界面实现yolov8推理和展示,代码仅仅有2个html文件和一个python文件,真正做到了用最简洁的代码实现复杂功能。 测试通过环境: windows x64 anaconda3python3.8 ultralytics8.3.81 flask1.1.2…...
Cursor的使用感受,帮你使用好自动化编程工具,整理笔记
使用感受 说实话,我觉得cursor还是好用的,可能我刚开始使用,没有使用的非常的熟练,运用也没有非常的透彻,总体体验还是不错的,在使用它时,我优先考虑,前端页面功能复用的时候&#…...
2024浙江大学计算机考研上机真题
2024浙江大学计算机考研上机真题 2024浙江大学计算机考研复试上机真题 2024浙江大学计算机考研机试真题 2024浙江大学计算机考研复试机试真题 历年浙江大学计算机复试上机真题 历年浙江大学计算机复试机试真题 2024浙江大学计算机复试上机真题 2024浙江大学计算机复试机试真题 …...
JS逆向:通达OA Office Anywhere 2019 的前端密码加密逆向分析,并使用Python构建通达OA登录
免责声明 本文仅为技术研究与渗透测试思路分享,旨在帮助安全从业人员更好地理解相关技术原理和防御措施。任何个人或组织不得利用本文内容从事非法活动或攻击他人系统。 如果任何人因违反法律法规或不当使用本文内容而导致任何法律后果,本文作者概不负责。 请务必遵守法律…...
贴吧ip什么意思?贴吧ip可以查到姓名吗
贴吧作为百度旗下的一个重要社区平台,一直以来都吸引着大量用户进行交流和讨论。然而,随着网络环境的日益复杂,用户的隐私保护问题也日益凸显。其中,贴吧IP地址的显示及其与个人信息的关系,成为不少用户关注的焦点。本…...
【css酷炫效果】纯CSS实现进度条加载动画
【css酷炫效果】纯CSS实现进度条加载动画 缘创作背景html结构css样式完整代码基础版进阶版 效果图 通过CSS渐变与背景位移动画,无需JavaScript即可创建流体动态进度条。 想直接拿走的老板,链接放在这里:https://download.csdn.net/download/u…...
【后端开发面试题】每日 3 题(十三)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:https://blog.csdn.net/newin2020/category_12903849.html 📚专栏简介:在这个专栏中,我将会分享后端开发面试中常见的面试题给大家,每天的题目都是独…...
【Android Studio】解决遇到的一些问题
目录 前言 一、Invalid Gradle JDK configuration found. Open Gradle Settings Change JDK location 报错场景 解决方法 二、adb 不是内部或外部命令,也不是可运行的程序或批处理文件。 报错场景 解决方法 前言 Android Studio的安装过程,可以参…...
UnitTest框架管理测试用例——python自动化测试
UnitTest框架 UnitTest是Python自带一个单元测试框架,常用它来做单元测试。 注意:对于测试来说,UnitTest框架的作用是 自动化脚本(用例代码)执行框架————(使用UnitTest框架来管理 运行多个测试用例的) 为什么使用UnitTest框架 能够组织多个用例去执…...
后端接口开发完成后,接口地址访问不到提示404,Spring项目的包结构错误
后端接口开发完成后,接口地址访问不到提示404,Spring项目的包结构错误 是因为包结构错误,导致无法在请求地址下找到对应的方法,原来错误的包结构(自建controller、service、config等包建到了项目包之外、而非项目包之下…...
算法竞赛-基础算法-位运算
目录 1.快速幂 2.快速乘 3.lowbit(n) 4.其他 5.相关题目 6.小结 引言:位运算的主要特点之一是在二进制表示下不进位,一下为一些基础的位运算操作: 与或非异或and,&or,|not,~xor 1.快速幂 快速幂的计算原理就是基于位运算&#x…...
DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能📚页面效果📚指令输入�…...
深入解析音频编解码器(Audio CODEC):硬件、接口与驱动开发
音频编解码器(Audio CODEC)是音频处理系统中的核心组件,负责 模拟信号与数字信号的相互转换,广泛应用于 智能音箱、嵌入式系统、消费电子产品 等设备。本篇文章将从 硬件结构、接口解析、驱动开发 和 软件配置 等方面,…...
什么是 Fisher 信息矩阵
什么是 Fisher 信息矩阵 Fisher 信息矩阵是统计学和机器学习中一个重要的概念,它用于衡量样本数据所包含的关于模型参数的信息量。 伯努利分布示例 问题描述 假设我们有一个服从伯努利分布的随机变量 X X X,其概率质量函数为 P ( X ...
【项目合集】智能语音小车-微信小程序控制
功能需求: 车子检测环境温度、湿度,上报 APP、WEB 端显示实时数据可通过 APP 控制小车前进、左转、右转可通过语音控制小车前进后退车上一个 LED 灯,可通过 WEB、小程序控制在 APP、WEB 上均可注册登录 硬件清单 硬件 功能 备注 ESP32 …...
Vue3项目中可以尝试封装那些组件
在 Vue 3 项目中,组件的封装可以根据功能、复用性和业务需求进行划分。以下是一些常见的组件类型,适合封装为独立组件: 1. 基础 UI 组件 按钮 (Button) 封装不同样式、大小、状态的按钮。支持 disabled、loading 等状态。 输入框 (Input) 封…...
Leetcode——151.反转字符串中的单词
题解一 思路 最开始的想法是把一个字符串分为字符串数组,但是不知道一共有几个单词(当时没想起来split()),所以选择了用ArrayList储存字符串,在输出时没有考虑ArrayList可以存储空字符串,所以最开始的输出…...
Deepseek+QuickAPI:打造 MySQL AI 智能体入门篇(一)
目录 一、什么是 MySQL AI 智能体? 二、准备工作:认识工具 1. Deepseek 的大模型能力 2. QuickAPI 的功能 3. MySQL 数据库 三、动手实践:用自然语言打造智能体 1. 创建一个用户表 2. 添加样本数据 3. 执行查询 四、效果展示 五、…...
Redis系列:深入理解缓存穿透、缓存击穿、缓存雪崩及其解决方案
在使用Redis作为缓存系统时,我们经常会遇到“缓存穿透”、“缓存击穿”和“缓存雪崩”等问题,这些问题一旦出现,会严重影响应用性能甚至造成服务不可用。因此,理解这些问题的产生原因和解决方案非常重要。 本文将全面讲解缓存穿透…...
python局部变量和全局变量
文章目录 1.局部变量和全局变量2.局部变量2.1 局部变量的作用2.2 局部变量的生命周期 3. 全局变量3.1 函数不能直接修改全局变量的引用3.2 在函数内部修改全局变量的值3.3 全局变量定义的位置3.4 全局变量命名的建议 1.局部变量和全局变量 (1)局部变量 …...
⭐算法OJ⭐两数之和【哈希表】(C++ 实现)Two Sum
“两数之和”(Two Sum)是一道非常经典的算法题目,几乎是算法入门和面试准备的必做题之一。它的经典性体现在以下几个方面: 1. 算法入门的基础题目 这道题目是许多初学者接触 哈希表(Hash Table) 或 字典&…...
【AVRCP】Notification PDUs 深入解析与应用
目录 一、Notification PDUs 概述 二、GetPlayStatus:同步查询播放状态 2.1 命令功能与应用场景 2.2 请求格式(CT → TG) 2.3 响应格式(TG → CT) 2.4 注意事项 2.5 协议实现示例(伪代码) 三、RegisterNotification:异步事件订阅 3.1 命令概述 3.2 命令格式 …...
算法题(100):腐烂的苹果
审题: 本题需要我们判断苹果是否可以完全腐烂,若可以完全腐烂,那么最短腐烂的所需时间是多少 思路: 方法一:多源BFS 首先我们分析腐烂过程,第一批腐烂苹果开始扩散,然后第二批腐烂苹果继续扩散&…...
某快餐店用户市场数据挖掘与可视化
1、必要库的载入 import pandas as pd import matplotlib.pyplot as plt import seaborn as sns2、加载并清洗数据 # 2.1 加载数据 df pd.read_csv(/home/mw/input/survey6263/mcdonalds.csv)# 2.2 数据清洗 # 2.2.1 检查缺失值 print(缺失值情况:) print(df.isn…...
【微服务】如何用Azure容器应用Job处理异步HTTP API请求
【微服务】如何用Azure容器应用Job处理异步HTTP API请求 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 【微服务】如何用Azure容器应用Job处理异步HTTP API请求Azure容器应用中的长…...
安卓edge://inspect 和 chrome://inspect调试移动设备上的网页
edge://inspect 和 chrome://inspect 是用于调试浏览器中运行的网页和移动设备上的网页的工具。这两个工具分别属于 Microsoft Edge 和 Google Chrome 浏览器。以下是它们的详细介绍: chrome://inspect 如果是直接使用数据线调试,则只需要执行下面的第一…...
TX-LCN 框架
TX-LCN 框架通俗教学(面试场景版) 一句话概括 TX-LCN 是分布式事务的 “交通警察”,确保多个微服务操作要么全部成功(比如转账扣款和到账),要么全部回滚(比如网购下单失败后库存自动恢复&#…...
玩转github
me github 可以给仓库添加开发人员吗 4o 是的,GitHub允许仓库管理员为仓库添加开发人员,并设置这些开发人员的角色和权限。这里是一个简单的步骤指导,教你如何给一个 GitHub 仓库添加开发人员: 前提条件 你必须有这个仓库的权限&…...
Dubbo 深度解析
Dubbo 深度解析与实战指南 一、Dubbo 核心设计理念与应用场景 1.1 为什么需要 Dubbo? 随着互联网业务规模扩大,单体架构面临以下挑战: 服务依赖复杂:模块间耦合度高,难以独立迭代[[5]]。性能瓶颈:单一应…...
基于javaweb的SpringBoot校园运动会管理系统设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…...
Socket封装---模板方法类
目录 一、模板方法类 二、Socket的框架 三、TCPSocket对父类的虚函数重写 在平时写网络代码的时候,经常会涉及到socket套接字的部分,这一部分用的十分频繁,但是流程都是固定的,我实在是饱受其苦,但是由于C不像java一…...
牛客周赛84 题解 Java ABCDEFG AK实录
目录 题目地址 做题情况 A 题 B 题 C / D 题 E 题 F / G 题 题目地址 牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ 做题情况 A 题 import java.io.*; import java.math.*; import java.util.*;// xixi♡西 public class Main {static IOS scnew…...