2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,18 +1,23 @@
|
|||
Computing the [[wp:Moving_average#Simple_moving_average|simple moving average]] of a series of numbers.
|
||||
|
||||
The task is to:
|
||||
:''Create a [[wp:Stateful|stateful]] function/class/instance that takes a period and returns a routine that takes a number as argument and returns a simple moving average of its arguments so far.''
|
||||
{{task heading}}
|
||||
|
||||
'''Description'''<br>
|
||||
A simple moving average is a method for computing an average of a stream of numbers by only averaging the last P numbers from the stream, where P is known as the period.
|
||||
It can be implemented by calling an initialing routine with P as its argument, I(P), which should then return a routine that when called with individual, successive members of a stream of numbers, computes the mean of (up to), the last P of them, lets call this SMA().
|
||||
Create a [[wp:Stateful|stateful]] function/class/instance that takes a period and returns a routine that takes a number as argument and returns a simple moving average of its arguments so far.
|
||||
|
||||
The word stateful in the task description refers to the need for SMA() to remember certain information between calls to it:
|
||||
* The period, P
|
||||
* An ordered container of at least the last P numbers from each of its individual calls.
|
||||
Stateful also means that successive calls to I(), the initializer, should return separate routines that do ''not'' share saved state so they could be used on two independent streams of data.
|
||||
{{task heading|Description}}
|
||||
|
||||
Pseudocode for an implementation of SMA is:
|
||||
A simple moving average is a method for computing an average of a stream of numbers by only averaging the last P numbers from the stream, where P is known as the period.
|
||||
|
||||
It can be implemented by calling an initialing routine with P as its argument, I(P), which should then return a routine that when called with individual, successive members of a stream of numbers, computes the mean of (up to), the last P of them, lets call this SMA().
|
||||
|
||||
The word ''stateful'' in the task description refers to the need for SMA() to remember certain information between calls to it:
|
||||
* The period, P
|
||||
* An ordered container of at least the last P numbers from each of its individual calls.
|
||||
|
||||
<br>
|
||||
''Stateful'' also means that successive calls to I(), the initializer, should return separate routines that do ''not'' share saved state so they could be used on two independent streams of data.
|
||||
|
||||
Pseudo-code for an implementation of SMA is:
|
||||
<pre>
|
||||
function SMA(number: N):
|
||||
stateful integer: P
|
||||
|
|
@ -30,5 +35,8 @@ function SMA(number: N):
|
|||
return average
|
||||
</pre>
|
||||
|
||||
{{task heading|See also}}
|
||||
|
||||
See also: [[Standard Deviation]]
|
||||
{{Related tasks/Statistical measures}}
|
||||
|
||||
<hr>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
$ cat simple-moving-avg.exs
|
||||
#!/usr/bin/env elixir
|
||||
|
||||
defmodule Math do
|
||||
def average([]), do: nil
|
||||
def average(enum) do
|
||||
Enum.sum(enum) / length(enum)
|
||||
end
|
||||
end
|
||||
|
||||
defmodule SMA do
|
||||
|
||||
def sma(l, p \\ 10) do
|
||||
IO.puts("\nSimple moving average(period=#{p}):")
|
||||
Enum.chunk(l, p, 1)
|
||||
|> Enum.map(&(%{"input": &1, "avg": Float.round(Math.average(&1), 3)}))
|
||||
end
|
||||
|
||||
defmacro gen_func(p) do
|
||||
quote do
|
||||
fn l -> SMA.sma(l, unquote(p)) end
|
||||
end
|
||||
end
|
||||
|
||||
def read_numeric_input do
|
||||
IO.stream(:stdio, :line)
|
||||
|> Enum.map(&(String.split(&1, ~r{\s+})))
|
||||
|> List.flatten()
|
||||
|> Enum.reject(&(is_nil(&1) || String.length(&1) == 0))
|
||||
|> Enum.map(&(Integer.parse(&1) |> elem(0)))
|
||||
end
|
||||
|
||||
def run do
|
||||
sma_func_10 = gen_func(10)
|
||||
sma_func_15 = gen_func(15)
|
||||
numbers = read_numeric_input
|
||||
sma_func_10.(numbers) |> IO.inspect
|
||||
sma_func_15.(numbers) |> IO.inspect
|
||||
end
|
||||
end
|
||||
|
||||
SMA.run
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
elixir ./simple-moving-avg.exs <<EOF
|
||||
1 2 3 4 5 6 7 8 9 8 7 6 5 4 3 2 1
|
||||
2 4 6 8 10 12 14 12 10 8 6 4 2
|
||||
EOF
|
||||
|
|
@ -1,26 +1,25 @@
|
|||
{-# LANGUAGE BangPatterns #-}
|
||||
|
||||
import Control.Monad
|
||||
import Data.List
|
||||
import Data.IORef
|
||||
|
||||
data Pair a b = Pair !a !b
|
||||
|
||||
mean :: Fractional a => [a] -> a
|
||||
mean xs = sum xs / (genericLength xs)
|
||||
mean = divl . foldl' (\(Pair s l) x -> Pair (s+x) (l+1)) (Pair 0.0 0)
|
||||
where divl (_,0) = 0.0
|
||||
divl (s,l) = s / fromIntegral l
|
||||
|
||||
series = [1,2,3,4,5,5,4,3,2,1]
|
||||
|
||||
simple_moving_averager period = do
|
||||
numsRef <- newIORef []
|
||||
return (\x -> do
|
||||
nums <- readIORef numsRef
|
||||
let xs = take period (x:nums)
|
||||
writeIORef numsRef xs
|
||||
return $ mean xs
|
||||
)
|
||||
mkSMA :: Int -> IO (Double -> IO Double)
|
||||
mkSMA period = avgr <$> newIORef []
|
||||
where avgr nsref x = readIORef nsref >>= (\ns ->
|
||||
let xs = take period (x:ns)
|
||||
in writeIORef nsref xs $> mean xs)
|
||||
|
||||
main = do
|
||||
sma3 <- simple_moving_averager 3
|
||||
sma5 <- simple_moving_averager 5
|
||||
forM_ series (\n -> do
|
||||
mm3 <- sma3 n
|
||||
mm5 <- sma5 n
|
||||
putStrLn $ "Next number = " ++ (show n) ++ ", SMA_3 = " ++ (show mm3) ++ ", SMA_5 = " ++ (show mm5)
|
||||
)
|
||||
main = mkSMA 3 >>= (\sma3 -> mkSMA 5 >>= (\sma5 ->
|
||||
mapM_ (str <$> pure n <*> sma3 <*> sma5) series))
|
||||
where str n mm3 mm5 =
|
||||
concat ["Next number = ",show n,", SMA_3 = ",show mm3,", SMA_5 = ",show mm5]
|
||||
|
|
|
|||
|
|
@ -23,6 +23,4 @@ demostrateSMA :: State SMAState [Float]
|
|||
demostrateSMA = mapM computeSMA [1, 2, 3, 4, 5, 5, 4, 3, 2, 1]
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn $ (show result)
|
||||
where
|
||||
(result, _) = runState demostrateSMA []
|
||||
main = print $ evalState demostrateSMA []
|
||||
|
|
|
|||
|
|
@ -1,10 +1,19 @@
|
|||
// single-sided
|
||||
Array.prototype.simpleSMA=function(N) {
|
||||
return this.map(function(x,i,v) {
|
||||
if(i<N-1) return NaN;
|
||||
return v.filter(function(x2,i2) { return i2<=i && i2>i-N; }).reduce(function(a,b){ return a+b; })/N;
|
||||
}); };
|
||||
return this.map(
|
||||
function(el,index, _arr) {
|
||||
return _arr.filter(
|
||||
function(x2,i2) {
|
||||
return i2 <= index && i2 > index - N;
|
||||
})
|
||||
.reduce(
|
||||
function(current, last, index, arr){
|
||||
return (current + last);
|
||||
})/index || 1;
|
||||
});
|
||||
};
|
||||
|
||||
g=[1,2,3,4,5,8,5,4];
|
||||
console.log(g.simpleSMA(3))
|
||||
console.log(g.simpleSMA(5))
|
||||
g=[0,1,2,3,4,5,6,7,8,9,10];
|
||||
console.log(g.simpleSMA(3));
|
||||
console.log(g.simpleSMA(5));
|
||||
console.log(g.simpleSMA(g.length));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
v:v,|v:1+!5
|
||||
v
|
||||
1 2 3 4 5 5 4 3 2 1
|
||||
|
||||
avg:{(+/x)%#x}
|
||||
sma:{avg'x@(,\!y),(1+!y)+\:!y}
|
||||
|
||||
sma[v;5]
|
||||
1 1.5 2 2.5 3 3.8 4.2 4.2 3.8 3
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
sma:{n::x#_n; {n::1_ n,x; {avg x@&~_n~'x} n}}
|
||||
|
||||
sma[5]' v
|
||||
1 1.5 2 2.5 3 3.8 4.2 4.2 3.8 3
|
||||
|
|
@ -1,10 +1,19 @@
|
|||
do
|
||||
local t = {}
|
||||
function f(a, b, ...) if b then return f(a+b, ...) else return a end end
|
||||
function average(n)
|
||||
if #t == 10 then table.remove(t, 1) end
|
||||
t[#t + 1] = n
|
||||
return f(unpack(t)) / #t
|
||||
end
|
||||
function sma(period)
|
||||
local t = {}
|
||||
function sum(a, ...)
|
||||
if a then return a+sum(...) else return 0 end
|
||||
end
|
||||
function average(n)
|
||||
if #t == period then table.remove(t, 1) end
|
||||
t[#t + 1] = n
|
||||
return sum(unpack(t)) / #t
|
||||
end
|
||||
return average
|
||||
end
|
||||
for v=1,30 do print(average(v)) end
|
||||
|
||||
sma5 = sma(5)
|
||||
sma10 = sma(10)
|
||||
print("SMA 5")
|
||||
for v=1,15 do print(sma5(v)) end
|
||||
print("\nSMA 10")
|
||||
for v=1,15 do print(sma10(v)) end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
sub sma-generator (Int $P where * > 0) {
|
||||
sub ($x) {
|
||||
state @a = 0 xx $P;
|
||||
@a.push($x).shift;
|
||||
@a.sum / $P;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
my &sma = sma-generator 3;
|
||||
|
||||
for 1, 2, 3, 2, 7 {
|
||||
printf "append $_ --> sma = %.2f (with period 3)\n", sma $_;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
sub sma(Int \P where * > 0) returns Sub {
|
||||
sub ($x) {
|
||||
state @a = 0 xx P;
|
||||
@a.push($x).shift;
|
||||
P R/ [+] @a;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +1,19 @@
|
|||
/*REXX program illustrates simple moving average using a constructed list. */
|
||||
parse arg p q n . /*get optional arguments from the C.L. */
|
||||
if p=='' then p=3 /*the 1st period (the default is: 3).*/
|
||||
if q=='' then q=5 /* " 2nd " " " " 5).*/
|
||||
if n=='' then n=10 /*the number of items in the list. */
|
||||
@.=0 /*define array with initial zero values*/
|
||||
/* [↓] build 1st half of list*/
|
||||
do j=1 for n%2; @.j=j; end /* ··· increasing values.*/
|
||||
/* [↓] build 2nd half of list*/
|
||||
do k=n%2 to 1 by -1; @.j=k; j=j+1; end /* ··· decreasing values.*/
|
||||
/*REXX program illustrates and displays a simple moving average using a constructed list*/
|
||||
parse arg p q n . /*obtain optional arguments from the CL*/
|
||||
if p=='' | p=="," then p= 3 /*Not specified? Then use the default.*/
|
||||
if q=='' | q=="," then q= 5 /* " " " " " " */
|
||||
if n=='' | n=="," then n=10 /* " " " " " " */
|
||||
@.=0 /*default value, only needed for odd N.*/
|
||||
do j=1 for n%2; @.j=j; end /*build 1st half of list, increasing #s*/
|
||||
do k=n%2 by -1 to 1; @.j=k; j=j+1; end /* " 2nd " " " decreasing " */
|
||||
|
||||
say ' ' " SMA with " ' SMA with '
|
||||
say ' number ' " period" p' ' ' period' q
|
||||
say ' ──────── ' "──────────" '──────────'
|
||||
say ' ' " SMA with " ' SMA with '
|
||||
say ' number ' " period" p' ' ' period' q
|
||||
say ' ──────── ' "──────────" '──────────'
|
||||
|
||||
/* [↓] perform a simple moving average*/
|
||||
do m=1 for n
|
||||
say center(@.m, 10) left(sma(p,m), 11) left(sma(q,m), 11)
|
||||
end /*m*/ /* [↑] show a simple moving average.*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
sma: procedure expose @.; parse arg p,j; s=0; i=0
|
||||
do k=max(1,j-p+1) to j+p for p while k<=j; i=i+1
|
||||
s=s+@.k
|
||||
end /*k*/
|
||||
return s/i
|
||||
do m=1 for n; say center(@.m, 10) left(SMA(p, m), 11) left(SMA(q, m), 11); end
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
SMA: procedure expose @.; parse arg p,j; i=0 ; $=0
|
||||
do k=max(1, j-p+1) to j+p for p while k<=j; i=i+1; $=$+@.k; end
|
||||
return $/i
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
struct SimpleMovingAverage {
|
||||
period: usize,
|
||||
numbers: Vec<usize>
|
||||
}
|
||||
|
||||
impl SimpleMovingAverage {
|
||||
fn new(p: usize) -> SimpleMovingAverage {
|
||||
SimpleMovingAverage {
|
||||
period: p,
|
||||
numbers: Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn add_number(&mut self, number: usize) -> f64 {
|
||||
self.numbers.push(number);
|
||||
|
||||
if self.numbers.len() > self.period {
|
||||
self.numbers.remove(0);
|
||||
}
|
||||
|
||||
if self.numbers.is_empty() {
|
||||
return 0f64;
|
||||
}else {
|
||||
let sum = self.numbers.iter().fold(0, |acc, x| acc+x);
|
||||
return sum as f64 / self.numbers.len() as f64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
for period in [3, 5].iter() {
|
||||
println!("Moving average with period {}", period);
|
||||
|
||||
let mut sma = SimpleMovingAverage::new(*period);
|
||||
for i in [1, 2, 3, 4, 5, 5, 4, 3, 2, 1].iter() {
|
||||
println!("Number: {} | Average: {}", i, sma.add_number(*i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
struct SimpleMovingAverage {
|
||||
period: usize,
|
||||
numbers: VecDeque<usize>
|
||||
}
|
||||
|
||||
impl SimpleMovingAverage {
|
||||
fn new(p: usize) -> SimpleMovingAverage {
|
||||
SimpleMovingAverage {
|
||||
period: p,
|
||||
numbers: VecDeque::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn add_number(&mut self, number: usize) -> f64 {
|
||||
self.numbers.push_back(number);
|
||||
|
||||
if self.numbers.len() > self.period {
|
||||
self.numbers.pop_front();
|
||||
}
|
||||
|
||||
if self.numbers.is_empty() {
|
||||
return 0f64;
|
||||
}else {
|
||||
let sum = self.numbers.iter().fold(0, |acc, x| acc+x);
|
||||
return sum as f64 / self.numbers.len() as f64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
for period in [3, 5].iter() {
|
||||
println!("Moving average with period {}", period);
|
||||
|
||||
let mut sma = SimpleMovingAverage::new(*period);
|
||||
for i in [1, 2, 3, 4, 5, 5, 4, 3, 2, 1].iter() {
|
||||
println!("Number: {} | Average: {}", i, sma.add_number(*i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
data = "1,2,3,4,5,5,4,3,2,1"
|
||||
token = Split(data,",")
|
||||
stream = ""
|
||||
WScript.StdOut.WriteLine "Number" & vbTab & "SMA3" & vbTab & "SMA5"
|
||||
For j = LBound(token) To UBound(token)
|
||||
If Len(stream) = 0 Then
|
||||
stream = token(j)
|
||||
Else
|
||||
stream = stream & "," & token(j)
|
||||
End If
|
||||
WScript.StdOut.WriteLine token(j) & vbTab & Round(SMA(stream,3),2) & vbTab & Round(SMA(stream,5),2)
|
||||
Next
|
||||
|
||||
Function SMA(s,p)
|
||||
If Len(s) = 0 Then
|
||||
SMA = 0
|
||||
Exit Function
|
||||
End If
|
||||
d = Split(s,",")
|
||||
sum = 0
|
||||
If UBound(d) + 1 >= p Then
|
||||
c = 0
|
||||
For i = UBound(d) To LBound(d) Step -1
|
||||
sum = sum + Int(d(i))
|
||||
c = c + 1
|
||||
If c = p Then
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
SMA = sum / p
|
||||
Else
|
||||
For i = UBound(d) To LBound(d) Step -1
|
||||
sum = sum + Int(d(i))
|
||||
Next
|
||||
SMA = sum / (UBound(d) + 1)
|
||||
End If
|
||||
End Function
|
||||
Loading…
Add table
Add a link
Reference in a new issue