The problem can be stated as: Given some sequential data, downsample the data according to the rate of change. That means, many samples where the rate of change is high and less samples if it is low.
The idea is to define a function that maps the evenly spaced indices of the data to unevenly spaced indices. Toward this aim we calculate the absolute values of the rate of change of the data: roc. We then invert this values, but because the rate can be zero, we need to add a damping term: 1/(roc+damp)
. damp
will determine how uneven the outcome will be and needs to be adapted to the data. We now have a function that is high where the rate is low and vice versa. If we integrate this function, we get the searched for function that maps the indices unevenly. In the following we have discrete data, therefore we take differences instead of derivatives and accumulate instead of integrate.
We start by defining some test data. Here we choose data over half a period of a sine.
dat = Table[Sin[x], {x, 0, Pi, Pi/100}] // N;
n = Length@dat;
Then we calculate the absolute values of the differences between the data points and invert this to give the inverse rate, using a damping factor of 0.005. Next we accumulate this data. Now, the range of this data is wrong, we need to normalize it to bring it into range 1..n, so that we may use this as indices into the original data.
invrate = 1/(0.005 + Abs@Differences[dat]);
acc = Accumulate[invrate];
newind = Round[n acc/acc[[-1]]];
Now we have everything to downsample the data. As an example we choose a downsampling factor of 5. We create down sampled indices and feed it to newind. Note that we lost one data point when we took the differences, therefore the highest index is: n-1. By this we get the new indices: samplesx, values: samplesy and points: samplesxy that we use for a plot:
samplesx = newind[[Range[1, n - 1, 5]]];
samplesy = dat[[samplesx]];
samplesxy = Table[{i, dat[[i]]}, {i, samplesx}];
ListLinePlot[dat, Epilog -> Point[samplesxy]]
With[{x = data[[All, 1]], y = data[[All, 2]]}, With[{dx = Differences@x}, dx . (Most[y] + Rest[y])/2 ]]
— would that be accurate & fast enough? $\endgroup$