Context: I have millisecond timestamped sample data that I want to convert to a uniformly sampled series. This I do by padding each interval with repeated values (pbp ~ 'pad by position'}.
The following function works as intended, (I would credit the trick of using a range to generate an explicit list of indices for speed if I could remember who it came from...)
SetAttributes[pbp, HoldAll];
pbp[s_,idx_]:=
Module[{ca,len, idx2},
idx2 = idx - idx[[1]] +1;
ca = ConstantArray[0,len=Last[idx]-First[idx]+1];
(ca[[#1[[1]]]]=#1[[2]]) & /@ Table[{Range[idx2[[i]],idx2[[i+1]]-1], s[[i]]}, {i,1,Length[idx2]-1}];
ca[[len]]=Last[s];
Return[ca];
];
For nSamples = 100k pbp runs in about 1.5s but my data set is orders of magnitude larger and I have other things to do afterwards so I would like any performance gain I can get, but I can't get it to compile. Being aware of some ConstantArray compilation issues I substituted a table, and as far as I can tell from CompilerFunctions[] there is nothing controversial in this:
pbpCompiled=
Compile[{{s, _Real, 1}, {idx, _Integer, 1}},
Module[{ca,len, idx2},
idx2 = idx - idx[[1]] +1;
len=Last[idx]-First[idx]+1;
ca = Table[0, {j,1,len}];
(Part[ca, Part[#, 1]] = Part[#, 2]) & /@ Table[{Range[idx2[[i]],idx2[[i+1]]-1], s[[i]]}, {i,1,Length[idx2]-1}];
ca[[len]]=Last[s];
ca
],
CompilationTarget -> "C", "RuntimeOptions"->"Speed"];
(NB, it was more idiomatically written but became less so as I tried to tease elements apart for debugging.)
However, I get this error (3x before further cpintIt are suppressed)
Compile`GetElement[System`Private`CompileSymbol[0],System`Private`CompileSymbol[1]][[1]] at position 2 of ca[[Compile`GetElement[System`Private`CompileSymbol[0],System`Private`CompileSymbol[1]][[1]]]] should be either a nonzero integer or a vector of nonzero integers; evaluation will use the uncompiled function
Q1 - what is wrong with the definition of the function to be compiled/how can it be fixed?
Q2 - is there some other uncompiled approach to the problem that would be significantly faster than the uncompiled version above?
The following can be used to provide some test data...
nSamples = 100000;
sampleSeries = RandomReal[{0, 1}, nSamples];
sampleTimes = IntegerPart@(1000 Accumulate[RandomReal[{0.001, 0.500}, nSamples]]);
then called as e.g. pbp[sampleSeries, sampleTimes]
pbp
? Why not just create a zeroth order InterpolatingFunction from the data? $\endgroup$ifun = Interpolation[Transpose[{sampleSeries, sampleTimes}], InterpolationOrder -> 0]; Plot[ifun[x], {x, 614, 2383}]
(small segment at the beginning of 100 samples spanning 493 to ). Got a flat line and error; seems ifun[x] for any x -> "Input value {nnn} lies outside the range of data in the interpolating function". Maybe this is a Q2 answer but I can't tell :( $\endgroup$p[s_, idx_] := Join @@ MapThread[ ConstantArray[#1, #2] &, {s, Append[Differences[idx], 1]}];
a bit more concise, s/b quicker... $\endgroup$TimeSeries
with its built-inTimeSeriesResample
method? reference.wolfram.com/language/guide/TimeSeries.html $\endgroup$