当前位置: 首页 > article >正文

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) = 学生们分数的分散程度

现在有两个作弊情况:

  1. 张三:偷偷抄答案考了100分(极端异常值)
  2. 李四:偶尔偷看考了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)=T1t=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- pvalue 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 分解&#x1f680; 在时序预测任务中&#xff0c;为了情绪化信号的各种成分&#xff0c;例如趋势信息季节信息等往往都需要对信号进行分解。目前熟知的分解方式有很多种&#xff0c;经验模态分解 EMD 变分模态分解 VMD &#xff0c;还有 集合经验模态分解 EEMD&#xff0c…...

基于SpringBoot + Vue 的房屋租赁系统

基于springboot的房屋租赁管理系统-带万字文档 SpringBootVue房屋租赁管理系统 送文档 本项目有前台和后台两部分、多角色模块、不同角色权限不一样 共分三种角色&#xff1a;用户、管理员、房东 管理员&#xff1a;个人中心、房屋类型管理、房屋信息管理、预约看房管理、合…...

Excel中国式排名,3种方法!

大家好&#xff0c;我是小鱼。 什么是中国式排名呢&#xff1f; 举个例子比如说公司一共有10名员工进行成绩考核&#xff0c;如果9个人考核成绩都是90分&#xff0c;你是89分&#xff0c;按照国际惯用的排名法则&#xff1a;9 个人考核成绩并列第一&#xff0c;你第10名&…...

Flutter:跑马灯公告栏

组件 import dart:async; import package:flutter/material.dart; import package:ducafe_ui_core/ducafe_ui_core.dart;class MarqueeNotice extends StatefulWidget {/// 公告数据列表&#xff0c;每条公告包含title和descfinal List<Map<String, String>> notic…...

Jmeter下载及环境配置

Jmeter下载及环境配置 java环境变量配置配置jdk环境变量检查是否配置成功JMeter下载 java环境变量配置 访问地址&#xff1a; https://www.oracle.com/cn/java/technologies/downloads/ 注意&#xff1a;需要自己注册账号 下载完成&#xff0c;解压后的目录为&#xff1a; …...

【初级篇】如何使用DeepSeek和Dify构建高效的企业级智能客服系统

在当今数字化时代,企业面临着日益增长的客户服务需求。使用Dify创建智能客服不仅能够提升客户体验,还能显著提高企业的运营效率。关于DIfy的安装部署,大家可以参考之前的文章: 【入门级篇】Dify安装+DeepSeek模型配置保姆级教程_mindie dify deepseek-CSDN博客 AI智能客服…...

OpenCV特征提取与深度学习CNN特征提取差异

一、特征生成方式 ‌OpenCV传统方法‌ ‌手工设计特征‌&#xff1a;依赖人工设计的算法&#xff08;如SIFT、FAST、BRIEF&#xff09;提取图像中的角点、边缘等低层次特征&#xff0c;需手动调整参数以适应不同场景‌。‌数学驱动‌&#xff1a;基于梯度变化、几何变换等数学规…...

微信小程序threejs三维开发

微信小程序threejs开发 import * as THREE from three; const { performance, document, window, HTMLCanvasElement, requestAnimationFrame, cancelAnimationFrame, core, Event, Event0 } THREE .DHTML import Stats from three/examples/jsm/libs/stats.module.js; im…...

关于在vue3中使用keep-live+component标签组合,实现对指定某些组件进行缓存或不缓存的问题

今天收到一个需求&#xff0c;在vue3写的动态组件条件下&#xff0c;要对指定的几个vue组件进行缓存。 我们用到了keep-livecomponent标签进行动态的渲染 可以通过exclude(排除)和include(包含)来进行指定缓存 <el-tabs v-model"activeName" type"card"…...

[Java实战]性能优化qps从1万到3万

一、问题背景 ​ 事情起因是项目上springboot项目提供的tps达不到客户要求,除了增加服务器提高tps之外,作为团队的技术总监,架构师,技术扛把子,本着我不入地狱谁入地狱的原则,决心从代码上优化,让客户享受到飞一般的感觉。虽然大多数编程工作在写下第一行代码时已经完成…...

30天学习Java第四天——设计模式

设计模式概述 设计模式是一套被广泛接受的、经过试验的、可反复使用的基于面向对象的软件设计经验总结&#xff0c;它是开发人员在软件设计时&#xff0c;对常见问题的解决方案的总结和抽象。 一句话就是&#xff0c;设计模式是针对软件开发中常见问题和模式的通用解决方案。 …...

HTML块级元素和内联元素(简单易懂)

在HTML中&#xff0c;元素可以分为块级元素&#xff08;Block-level elements&#xff09;和内联元素&#xff08;Inline elements&#xff09;。这两类元素在页面布局和样式应用上有不同的特点和用途。 一、块级元素&#xff08;Block-level elements&#xff09; 1. 定义 …...

Webpack 和 Vite 的主要区别

Webpack 和 Vite 的主要区别&#xff0c;从构建机制、开发体验、生产优化等多个维度进行对比&#xff1a; 1. 构建机制与速度 Webpack 全量打包&#xff1a;启动时必须分析所有模块依赖关系&#xff0c;进行全量打包&#xff0c;生成 Bundle 文件。项目越大&#xff0c;冷启动时…...

大数据-spark3.5安装部署之standalone模式

真实工作中还是要将应用提交到集群中去执行&#xff0c;Standalone模式就是使用Spark自身节点运行的集群模式&#xff0c;体现了经典的master-slave模式。集群共三台机器&#xff0c;具体如下 u22server4spark&#xff1a; master worker u22server4spark2&#xff1a; worke…...

技术视界|构建理想仿真平台,加速机器人智能化落地

在近期的 OpenLoong 线下技术分享会 上&#xff0c;松应科技联合创始人张小波进行了精彩的演讲&#xff0c;深入探讨了仿真技术在机器人智能化发展中的关键作用。他结合行业趋势&#xff0c;剖析了现有仿真平台的挑战&#xff0c;并描绘了未来理想仿真系统的设计理念与实现路径…...

AutoGen多角色、多用户、多智能体对话系统

2023-03-11-AutoGen 使用【autoGenchainlitdeepSeek】实现【多角色、多用户、多智能体对话系统】 1-核心思路 01&#xff09;技术要点&#xff1a;autoGenchainlitdeepSeek02&#xff09;什么是autoGen->autogen是微软旗下的多智能体的框架03&#xff09;什么是chainlit-&g…...

SQL99 多表查询

内连接&#xff1a; select name, depart_name, city from employee e join department d on e.depart_id d.depart_id join location l on d.locat_id l.locat_id; 外连接 注&#xff1a;本图取自博客园大佬"anliux"的博客&#xff0c;原帖链接&#xff1a;【学…...

ubuntu20.04装nv驱动的一些坑

**1.一定要去bios里面关闭secure boot&#xff0c;否则驱动程序需要签名&#xff0c;安装了的驱动无法被识别加载 2.假如没有关闭secure boot然后装了驱动&#xff0c;然后再去关闭secure boot&#xff0c;可能会导致进入不了ubuntu的情况 此时&#xff0c;先恢复secure boot&…...

sql靶场5-6关(报错注入)保姆级教程

目录 sql靶场5-6关&#xff08;报错注入&#xff09;保姆级教程 1.第五关 1.步骤一&#xff08;闭合&#xff09; 2.步骤二&#xff08;列数&#xff09; 3.报错注入深解 4.报错注入格式 5.步骤三&#xff08;数据库表名&#xff09; 6.常用函数 7.步骤四&#xff08;表…...

矩阵分析-浅要理解(深度学习方向)

梯度分析与最优化 在深度学习的任务中&#xff0c;我们所期望的是训练一个神经网络&#xff0c;使得预测结果与真实标签之间的误差最小化&#xff0c;这可以近似看作是一个提供梯度下降等优化找到全局最优解的凸优化问题。 奇异值分解 在信息工程领域&#xff0c;对数据处理的…...

校园安全用电怎么保障?防触电装置来帮您

引言 随着教育设施的不断升级和校园用电需求的日益增长&#xff0c;校园电力系统的安全性和可靠性成为了学校管理的重要课题。三相智能安全配电装置作为一种电力管理设备&#xff0c;其在校园中的应用不仅能够提高电力系统的安全性&#xff0c;还能有效保障师生的用电安全&am…...

第十五届蓝桥杯大学B组(握手问题、小球反弹、好数)

一、握手问题 思路1&#xff1a; 1)先让所有人相互握手 第一个人49次 第二个人48次 第五十个人0次 共计01249 2)减去7个没握手的 016 #include<stdio.h> int main() {int a 50*49/2 - 7*6/2;printf("%d\n",a);return 0; } 运行结果&#xf…...

【教学类-43-26】20240312 数独4宫格的所有可能(图片版 576套样式,空1格-空8格,每套65534张*576小图=3千万张小图)

背景需求&#xff1a; 之前做了三宫格所有可能图片 510小图*12套6120图&#xff0c;所以3分钟就生成了 【教学类-43-25】20240311 数独3宫格的所有可能&#xff08;图片版 12套样式&#xff0c;空1格-空8格&#xff0c;每套510张&#xff0c;共6120小图&#xff09;-CSDN博客…...

如何手动使用下载并且运行 QwQ-32B-GGUF

首先使用安装 pip install ModelScope 使用 ModelScope 下载对应的模型 modelScope download --model Qwen/QwQ-32B-GGUF qwq-32b-q4_k_m.gguf 第二步开始下载 ollama git clone https://githubfast.com/ggerganov/llama.cpp # githubfast.com 可以加速下载 切换到目录&am…...

Spring Boot对接twilio发送邮件信息

要在Spring Boot应用程序中对接Twilio发送邮件信息&#xff0c;您可以使用Twilio的SendGrid API。以下是一个简单的步骤指南&#xff0c;帮助您完成这一过程&#xff1a; 1. 创建Twilio账户并获取API密钥 注册一个Twilio账户&#xff08;如果您还没有的话&#xff09;。在Twi…...

约束优化技术:KKT条件的完整推导与应用

前言 本文隶属于专栏《机器学习数学通关指南》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见《机器学习数学通关指南》 ima 知识库 知识库广场搜索&#…...

大数据面试之路 (二) hive小文件合并优化方法

大量小文件容易在文件存储端造成瓶颈&#xff0c;影响处理效率。对此&#xff0c;您可以通过合并Map和Reduce的结果文件来处理。 一、合并小文件的常见场景 写入时产生小文件&#xff1a;Reduce任务过多或数据量过小&#xff0c;导致每个任务输出一个小文件。 动态分区插入&…...

对比文章相似度的余弦相似度算法的原理

近期不是项目遇到对比代码的相似度&#xff0c;来判断代码是否存在抄袭嘛。通过研究采用了余弦相似度来对比。既然接触的一个新的东西&#xff0c;怎么也得研究下吧。 一、什么是余弦相似度 利用余弦相似度对比文章相似度的原理&#xff0c;主要基于向量空间模型&#xff0c;通…...

使用vue的路由打开新标签页跳转

vue的路由只支持在本标签页跳转&#xff0c;要用vue的路由打开新标签页需要做处理再用window.open方法打开&#xff1a; // 在当前标签页中跳转 router.push({path: /new-page,query: {id: id.toString(),} });// 在新标签页中打开 const routeData router.resolve({path: /n…...

山东省新一代信息技术创新应用大赛-计算机网络管理赛项(样题)

目录 竞赛试题 网络拓扑 配置需求 虚拟局域网 IPv4地址部署 OSPF及路由部署 配置合适的静态路由组网 MSTP及VRRP链路聚合部署 IPSEC部署 路由选路部署 设备与网络管理部署 1.R1 2.R2 3.S1 4.S2 5.S3 竞赛试题 本竞赛使用HCL(华三云实验室)来进行网络设备选择…...