Skip to content

Commit b69fc89

Browse files
committed
Added mean algorithms :)
1 parent 2010473 commit b69fc89

2 files changed

Lines changed: 151 additions & 0 deletions

File tree

Average/Lua/Yonaba/average.lua

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
-- Various average (means) algorithms implementation
2+
-- See: http://en.wikipedia.org/wiki/Average
3+
4+
-- Returns the sum of a sequence of values
5+
local function sum(x)
6+
local s = 0
7+
for _, v in ipairs(x) do s = s + v end
8+
return s
9+
end
10+
11+
-- Calculates the arithmetic mean of a set of values
12+
-- x : an array of values
13+
-- returns : the arithmetic mean
14+
local function arithmetic_mean(x)
15+
return (sum(x) / #x)
16+
end
17+
18+
-- Calculates the geometric mean of a set of values
19+
-- x : an array of values
20+
-- returns : the geometric mean
21+
local function geometric_mean(x)
22+
local prod = 1
23+
for _, v in ipairs(x) do prod = prod * v end
24+
return (prod ^ (1 / #x))
25+
end
26+
27+
-- Calculates the harmonic mean of a set of values
28+
-- x : an array of values
29+
-- returns : the harmonic mean
30+
local function harmonic_mean(x)
31+
local s = 0
32+
for _, v in ipairs(x) do s = s + (1 / v) end
33+
return (#x / s)
34+
end
35+
36+
-- Calculates the quadratic mean of a set of values
37+
-- x : an array of values
38+
-- returns : the quadratic mean
39+
local function quadratic_mean(x)
40+
local ssquares = 0
41+
for _, v in ipairs(x) do ssquares = ssquares + (v * v) end
42+
return math.sqrt((1 / #x) * ssquares)
43+
end
44+
45+
-- Calculates the generalized mean (to a specified power p) of a set of values
46+
-- x : an array of values
47+
-- p : a power
48+
-- returns : the generalized mean
49+
local function generalized_mean(x, p)
50+
local sump = 0
51+
for _, v in ipairs(x) do sump = sump + (v ^ p) end
52+
return ((1 / #x) * sump) ^ (1 / p)
53+
end
54+
55+
-- Calculates the weighted mean of a set of values
56+
-- x : an array of values
57+
-- w : an array of weights for each value in x
58+
-- returns : the weighted mean
59+
local function weighted_mean(x, w)
60+
local sump = 0
61+
for i, v in ipairs (x) do sump = sump + (v * w[i]) end
62+
return sump / sum(w)
63+
end
64+
65+
-- Calculates the midrange mean of a set of values
66+
-- x : an array of values
67+
-- returns : the midrange mean
68+
local function midrange_mean(x)
69+
local sump = 0
70+
return 0.5 * (math.min(unpack(x)) + math.max(unpack(x)))
71+
end
72+
73+
-- Calculates the energetic mean of a set of values
74+
-- x : an array of values
75+
-- returns : the energetic mean
76+
local function energetic_mean(x)
77+
local s = 0
78+
for _,v in ipairs(x) do s = s + (10 ^ (v / 10)) end
79+
return 10 * math.log10((1 / #x) * s)
80+
end
81+
82+
return {
83+
arithmetic = arithmetic_mean,
84+
geometric = geometric_mean,
85+
harmonic = harmonic_mean,
86+
quadratic = quadratic_mean,
87+
generalized = generalized_mean,
88+
weighted = weighted_mean,
89+
midrange = midrange_mean,
90+
energetic = energetic_mean,
91+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
-- Tests for average.lua
2+
local mean = require 'average'
3+
4+
local total, pass = 0, 0
5+
6+
local function dec(str, len)
7+
return #str < len
8+
and str .. (('.'):rep(len-#str))
9+
or str:sub(1,len)
10+
end
11+
12+
local function run(message, f)
13+
total = total + 1
14+
local ok, err = pcall(f)
15+
if ok then pass = pass + 1 end
16+
local status = ok and 'PASSED' or 'FAILED'
17+
print(('%02d. %68s: %s'):format(total, dec(message,68), status))
18+
end
19+
20+
local function fuzzyEqual(a, b, eps) return math.abs(a - b) < eps end
21+
local x = {1, 2, 3, 4, 5}
22+
23+
run('Arithmetic mean', function()
24+
assert(mean.arithmetic(x) == 3)
25+
end)
26+
27+
run('Geometric mean', function()
28+
assert(fuzzyEqual(mean.geometric(x), 2.60517108,1e-8))
29+
end)
30+
31+
run('Harmonic mean', function()
32+
assert(fuzzyEqual(mean.harmonic(x), 2.18978102,1e-8))
33+
end)
34+
35+
run('Quadratic mean', function()
36+
assert(fuzzyEqual(mean.quadratic(x), 3.31662479,1e-8))
37+
end)
38+
39+
run('Generalized mean', function()
40+
assert(fuzzyEqual(mean.generalized(x,1), mean.arithmetic(x),1e-8))
41+
assert(fuzzyEqual(mean.generalized(x,2), mean.quadratic(x),1e-8))
42+
assert(fuzzyEqual(mean.generalized(x,-1), mean.harmonic(x),1e-8))
43+
end)
44+
45+
run('Weighted mean', function()
46+
local w = { 0.1, 0.2, 0.2, 0.3, 0.2}
47+
assert(mean.weighted(x, w) == 3.3)
48+
end)
49+
50+
run('Midrange mean', function()
51+
assert(mean.midrange(x) == 3)
52+
end)
53+
54+
run('Energetic mean', function()
55+
assert(fuzzyEqual(mean.energetic(x), 3.22766781,1e-8))
56+
end)
57+
58+
print(('-'):rep(80))
59+
print(('Total : %02d: Pass: %02d - Failed : %02d - Success: %.2f %%')
60+
:format(total, pass, total-pass, (pass*100/total)))

0 commit comments

Comments
 (0)