Peak Detection in Time Series

后端 未结 6 1737
栀梦
栀梦 2021-02-01 07:59

I\'m currently working on a little project in which I want to compare two time-series. The similarity measure is really vague, they are considered to be similar if the two time

相关标签:
6条回答
  • 2021-02-01 08:43

    You seem to simply look for slope inversion (from positive to negative and vice versa). A rough java algo could be (not tested):

    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;
    }
    

    Finally, a good way to measure similarity is correlation. In your case, I would look at % move correlation (in other words, you want your 2 series to go up or down at the same time) - that's typically what is done in finance where you calculate the correlation between 2 assets returns for example:

    • create 2 new series with the % move for each point of the 2 series
    • calculate the correlation between those 2 series

    You can read more about returns correlations here for example. In summary, if your values are:

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

    The "returns" series will be:

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

    And you calculate the correlation of those 2 returns series (in this example: 0.96) to get a measure of how much the 2 curves look alike. You might want to adjust the result for variance (i.e. if one shape has a much wider range than the other).

    0 讨论(0)
  • 2021-02-01 08:43

    If you want something statistically more sound, you could measure the cross correlation between the two series. You can check Wikipedia, or this site.

    0 讨论(0)
  • 2021-02-01 08:44

    I'm not sure about correlation between time series or specific peak detection algorithms but here's a little maximum peak detection algorithm I wrote. It doesn't detect the minimum peaks but could easily be extended to do so by reversing the operations in the for loop.

    List<XYDataItem> maxPoints = ... //list to store the maximums
    XYDataItem leftPeakPoint = new XYDataItem(0, 0);
    int leftPeakPointIndex = 0;
    XYDataItem rightPeakPoint = new XYDataItem(0, 0);
    boolean first = true;
    int index = -1;
    List<XYDataItem> pointList = (List<XYDataItem>) lrpSeries.getItems();
    for (XYDataItem point : pointList) {
        index++;
        if (first) {
            //initialize the first point
            leftPeakPoint = point;
            leftPeakPointIndex = index;
            first = false;
            continue;
        }
        if (leftPeakPoint.getYValue() < point.getYValue()) {
            leftPeakPoint = point;
            leftPeakPointIndex = index;
            rightPeakPoint = point;
        } else if (leftPeakPoint.getYValue() == point.getYValue()) {
            rightPeakPoint = point;
        } else {
            //determine if we are coming down off of a peak by looking at the Y value of the point before the
            //left most point that was detected as a part of a peak
            if (leftPeakPointIndex > 0) {
                XYDataItem prev = pointList.get(leftPeakPointIndex - 1);
                //if two points back has a Y value that is less than or equal to the left peak point
                //then we have found the end of the peak and we can process as such
                if (prev.getYValue() <= leftPeakPoint.getYValue()) {
                    double peakx = rightPeakPoint.getXValue() - ((rightPeakPoint.getXValue() - leftPeakPoint.getXValue()) / 2D);
                    maxPoints.add(new XYDataItem(peakx, leftPeakPoint.getYValue()));
                }
            }
            leftPeakPoint = point;
            leftPeakPointIndex = index;
            rightPeakPoint = point;
        }
    }
    

    The result of this will center the detected peak on flat sections where the Y value of consecutive data points is the same. XYDataItem is just a class that contains an X and Y value as a double. This can easily be replaced with something equivalent.

    0 讨论(0)
  • 2021-02-01 08:49

    Late answer for the question but Dynamic Time Warping (DTW) algorithm is the right choise for this type problems. Basicly there is a two time series one of them is template other one is sample. I recomment to check source code of Smile libraries DynamicTimeWarping class.

    http://haifengl.github.io/

    0 讨论(0)
  • 2021-02-01 08:51

    The peakdet algorithm as proposed by Eli Billauer works very well and is easy to implement:

    http://www.billauer.co.il/peakdet.html

    The algorithm works especially well with noisy signals where methods using the first derivative fail.

    0 讨论(0)
  • 2021-02-01 08:56

    You can use a very simple local extremes detector:

    // 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`
    

    This will work nice with smooth series. If you have a certain variation in your data, you should put it through a low pass filter first. A very simple implementation of a low pass filter would be the moving average (every point is replaced by the average of the nearest k values, with k being the window size).

    0 讨论(0)
提交回复
热议问题