2
$\begingroup$

I have list of rules from where a DateListStepPlot can be created to visualize the problem:

dateToPopulationRules = {DateObject[{2019, 1, 1}] -> 5, DateObject[{2019, 2, 1}] -> 10, DateObject[{2019, 2, 13}] -> 6, DateObject[{2019, 4, 4}] -> 1};
DateListStepPlot[List @@@ dateToPopulationRules, PlotMarkers -> Automatic, FrameLabel -> {None, "Population"}]

enter image description here

I want to create an efficient function for population using a huge instance of dateToPopulationRules. Here's my poor implementation:

Clear[population];
population[dateObj_] := 0;
Table[
  With[{dateLim = First@dpr, pop = Last@dpr},
   population[dateObj_] := Condition[pop, dateObj >= dateLim]
   ]
  , {dpr, dateToPopulationRules}];

An example showing how the population function works is below. You may want to see DownValues@population in case that helps understanding my code.

In[11]:= population[DateObject[{2019, 3, 1}]]
Out[11]= 5

Although this approach is effective I don't think is the most efficient. I would like to see another solution using a Nearest function or other function that can handle large data sets efficiently.

$\endgroup$
2
  • 4
    $\begingroup$ If you want it to be efficient, it's probably best to convert the dates to AbsoluteTime. Simple numbers will beat date objects in performance most of the time. You can use Interpolation[data, InterpolationOrder -> 0] to get the interpolation behavior you're looking for. $\endgroup$ – Sjoerd Smit Nov 12 '19 at 13:39
  • $\begingroup$ Wow! It looks so obvious now. Still, it would be good to see the implementation. Thanks! $\endgroup$ – Ariel Sepulveda Nov 12 '19 at 14:06
2
$\begingroup$

You could use Interpolation as suggested @Sjoerd, for example:

data = List @@@ dateToPopulationRules /. d_DateObject :> AbsoluteTime[d];

p = Interpolation[
    data . {{-1, 0}, {0, 1}},
    InterpolationOrder->0
] @* Minus;

where I need to use a double negation to get the end point behavior correct. Visualization:

Plot[
    p[x],
    {x, AbsoluteTime@DateObject[{2019,1,1}], AbsoluteTime@DateObject[{2019,6,1}]},
    PlotRange->{0,10.5},
    Ticks->{
        Charting`DateTicksFunction[Automatic, DateTicksFormat -> {Automatic}],
        Automatic
    },
    Epilog -> {PointSize[Large], Point[data]} 
]

enter image description here

If you want a faster function, you could try using StepFunction from How can the behavior of InerpolationOrder->0 be controlled:

q = StepFunction[data, Right];
Plot[
    q[x],
    {x, AbsoluteTime@DateObject[{2019,1,1}], AbsoluteTime@DateObject[{2019,6,1}]},
    PlotRange->{0,10.5},
    Ticks->{
        Charting`DateTicksFunction[Automatic, DateTicksFormat -> {Automatic}],
        Automatic
    },
    Epilog -> {PointSize[Large], Point[data]} 
]

enter image description here

Speed comparison:

times = RandomReal[
    AbsoluteTime /@ {DateObject[{2019, 1, 1}], DateObject[{2019, 4, 1}]},
    10^5
];

r1 = p[times]; //RepeatedTiming
r2 = q[times]; //RepeatedTiming

r1===r2

{0.14, Null}

{0.0072, Null}

True

So, using StepFunction is almost 20 times faster.

$\endgroup$
2
  • $\begingroup$ Excellent! I assume your StepFunction will eventually be added to the Wolfram Language. $\endgroup$ – Ariel Sepulveda Nov 13 '19 at 19:55
  • $\begingroup$ @ArielSepulveda I'm planning to add it as a ResourceFunction, no idea whether somebody might add a kernel function to do this. $\endgroup$ – Carl Woll Nov 13 '19 at 21:33
2
$\begingroup$

You may useTimeSeries with the ResamplingMethod option.

tsPop = TimeSeries[List @@@ dateToPopulationRules,
  ResamplingMethod -> {"Interpolation", InterpolationOrder -> 0}]

Mathematica graphics

InterpolationOrder -> 0 repeats prior value until new value is defined.

tsPop[DateObject /@ {{2019, 1, 30}, {2019, 2, 1}}]
{5, 10}

Plot with DateListStepPlot.

DateListStepPlot[tsPop, Mesh -> Full]

Mathematica graphics

Hope this helps.

$\endgroup$
1
  • $\begingroup$ Very useful and a new window opened into TimeSeries. Thanks! Based on a simple test using RepeatedTiming q function based on StepFunction seems to be near one order faster than tsPop. $\endgroup$ – Ariel Sepulveda Nov 13 '19 at 19:50

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.