1 """Generic linear best fits."""
2
3 import types
4 from gmisclib import Num
5
6
7 -def fit(idata, fitting_fcns, ff_info=None, wt=None):
8 """Fits data to a linear combination of fitting_fcns.
9 @rtype: tuple
10 @return: The returned value is a tuple of:
11 the coefficients of the optimal solution (as an array),
12 the residual (a single float number),
13 the rank of the fit (int),
14 an array of the singular values,
15 and the best fit to the data.
16 The returned value follows Num.LA.linear_least_squares(),
17 except that residual is always calculated and is a scalar.
18 @type idata: an array of (vector, info).
19 @type fitting_fcns: an array of functions.
20 @param fitting_fcns: the basis functions for the linear regression.
21 The fitting functions return vectors (which must match the data).
22 Fitting functions are called as f(info, ff_info, len(vector)).
23 Vectors may have different lengths, as long as the
24 corresponding data and fit vectors agree.
25 """
26
27 nd = len(idata)
28 assert wt is None or len(wt) == nd
29 w = [None] * nd
30
31
32
33 d_idx = Num.zeros((nd+1,), Num.Int)
34 nd_total = 0
35 for i in range(nd):
36 assert len(idata[i]) == 2
37 assert type(idata[i]) == types.TupleType
38 d_idx[i] = nd_total
39 nd_total = nd_total + len(idata[i][0])
40 d_idx[nd] = nd_total
41
42
43 data = Num.zeros((nd_total,), Num.Float)
44 for i in range(nd):
45 if wt is None:
46 w[i] = Num.ones((len(idata[i][0]),), Num.Float)
47 else:
48 assert len(wt[i]) == len(idata[i][0])
49 w[i] = Num.asarray(wt[i], Num.Float)
50 assert len(idata[i][0]) == d_idx[i+1]-d_idx[i]
51 data[d_idx[i] : d_idx[i+1]] = Num.asarray(idata[i][0],
52 Num.Float) * w[i]
53
54
55 nff = len(fitting_fcns)
56 base = Num.zeros((nd_total, nff), Num.Float)
57 for i in range(nd):
58 for j in range(nff):
59 ff = fitting_fcns[j]
60 zfit = Num.asarray(ff(idata[i][1], ff_info, d_idx[i+1]-d_idx[i]),
61 Num.Float)
62 assert len(zfit.shape)==1
63 assert zfit.shape[0] == d_idx[i+1]-d_idx[i]
64 base[d_idx[i]:d_idx[i+1], j] = zfit * w[i]
65
66 rcond = 1e-5
67 x, resid, rank, s = Num.LA.linear_least_squares(base, data, rcond)
68 bfit = Num.matrixmultiply(base, x)
69 resid = Num.sum(Num.square(bfit-data).ravel())
70
71 bestfit = []
72
73 for i in range(nd):
74 bestfit.append(bfit[d_idx[i]:d_idx[i+1]]/w[i])
75
76 return x, resid, rank, s, bestfit
77
78
79
80
81
82
83
91
93 x, resid, rank, s, f = fit([([0,1,2,3,4,5], None)], [lambda di, fi, l: range(l)], None)
94 assert abs(x[0]-1)<0.0001
95 assert resid < 0.001
96 assert rank == 1
97
99 x, resid, rank, s, f = fit([([0,1,2,3], None), ([0,1,2,3,4], None)], [lambda di, fi, l: range(l)], None)
100 assert abs(x[0]-1)<0.0001
101 assert resid < 0.001
102 assert rank == 1
103
105 x, resid, rank, s, f = fit([([0,1,2,3], None), ([0,2,4,6], None)], [lambda di, fi, l: range(l)])
106 assert abs(x[0]-1.5)<0.0001
107 assert rank == 1
108 x, resid, rank, s, f = fit([([0,1,2,3], None), ([0,2,4,6], None)], [lambda di, fi, l: range(l)], wt=[[1,1,1,1],[1e-10,1e-10,1e-10,1e-10]])
109 assert abs(x[0]-1)<0.0001
110 assert rank == 1
111
113 x, resid, rank, s, f = fit([([0,1,2,3], None), ([1,2,3,4], None)], [lambda di, fi, l: range(l), lambda di, fi, l: [1]*l], None)
114 assert abs(x[0]-1)<0.0001
115 assert abs(x[1]-0.5)<0.0001
116 assert rank == 2
117
119 x, resid, rank, s, f = fit([([1,2,3,4], None)], [lambda di, fi, l: range(l), lambda di, fi, l: [1]*l])
120 assert abs(x[0]-1)<0.0001
121 assert abs(x[1]-1)<0.0001
122 assert resid < 0.001
123 assert rank == 2
124 assert abs(f[0][0]-1)<0.001
125 assert abs(f[0][1]-2)<0.001
126
128 x, resid, rank, s, f = fit(
129 [([1,2,3,4], None)],
130 [lambda di, fi, l: range(l), lambda di, fi, l: [1]*l],
131 wt=[[5,2,3,1e-10]]
132 )
133 assert abs(x[0]-1)<0.0001
134 assert abs(x[1]-1)<0.0001
135 assert resid < 0.001
136 assert rank == 2
137
138
139
140
141
142 if __name__ == '__main__' :
143 test()
144 print "OK: passed tests"
145