Time-series forecasting

Hi all,
I'm trying to implement the popular Triple Exponential Smoothing (Holt-Winters), much like the FORECAST.ETS function in Excel, to predict the next data points in a sequence.

I used the Smooth node for this task, with α=25 (α=0.25) to predict the following seasonal random sequence:

Values:
[0.755154261,0.912094449,0.884490302,0.722404901,0.917280197,0.825058562,0.880320681,0.796308845,0.79255487,0.76197476]
Timeline:
[9:49,9:50,9:51,9:52,9:53,9:54,9:55,9:56,9:57,9:58]

Here's the expected result: (9:59=>0.786928627,10:00=>0.782188051,10:01=>0.777447474)

Here's what I have so far:
image

My flow:

[{"id":"9071add5.fb751","type":"inject","z":"f71e5505.8bfbf8","name":"","topic":"","payload":"0.755154261","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1380,"wires":[["8cfa28e1.2d6e88","e592ccaa.befed","93b42cdf.d04b3"]]},{"id":"8cfa28e1.2d6e88","type":"smooth","z":"f71e5505.8bfbf8","name":"Mean","property":"payload","action":"mean","count":"10","round":"","mult":"single","reduce":true,"x":490,"y":1560,"wires":[["b3061169.2ecb3"]]},{"id":"df715d88.163c4","type":"debug","z":"f71e5505.8bfbf8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":790,"y":1600,"wires":[]},{"id":"93b42cdf.d04b3","type":"smooth","z":"f71e5505.8bfbf8","name":"HPF = α","property":"payload","action":"high","count":"25","round":"","mult":"single","reduce":true,"x":500,"y":1640,"wires":[["c9803255.0832d"]]},{"id":"e592ccaa.befed","type":"smooth","z":"f71e5505.8bfbf8","name":"LPF = α","property":"payload","action":"low","count":"25","round":"","mult":"single","reduce":true,"x":500,"y":1600,"wires":[["cef6c815.723e18"]]},{"id":"ce89aa4a.ce84c8","type":"inject","z":"f71e5505.8bfbf8","name":"","topic":"","payload":"0.912094449","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1420,"wires":[["8cfa28e1.2d6e88","e592ccaa.befed","93b42cdf.d04b3"]]},{"id":"c252aaad.b24838","type":"inject","z":"f71e5505.8bfbf8","name":"","topic":"","payload":"0.884490302","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1460,"wires":[["8cfa28e1.2d6e88","e592ccaa.befed","93b42cdf.d04b3"]]},{"id":"82e9371c.e17a08","type":"inject","z":"f71e5505.8bfbf8","name":"","topic":"","payload":"0.722404901","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1500,"wires":[["8cfa28e1.2d6e88","e592ccaa.befed","93b42cdf.d04b3"]]},{"id":"30bf94e0.d792bc","type":"inject","z":"f71e5505.8bfbf8","name":"","topic":"","payload":"0.917280197","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1540,"wires":[["8cfa28e1.2d6e88","e592ccaa.befed","93b42cdf.d04b3"]]},{"id":"b36d2602.c44c88","type":"inject","z":"f71e5505.8bfbf8","name":"","topic":"","payload":"0.880320681","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1620,"wires":[["8cfa28e1.2d6e88","e592ccaa.befed","93b42cdf.d04b3"]]},{"id":"7127abe6.7989d4","type":"inject","z":"f71e5505.8bfbf8","name":"","topic":"","payload":"0.825058562","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1580,"wires":[["8cfa28e1.2d6e88","e592ccaa.befed","93b42cdf.d04b3"]]},{"id":"caabea11.f761a8","type":"inject","z":"f71e5505.8bfbf8","name":"","topic":"","payload":"0.796308845","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1660,"wires":[["8cfa28e1.2d6e88","e592ccaa.befed","93b42cdf.d04b3"]]},{"id":"5ba5006b.3bc27","type":"inject","z":"f71e5505.8bfbf8","name":"","topic":"","payload":"0.79255487","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1700,"wires":[["8cfa28e1.2d6e88","e592ccaa.befed","93b42cdf.d04b3"]]},{"id":"2ef04fce.f3cb2","type":"inject","z":"f71e5505.8bfbf8","name":"","topic":"","payload":"0.76197476","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":1740,"wires":[["8cfa28e1.2d6e88","e592ccaa.befed","93b42cdf.d04b3"]]},{"id":"c9803255.0832d","type":"change","z":"f71e5505.8bfbf8","name":"hpf","rules":[{"t":"set","p":"topic","pt":"msg","to":"hpf","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":1640,"wires":[["df715d88.163c4"]]},{"id":"cef6c815.723e18","type":"change","z":"f71e5505.8bfbf8","name":"lpf","rules":[{"t":"set","p":"topic","pt":"msg","to":"lpf","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":1600,"wires":[["df715d88.163c4"]]},{"id":"b3061169.2ecb3","type":"change","z":"f71e5505.8bfbf8","name":"mean","rules":[{"t":"set","p":"topic","pt":"msg","to":"mean","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":1560,"wires":[["df715d88.163c4"]]}]

Any idea how to extend this flow make it work for this sequence, and even bigger ones?
all sequences are evenly spaced and varies from 0.01 to 0.99.

Thanks, highly appreciated

Hi,

instead of may Inject nodes you could try one with an JSON formated array. either with single values (same result as when you click on each inject node in your flow) or an array of objects where you can use timestamp / value pairs. Then you split to feed split the array into a sequence of messages.

Perhaps this could help you:

[{"id":"234870ae.be8f1","type":"inject","z":"339ad8dc.ba3688","name":"values","topic":"","payload":"[0.755154261,0.912094449,0.884490302,0.722404901,0.917280197,0.825058562,0.880320681,0.796308845,0.79255487,0.76197476]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":186,"y":544,"wires":[["e47a9588.3df638"]]},{"id":"afba5a54.2e3438","type":"debug","z":"339ad8dc.ba3688","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":521,"y":544,"wires":[]},{"id":"e47a9588.3df638","type":"split","z":"339ad8dc.ba3688","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":348,"y":544,"wires":[["afba5a54.2e3438"]]},{"id":"5b516680.de7398","type":"inject","z":"339ad8dc.ba3688","name":"values","topic":"","payload":"[{\"time\":\"9:49\",\"value\":0.755154261},{\"time\":\"9:50\",\"value\":0.912094449},{\"time\":\"9:51\",\"value\":0.884490302},{\"time\":\"9:52\",\"value\":0.722404901},{\"time\":\"9:53\",\"value\":0.917280197},{\"time\":\"9:54\",\"value\":0.825058562},{\"time\":\"9:55\",\"value\":0.880320681},{\"time\":\"9:56\",\"value\":0.796308845},{\"time\":\"9:57\",\"value\":0.79255487},{\"time\":\"9:58\",\"value\":0.76197476}]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":186,"y":646,"wires":[["5bcdcbf1.ac4ed4"]]},{"id":"f818f2b9.059b2","type":"debug","z":"339ad8dc.ba3688","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":521,"y":646,"wires":[]},{"id":"5bcdcbf1.ac4ed4","type":"split","z":"339ad8dc.ba3688","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":348,"y":646,"wires":[["f818f2b9.059b2"]]},{"id":"423ed781.76ed48","type":"inject","z":"339ad8dc.ba3688","name":"values","topic":"","payload":"[{\"9:49\":0.755154261},{\"9:50\":0.912094449},{\"9:51\":0.884490302},{\"9:52\":0.722404901},{\"9:53\":0.917280197},{\"9:54\":0.825058562},{\"9:55\":0.880320681},{\"9:56\":0.796308845},{\"9:57\":0.79255487},{\"9:58\":0.76197476}]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":186,"y":595,"wires":[["d0ddd84f.bc23c8"]]},{"id":"b525f4bd.38f8f8","type":"debug","z":"339ad8dc.ba3688","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":521,"y":595,"wires":[]},{"id":"d0ddd84f.bc23c8","type":"split","z":"339ad8dc.ba3688","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":348,"y":595,"wires":[["b525f4bd.38f8f8"]]}]

Or using the csv in node ...

Thanks @Christian-Me, indeed it simplify things. The new flow:

[{"id":"45217fc3.dac7d","type":"debug","z":"44a70066.170c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":650,"y":380,"wires":[]},{"id":"bb19fae3.0f2858","type":"change","z":"44a70066.170c","name":"mean","rules":[{"t":"set","p":"topic","pt":"msg","to":"mean","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":380,"wires":[["45217fc3.dac7d"]]},{"id":"1fb723f8.6f2cac","type":"smooth","z":"44a70066.170c","name":"Mean","property":"payload","action":"mean","count":"10","round":"","mult":"single","reduce":true,"x":390,"y":380,"wires":[["bb19fae3.0f2858"]]},{"id":"3776469.15bc2ba","type":"split","z":"44a70066.170c","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":270,"y":380,"wires":[["1fb723f8.6f2cac"]]},{"id":"b2b4d521.783a68","type":"inject","z":"44a70066.170c","name":"values","topic":"","payload":"[0.755154261,0.912094449,0.884490302,0.722404901,0.917280197,0.825058562,0.880320681,0.796308845,0.79255487,0.76197476]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":380,"wires":[["3776469.15bc2ba"]]}]

However, the issue here is the predicted result. I get now this reult:

0.8247641827999999

by applying only the "mean function" after evenly time-spaced 10 messages within the smooth node. This result should be smoothed to get the expected value of:

0.786928627

i.e. we still have a potential of 4.587% error.
I used only the Low-Pass-Filter with α=20 and got now only 0.61% error at the last value.
The question remains, is Low-Pass-Filter is the right way to "smooth" and predict the next value in a sequence?

Thanks

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.