2 people like it.
Like the snippet!
AdaBoost in F#
I have provided a class that implements adaptive boosting (AdaBoost) which is a very elegant technique to create a strong classifier from a set of weak classifiers.
The strong classifier is the sign of the weighted average of the best N weak classifiers where N is a user specified parameter.
The training process consists of N selection rounds. During each round, the training samples are given a weight distribution. The classifier selected is the one that has the least error which is equal to the weighted average of incorrectly classified samples. Training samples that have been incorrectly classified are given a larger weight for the next round. This increases the likelihood of drafting a weak classifier that can help with as yet misclassified samples.
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:
|
namespace AdaBooster
type LabelType =
| NEG = -1
| POS = 1
type AdaBooster(trainingSamples : (obj * LabelType) [], weakClassifiers : (obj -> LabelType) [], weakClassifierMaxCount : int) =
let trainingSamplesCount = trainingSamples.Length
let weakClassifierCount = weakClassifiers.Length
let weightMatrix = Array2D.create trainingSamplesCount weakClassifierMaxCount 1.0
let scoutingMatrix = Array2D.create trainingSamplesCount weakClassifierCount 0
let mutable strongClassifier: (int * float) list = []
let initializeScoutingMatrix =
for j in 0 .. weakClassifiers.Length - 1 do
for i in 0 .. trainingSamplesCount - 1 do
let (sample, label) = trainingSamples.[i]
scoutingMatrix.[i, j] <-
if ( weakClassifiers.[j] sample ) <> label then 1 else 0
let calculateError weakClassifierIndex weights =
weights
|> List.mapi (fun i wt -> float scoutingMatrix.[i, weakClassifierIndex] * wt)
|> List.sum
let selectBestWeakClassifier weights weakClassifierIndices =
weakClassifierIndices
|> List.map (fun weakClassifierIndex -> (weakClassifierIndex, calculateError weakClassifierIndex weights))
|> List.minBy (fun (x, y) -> y)
let rec train m weights weakClassifierIndices =
if m >= weakClassifierMaxCount then []
else
let nextM = m + 1
let (bestWeakClassifierIndex, classifierWeight) = selectBestWeakClassifier weights weakClassifierIndices
let error = classifierWeight / List.sum weights
let weakClassifierCoefficient = 0.5 * log ((1.0 - error) / error)
let wm1 = sqrt(( 1.0 - error) / error)
let newWeights =
weights
|> List.mapi ( fun i wm -> if scoutingMatrix.[ i, bestWeakClassifierIndex] = 1 then wm * wm1 else wm / wm1)
for i in 0 .. (trainingSamplesCount - 1) do
weightMatrix.[i, m] <- weights.[i]
let weakClassifiersToScanNext =
weakClassifierIndices
|> List.filter (fun index -> index <> bestWeakClassifierIndex)
(bestWeakClassifierIndex, weakClassifierCoefficient) :: train nextM newWeights weakClassifiersToScanNext
member this.Predict sample =
strongClassifier
|> List.sumBy (fun (weakClassifierIndex, weakClassifierCoefficient) -> weakClassifierCoefficient * float ( weakClassifiers.[weakClassifierIndex] sample) )
|> (fun x -> if x > 0.0 then (x, LabelType.POS) else (x,LabelType.NEG))
member this.Train =
let initialWeights = List.init trainingSamplesCount (fun x -> 1.0)
strongClassifier <- train 0 initialWeights [0 .. (weakClassifierCount - 1)]
strongClassifier
member this.ScoutingMatrix =
scoutingMatrix
member this.WeightMatrix =
weightMatrix
|
Multiple items
type AdaBooster =
new : trainingSamples:(obj * LabelType) [] * weakClassifiers:(obj -> LabelType) [] * weakClassifierMaxCount:int -> AdaBooster
member Predict : sample:obj -> float * LabelType
member ScoutingMatrix : int [,]
member Train : (int * float) list
member WeightMatrix : float [,]
Full name: AdaBooster.AdaBooster
--------------------
new : trainingSamples:(obj * LabelType) [] * weakClassifiers:(obj -> LabelType) [] * weakClassifierMaxCount:int -> AdaBooster
LabelType.NEG: LabelType = -1
LabelType.POS: LabelType = 1
val trainingSamples : (obj * LabelType) []
type obj = System.Object
Full name: Microsoft.FSharp.Core.obj
type LabelType =
| NEG = -1
| POS = 1
Full name: AdaBooster.LabelType
val weakClassifiers : (obj -> LabelType) []
val weakClassifierMaxCount : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
val trainingSamplesCount : int
property System.Array.Length: int
val weakClassifierCount : int
val weightMatrix : float [,]
module Array2D
from Microsoft.FSharp.Collections
val create : length1:int -> length2:int -> value:'T -> 'T [,]
Full name: Microsoft.FSharp.Collections.Array2D.create
val scoutingMatrix : int [,]
val mutable strongClassifier : (int * float) list
Multiple items
val float : value:'T -> float (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.float
--------------------
type float = System.Double
Full name: Microsoft.FSharp.Core.float
--------------------
type float<'Measure> = float
Full name: Microsoft.FSharp.Core.float<_>
type 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>
val initializeScoutingMatrix : unit
val j : int32
val i : int32
val sample : obj
val label : LabelType
val calculateError : (int -> float list -> float)
val weakClassifierIndex : int
val weights : float list
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val mapi : mapping:(int -> 'T -> 'U) -> list:'T list -> 'U list
Full name: Microsoft.FSharp.Collections.List.mapi
val i : int
val wt : float
val sum : list:'T list -> 'T (requires member ( + ) and member get_Zero)
Full name: Microsoft.FSharp.Collections.List.sum
val selectBestWeakClassifier : (float list -> int list -> int * float)
val weakClassifierIndices : int list
val map : mapping:('T -> 'U) -> list:'T list -> 'U list
Full name: Microsoft.FSharp.Collections.List.map
val minBy : projection:('T -> 'U) -> list:'T list -> 'T (requires comparison)
Full name: Microsoft.FSharp.Collections.List.minBy
val x : int
val y : float
val train : (int -> float list -> int list -> (int * float) list)
val m : int
val nextM : int
val bestWeakClassifierIndex : int
val classifierWeight : float
val error : float
val weakClassifierCoefficient : float
val log : value:'T -> 'T (requires member Log)
Full name: Microsoft.FSharp.Core.Operators.log
val wm1 : float
val sqrt : value:'T -> 'U (requires member Sqrt)
Full name: Microsoft.FSharp.Core.Operators.sqrt
val newWeights : float list
val wm : float
val weakClassifiersToScanNext : int list
val filter : predicate:('T -> bool) -> list:'T list -> 'T list
Full name: Microsoft.FSharp.Collections.List.filter
val index : int
val this : AdaBooster
member AdaBooster.Predict : sample:obj -> float * LabelType
Full name: AdaBooster.AdaBooster.Predict
val sumBy : projection:('T -> 'U) -> list:'T list -> 'U (requires member ( + ) and member get_Zero)
Full name: Microsoft.FSharp.Collections.List.sumBy
val x : float
member AdaBooster.Train : (int * float) list
Full name: AdaBooster.AdaBooster.Train
val initialWeights : float list
val init : length:int -> initializer:(int -> 'T) -> 'T list
Full name: Microsoft.FSharp.Collections.List.init
member AdaBooster.ScoutingMatrix : int [,]
Full name: AdaBooster.AdaBooster.ScoutingMatrix
member AdaBooster.WeightMatrix : float [,]
Full name: AdaBooster.AdaBooster.WeightMatrix
More information