1
$\begingroup$

It is possible to do simple math between TemporalSeries objects. For example

es=EventSeries[{{{2016, 1, 1}, 2}, {{2016, 1, 3}, 2.1}}];
td=TemporalData[{{{2016, 1, 1}, 2}, {{2016, 1, 3}, 3.1}}];
es*td (* works fine *)

This returns a TemporalData object with the path {{3660595200, 4}, {3660768000, 6.51}}.

This method does not work however if the objects being manipulated have differing dimensions.

es=EventSeries[{{{2016, 1, 1}, 2}, {{2012, 1, 3}, 1.9}, {{2016, 1, 3}, 2.1}}];
td=TemporalData[{{{2016, 1, 1}, 2}, {{2016, 1, 3}, 3.1}}];
es*td (* ka-boom *)

With the data I'm using, one series or the other may be missing data at various time stamps, and it would be acceptable to either interpolate for those missing points or to simply omit them from the computation and the output.

I've been dealing with this problem in several steps,

  1. Make a list of the dates that all the series have in common with intersectionDates=Apply[Intersection, Map[#["Path"][[All, 1]] &, listOfTD]
  2. Extract the points for only those dates with alignedData=Map[Select[#, MemberQ[intersectiondates, #[[1]]] &]&, listOfTD]
  3. And finally turn the output back into TemporalData with Map[TimeSeries[#] &, alignedData]

In practice I have additional code to remove duplicate dates, if any exist, to convert EventSeries back to EventSeries, and some other bells and whistles, not shown above.

The problem is, this method is unusably slow for large datasets. With a few hundred points, it works fine, but with 5000+, it becomes intolerable.

I welcome any suggestions for approaches that would allow me to complete simple math between TemporalData objects of differing dimensions much faster.

$\endgroup$
1
$\begingroup$

Given two TimeSeries (ts1 and ts2), I was able to speed up my results about 60x with the following:

  1. paths=Map[#["Path"] &, {ts1,ts2}];
  2. commonDates=Intersection[paths[[1, All, 1]], paths[[2, All, 1]]];
  3. fakeDatepath=Transpose[{commonDates, Table[-1, {Length[commonDates]}]}];
  4. shortPaths=Map[(TemporalData[Intersection[#, fakeDatepath, SameTest -> (#1[[1]] == #2[[1]] &)]]) &, paths];
  5. Map[TemporalData[#]&, shortPaths]

My production code works with an arbitrary number of TimeSeries simultaneously, using a generalized form of this approach.

$\endgroup$
  • 1
    $\begingroup$ paths = Through[{ts1, ts2}["Path"]]; is slightly neater. $\endgroup$ – J. M. will be back soon Jul 7 '16 at 23:39
  • $\begingroup$ @J.M. OK, but any suggestions on making it faster? Each "intersection" still takes several minutes. $\endgroup$ – Michael Stern Jul 8 '16 at 10:44
1
$\begingroup$

If you want to interpolate then use TimeSeriesThread to combine TimeSeries (by default TimeSeries uses linear interpolation):

In[96]:= ts1 = TimeSeries[{{{2016, 1, 1}, 2}, {{2012, 1, 3}, 1.9}, {{2016, 1, 3}, 
     2.1}}];
ts2 = TimeSeries[{{{2016, 1, 1}, 2}, {{2016, 1, 3}, 3.1}}];

In[100]:= res = TimeSeriesThread[Times @@ # &, {ts1, ts2}];

During evaluation of In[100]:= InterpolatingFunction::dmval: Input value {3534537600} lies outside the range of data in the interpolating function. Extrapolation will be used.

In[101]:= Normal[res]

Out[101]= {{DateObject[{2012, 1, 3}], -1520.86}, {DateObject[{2016, 1,
     1}], 4.}, {DateObject[{2016, 1, 3}], 6.51}}

If you use TemporalData, then default is the interpolation with order 0.

If you use EventSeries, no interpolation is applied and Missing[] is created:

    In[87]:= 
es1 = EventSeries[{{{2016, 1, 1}, 2}, {{2012, 1, 3}, 1.9}, {{2016, 1, 3}, 
         2.1}}];
es2 = EventSeries[{{{2016, 1, 1}, 2}, {{2016, 1, 3}, 3.1}}];

In[94]:= res = TimeSeriesThread[Times @@ # &, {es1, es2}];

In[95]:= Normal[res]

Out[95]= {{DateObject[{2012, 1, 3}], 
  1.9 Missing[]}, {DateObject[{2016, 1, 1}], 
  4}, {DateObject[{2016, 1, 3}], 6.51}}
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.