algorithmtime-serieslanguage-agnosticdata-processingtimeserieschart

time series data change point detection


I am trying to segment a time series data into different zones.

In each time period, the pressure is running under an allowed max stress level (was not told before hand). Please see the pictures below.

edit each time period is more than a week.

enter image description here

How to detect the start / end of different time period? Would anyone point me some direction?

Once the time different time zones are divided, I guess I could average several max readings in each zone to have the max allowed stress.


Solution

  • I would take let's say enough values for 1h. Then you calculate the average value. After that, you set the the average value in relation with the one before. Some Pseudocode, to make it visual.

    class Chunk:
      private double[] values;//For one hour, for example.
      double average();
    enum Relation:
      FALLING,RISING,EQUAL
    
    func algorithm(Chunk[] chunks){
      double averages=new double[chunks.length];
      for(int i=0;i<chunks.length;i++)
        averages[i]=chunks[i].average();
      //Got averages, now make it rising or falling or stay same.
      Relation[] relations=new Relation[chunks.length];
      for(int i=1;i<chunks.length;i++){
        double diff=averages[i]-averages[i-1];
        if(diff==0) //TODO, a bit of difference is allowed (Like deviations of +-3)
         relations[i]=EQUALS;
        else
         relations[i]=diff>0?RISING:FALLING;
      }
     // After that, you have to find sequences of many FALLING or RISING, followed by many EQUALS
    }
    

    To proceed with this array of Relations, you could divide it into smaller arrays, calculate the average (Like FALLING=0,RISING=1,EQUAL=2). After that you simply "merge" them like this:

    F=FALLING
    R=RISING
    E=EQUALS
    //Before merging
    [RREEEEFFEEEEERRREEEE]
    //After merging
    [REFERE]
    

    And there you can see the mountains and valleys.

    Now, to get the exact values, when a mountain or valley starts, you have to extend Chunk a bit.

    class Chunk:
      //The value on x-Axis + the value of y-Axis
      private Tuple<Time,Double>[] values;
      //Tuple of Range, this chunk uses and the average value of this range
      Tuple<Tuple<Time,Time>,double> average();
    

    Furthermore, you can't use raw Relation anymore, you have to wrap it with the Range, from where it starts to the end.