Reputation: 25008
I'm trying to build F#
equivalent code for the Python
code appearing here, I've the below code:
let tripleExponentialSmoothing series slen alpha beta gamma nPreds =
let result : float list = []
let mutable smooth = 0.
let mutable trend = 0.
let seasonals = initialSeasonalComponents series 12
for i in 0..(series.Length+nPreds-1) do
match i with
| 0 -> // initial values
smooth <- series |> Array.head |> float
trend <- initialTrend series slen
result |> List.append [series |> Array.head |> float] |> ignore
| i when i >= series.Length -> // we are forecasting
let m = i - series.Length + 1
result |> List.append [(smooth + float m * trend) + seasonals.Item(i%slen)] |> ignore
| _ ->
let v = series |> Array.head |> float
let lastSmooth = smooth
smooth <- alpha*(v-seasonals.Item(i%slen)) + (1.-alpha)*(smooth+trend)
trend <- beta * (smooth-lastSmooth) + (1.-beta)*trend
seasonals.Item(i%slen) <- gamma*(v-smooth) + (1.-gamma)*seasonals.Item(i%slen)
result |> List.append [smooth + trend + seasonals.Item(i%slen)] |> ignore
result
For which I got the below error:
warning FS0020: The result of this expression is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.
I tried to write the above as conversion of the below Python
code:
def triple_exponential_smoothing(series, slen, alpha, beta, gamma, n_preds):
result = []
seasonals = initial_seasonal_components(series, slen)
for i in range(len(series)+n_preds):
if i == 0: # initial values
smooth = series[0]
trend = initial_trend(series, slen)
result.append(series[0])
continue
if i >= len(series): # we are forecasting
m = i - len(series) + 1
result.append((smooth + m*trend) + seasonals[i%slen])
else:
val = series[i]
last_smooth, smooth = smooth, alpha*(val-seasonals[i%slen]) + (1-alpha)*(smooth+trend)
trend = beta * (smooth-last_smooth) + (1-beta)*trend
seasonals[i%slen] = gamma*(val-smooth) + (1-gamma)*seasonals[i%slen]
result.append(smooth+trend+seasonals[i%slen])
return result
What the wrong things I did, and what is the correct code equivalent to the mentioned Python
's one.
Upvotes: 1
Views: 2625
Reputation: 26204
You are running the for as a side effect.
Maybe you want to a seq expression, I think in Python you have generators but here in F# remember that everything is an expression.
let tripleExponentialSmoothing series slen alpha beta gamma nPreds =
let mutable smooth = 0.
let mutable trend = 0.
let seasonals = initialSeasonalComponents series 12 |> Dictionary
seq {
for i in 0..(series.Length+nPreds-1) do
match i with
| 0 -> // initial values
smooth <- series |> Array.head |> float
trend <- initialTrend series slen
yield series |> Array.head |> float
| i when i >= series.Length -> // we are forecasting
let m = i - series.Length + 1
yield (smooth + float m * trend) + seasonals.[i%slen]
| _ ->
let v = series |> Array.head |> float
let lastSmooth = smooth
smooth <- alpha*(v-seasonals.[i%slen]) + (1.-alpha)*(smooth+trend)
trend <- beta * (smooth-lastSmooth) + (1.-beta)*trend
seasonals.[i%slen] <- gamma*(v-smooth) + (1.-gamma)*seasonals.[i%slen]
yield smooth + trend + seasonals.[i%slen] }
So, a sequence expressions is of the form seq { expr }
and inside the expression you use yield
to yield results.
Upvotes: 4
Reputation: 243126
As mentioned in the other answer, you are trying to mutate the list of results in the for
loop, but this is not possible, because F# lists are immutable by default.
If you want to directly follow the style of the Python code, you can use mutable ResizeArray
:
let tripleExponentialSmoothing series slen alpha beta gamma nPreds =
let result = ResizeArray<_>()
let mutable smooth = 0.
let mutable trend = 0.
let seasonals = initialSeasonalComponents series 12
for i in 0..(series.Length+nPreds-1) do
match i with
| 0 -> // initial values
smooth <- series |> Array.head |> float
trend <- initialTrend series slen
result.Add(series |> Array.head |> float)
| i when i >= series.Length -> // we are forecasting
let m = i - series.Length + 1
result.Add((smooth + float m * trend) + seasonals.Item(i%slen))
| _ ->
let v = series |> Array.head |> float
let lastSmooth = smooth
smooth <- alpha*(v-seasonals.Item(i%slen)) + (1.-alpha)*(smooth+trend)
trend <- beta * (smooth-lastSmooth) + (1.-beta)*trend
seasonals.Item(i%slen) <- gamma*(v-smooth) + (1.-gamma)*seasonals.Item(i%slen)
result.Add(smooth + trend + seasonals.Item(i%slen))
This is not very idiomatic F# code, but it solves your immediate problem. For a more functional solution, you can go with sequence expressions as mentioned by Gustavo and yield results one by one, but you still keep smooth
and trend
as mutable variables, so there probably is even nicer way of doing this - but that's hard to guess without knowing more about your algorithm.
Upvotes: 2