时间序列中的峰值检测

2022-09-04 02:41:20

我目前正在做一个小项目,我想在其中比较两个时间序列。相似性度量实际上是模糊的,如果两个时间序列大致具有相同的形状,则它们被认为是相似的。

所以我对自己说:“好吧,如果它们只需要具有相同的形状,我只是比较两个时间序列的峰值,如果峰值位于同一位置,那么时间序列肯定会相似”

我现在的问题是找到一个好的峰值检测算法。我用了谷歌,但我只提出了论文《时间序列中峰值检测的简单算法》。问题是,本文中描述的算法在非常极端和薄的峰值下工作得很好,但在大多数情况下,我的时间序列具有相当平坦的峰值,因此它们不会被检测到。

有谁知道我在哪里可以找到或搜索一种算法来检测下图所示的峰值?

time-series


答案 1

您似乎只是寻找斜率反转(从正到负,反之亦然)。一个粗略的java算法可能是(未经测试):

List<Point> points = ... //all the points in your curve
List<Point> extremes = new ArrayList<Point> ();
double previous = null;
double previousSlope = 0;

for (Point p : points) {
    if (previous == null) { previous = p; continue; }
    double slope = p.getValue() - previous.getValue();
    if (slope * previousSlope < 0) { //look for sign changes
        extremes.add(previous);
    }
    previousSlope = slope;
    previous = p;
}

最后,衡量相似性的一个好方法是相关性。在你的例子中,我会看看%的移动相关性(换句话说,你希望你的2个序列同时上升或下降) - 这通常是在金融中所做的,你计算2个资产回报之间的相关性,例如:

  • 创建 2 个新系列,2 个系列的每个点的移动百分比
  • 计算这两个序列之间的相关性

例如,您可以在此处阅读有关退货相关性的更多信息。总之,如果您的值为:

Series 1  Series 2
 100        50
 98         49
 100        52
 102        54

“退货”系列将是:

Series 1  Series 2
 -2.00%     -2.00%
 +2.04%     +6.12%
 +2.00%     +3.85%

然后,您计算这 2 条返回序列的相关性(在本例中为 0.96),以衡量 2 条曲线的相似程度。您可能希望调整方差的结果(即,如果一个形状的范围比另一个形状大得多)。


答案 2

您可以使用一个非常简单的局部极端检测器:

// those are your points:
double[] f = {1, 2, 3, 4, 5, 6, 5, 4, 7, 8, 9, 3, 1, 4, 6, 8, 9, 7, 4, 1};
List<Integer> ext = new ArrayList<Integer> ();
for (int i = 0; i<f.length-2; i++) {
  if ((f[i+1]-f[i])*(f[i+2]-f[i+1]) <= 0) { // changed sign?
    ext.add(i+1);
  }
}
// now you have the indices of the extremes in your list `ext`

这将很好地工作与平滑系列。如果数据有某种变化,则应首先将其置于低通滤波器中。低通滤波器的一个非常简单的实现是移动平均线(每个点都被最接近的k值的平均值替换,其中k是窗口大小)。


推荐