-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstable-computation.py
More file actions
85 lines (68 loc) · 2.26 KB
/
Copy pathstable-computation.py
File metadata and controls
85 lines (68 loc) · 2.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import numpy as np
__doc__ = "different methods to avoid catastrophic cancellation in computing variance and covariance"
def mean_deviation(array):
return np.subtract(array, np.mean(array))
def naive_variance(series, sample=False):
assert np.ndim(series) == 1
n = np.shape(series)[0]
s = np.sum(series)
ss = np.square(series).sum()
var = ss/n - (s/n)**2
if sample:
var *= n / (n-1)
return var
def shifted_variance(series, sample=False):
'''
According to Var(X-k)=Var(X) for any constant k we can avoid cancellation
by any k in the range of X; the closer k to mean, the better.
'''
assert np.ndim(series) == 1
n = np.shape(series)[0]
if n < 2:
return 0.0
k = series[0]
s = np.subtract(series, k).sum()
ss = np.square(np.subtract(series, k)).sum()
var = (ss - s**2/n) / (n-1 if sample else n)
return var
def two_pass_variance(series, sample=False):
'''most stable method for variance computation'''
assert np.ndim(series) == 1
df = np.shape(series)[0]
if sample:
df -= 1
return np.square(mean_deviation(series)).sum() / df
def naive_covariance(A, B, sample=False):
assert np.ndim(A) == np.ndim(B) == 1
n, m = np.shape(A)[0], np.shape(B)[0]
assert n == m, n>0
s1 = np.sum(A)
s2 = np.sum(B)
s12 = np.multiply(A, B).sum()
return (s12 - s1*s2/n) / (n-1 if sample else n)
def shifted_covariance(A, B, sample=False):
assert np.ndim(A) == np.ndim(B) == 1
n, m = np.shape(A)[0], np.shape(B)[0]
assert n == m, n>0
k1 = A[0]
k2 = B[0]
d1 = np.subtract(A, k1)
d2 = np.subtract(B, k2)
d12 = d1 * d2
s1 = d1.sum()
s2 = d2.sum()
s12 = d12.sum()
return (s12 - s1*s2/n) / (n-1 if sample else n)
def two_pass_covariance(A, B, sample=False):
assert np.ndim(A) == np.ndim(B) == 1
n, m = np.shape(A)[0], np.shape(B)[0]
assert n == m, n>0
df = n-1 if sample else n
return np.sum(mean_deviation(A) * mean_deviation(B)) / df
if __name__ == '__main__':
array = np.random.random(size=1000)
print(np.var(array, ddof=1))
print(naive_variance(array, True))
print(shifted_variance(array, True))
print(two_pass_variance(array, True))
print(two_pass_covariance(array, array, True))