Skip to content

Commit 57f8939

Browse files
authored
Add Generalised Linear Models to FSharpStats (#334)
* Implement IRLS solver for GLMs * Implement iterative reweighted least squares (IRLS) solver for generalised linear models * add qr based GLM * Add tests * Updated Gamma Distribution Variance function
1 parent c5444cc commit 57f8939

10 files changed

+2962
-4
lines changed

docs/GeneralisedLinearModels.fsx

+312
Large diffs are not rendered by default.

docs/data/cheese.csv

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"","Taste","Acetic","H2S","Lactic"
2+
"1",12.3,94,23,0.86
3+
"2",20.9,174,155,1.53
4+
"3",39,214,230,1.57
5+
"4",47.9,317,1801,1.81
6+
"5",5.6,106,45,0.99
7+
"6",25.9,298,2000,1.09
8+
"7",37.3,362,6161,1.29
9+
"8",21.9,436,2881,1.78
10+
"9",18.1,134,47,1.29
11+
"10",21,189,65,1.58
12+
"11",34.9,311,465,1.68
13+
"12",57.2,630,2719,1.9
14+
"13",0.7,88,20,1.06
15+
"14",25.9,188,140,1.3
16+
"15",54.9,469,856,1.52
17+
"16",40.9,581,14589,1.74
18+
"17",15.9,120,50,1.16
19+
"18",6.4,224,110,1.49
20+
"19",18,190,480,1.63
21+
"20",38.9,230,8639,1.99
22+
"21",14,96,141,1.15
23+
"22",15.2,200,185,1.33
24+
"23",32,234,10322,1.44
25+
"24",56.7,349,26876,2.01
26+
"25",16.8,214,39,1.31
27+
"26",11.6,421,25,1.46
28+
"27",26.5,638,1056,1.72
29+
"28",0.7,206,50,1.25
30+
"29",13.4,331,800,1.08
31+
"30",5.5,481,120,1.25

src/FSharp.Stats/Algebra/LinearAlgebra.fs

+105
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,111 @@ module LinearAlgebra =
219219
// else LinearAlgebraManaged.QR a
220220
LinearAlgebraManaged.QR a
221221

222+
/// <summary>
223+
/// Performs QR decomposition using an alternative algorithm.
224+
/// QR decomposition is a method to decompose a matrix A into two components:
225+
/// Q (an orthogonal matrix) and R (an upper triangular matrix),
226+
/// such that A = Q * R. It is commonly used in solving linear systems,
227+
/// least squares fitting, and eigenvalue problems.
228+
/// </summary>
229+
/// <returns>
230+
/// A tuple containing:
231+
/// <list type="bullet">
232+
/// <item><description>Q: The orthogonal matrix obtained from the decomposition.</description></item>
233+
/// <item><description>R: The upper triangular matrix obtained from the decomposition.</description></item>
234+
/// </list>
235+
/// </returns>
236+
let qrAlternative (A: Matrix<float>) =
237+
let m: int = A.NumRows
238+
let n: int = A.NumCols
239+
240+
let q: Matrix<float> = Matrix.zero m n
241+
let r: Matrix<float> = Matrix.zero n n
242+
let qLengths: Vector<float> = Vector.zeroCreate n
243+
244+
let getVectorLength (v: Vector<float>) = Vector.fold (fun folder i -> folder+(i*i)) 0. v
245+
246+
let setqOfA (n: int) =
247+
let aN: Vector<float> = Matrix.getCol A n
248+
let qN =
249+
if n = 0 then
250+
aN
251+
else
252+
Array.init (n) (fun i ->
253+
let denominator = qLengths[i]
254+
let forNominator: Vector<float> = Matrix.getCol q i
255+
let nominator: float = Vector.dot aN forNominator
256+
r.[i, n] <- nominator
257+
(nominator/denominator) * forNominator
258+
)
259+
|> Array.fold (fun folder e -> folder-e ) aN
260+
Matrix.setCol q n qN
261+
qN
262+
263+
for i=0 to n-1 do
264+
let qN = setqOfA i
265+
let qLength = getVectorLength qN
266+
let rValue = sqrt(qLength)
267+
r[i,i] <- rValue
268+
qLengths[i] <- qLength
269+
270+
for i=0 to n-1 do
271+
let qN: Vector<float> = Matrix.getCol q i
272+
let updateQ = (1./sqrt( qLengths[i] )) * qN
273+
Matrix.setCol q i updateQ
274+
for j=i+1 to n-1 do
275+
let denominator = r[i, i]
276+
let nominator = r[i, j]
277+
r[i, j] <- (nominator/denominator)
278+
279+
q, r
280+
281+
/// <summary>
282+
/// Solves a linear system of equations using QR decomposition.
283+
/// </summary>
284+
/// <param name="A">The coefficient matrix of the linear system.</param>
285+
/// <param name="t">The target vector of the linear system.</param>
286+
/// <returns>
287+
/// A tuple containing:
288+
/// <list type="bullet">
289+
/// <item><description>mX: The solution vector of the linear system.</description></item>
290+
/// <item><description>r: The upper triangular matrix obtained from QR decomposition.</description></item>
291+
/// </list>
292+
/// </returns>
293+
let solveLinearQR (A: Matrix<float>) (t: Vector<float>) =
294+
let m = A.NumRows
295+
let n = A.NumCols
296+
297+
System.Diagnostics.Debug.Assert(m >= n)
298+
299+
let q,r = qrAlternative A
300+
301+
let QT = q.Transpose
302+
303+
let mX = Vector.zeroCreate n
304+
305+
let c: Vector<float> = QT * t
306+
307+
let rec build_mX_inner cross_prod i j =
308+
if j=n then
309+
cross_prod
310+
else
311+
let newCrossprod = cross_prod + (r[i, j] * mX[j])
312+
build_mX_inner newCrossprod i (j+1)
313+
314+
let rec build_mX_outer i =
315+
if i<0 then
316+
()
317+
else
318+
let crossProd = build_mX_inner 0. i (i+1)
319+
mX[i] <- (c[i] - crossProd) / r[i, i]
320+
build_mX_outer (i-1)
321+
322+
build_mX_outer (n-1)
323+
324+
mX,r
325+
326+
222327
///Returns the full Singular Value Decomposition of the input MxN matrix
223328
///
224329
///A : A = U * SIGMA * V**T in the tuple (S, U, V**T),

src/FSharp.Stats/FSharp.Stats.fsproj

+7-2
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
<Compile Include="Fitting\LogisticRegression.fs" />
153153
<Compile Include="Fitting\QuantileNormalization.fs" />
154154
<Compile Include="Fitting\Spline.fs" />
155+
<Compile Include="Fitting\GeneralisedLinearModel.fs" />
155156
<!-- ML -->
156157
<Compile Include="ML\SurprisalAnalysis.fs" />
157158
<Compile Include="ML\SimilarityMetrics.fs" />
@@ -170,7 +171,8 @@
170171
<None Include="Playground.fsx" />
171172
</ItemGroup>
172173
<ItemGroup>
173-
<Content Include="../../lib/*.dll" PackagePath="netlib_LAPACK"></Content>
174+
<Content Include="../../lib/*.dll" PackagePath="netlib_LAPACK">
175+
</Content>
174176
</ItemGroup>
175177
<ItemGroup>
176178
<PackageReference Include="FSharpAux.Core" Version="2.0.0" />
@@ -182,4 +184,7 @@
182184
<ItemGroup>
183185
<None Include="../../README.md" Pack="true" PackagePath="\" />
184186
</ItemGroup>
185-
</Project>
187+
<ItemGroup>
188+
<InternalsVisibleTo Include="FSharp.Stats.Tests" />
189+
</ItemGroup>
190+
</Project>

0 commit comments

Comments
 (0)