1 /** 2 * A Library for AROW Linear Classification 3 * 4 * Authors: Kazuya Gokita 5 */ 6 7 module arow; 8 9 import std.math; 10 import std.random; 11 12 /*** 13 * Adaptive Regularization of Weight Vectors 14 * 15 * See_Also: 16 * K. Crammer, A. Kulesza, and M. Dredze. "Adaptive regularization of weight vectors" NIPS 2009 17 */ 18 class Arow { 19 private: 20 size_t dimension; // Size of feature vector 21 double[] mean; // Average vector 22 double[] cov; // Variance matrix (diagonal) 23 24 double r; // Hyper parameter ( r > 0 ) 25 26 invariant() { 27 assert(mean != null); 28 assert(cov != null); 29 assert(mean.length == dimension); 30 assert(cov.length == dimension); 31 assert(r > 0); 32 } 33 34 35 /** 36 * Calculate confidence 37 * Params: 38 * f = feature 39 * 40 * Returns: confidence 41 */ 42 double getConfidence(in double[int] f) @trusted 43 in { 44 assert(f != null); 45 } 46 out(confidence) { 47 assert(confidence != double.nan); 48 assert(confidence != double.nan && confidence != -double.infinity); 49 } 50 body { 51 double confidence = 0.0; 52 foreach(index; f.keys) { 53 confidence += cov[index] * f[index] * f[index]; 54 } 55 56 return confidence; 57 } 58 59 60 public: 61 this(size_t num_features, double param = 0.1) { 62 dimension = num_features; 63 mean = new double[dimension]; 64 cov = new double[dimension]; 65 66 mean[] = 0.0; 67 cov[] = 1.0; 68 r = param; 69 } 70 71 72 @property { 73 auto dim() { return dimension; } 74 } 75 76 77 @property { 78 auto param() { return r; } 79 auto param(double val) { return r = val; } 80 } 81 82 83 /** 84 * Update weight vector 85 * Params: 86 * fv = feature 87 * label = class label (+1 / -1) 88 * 89 * Returns: loss (0 / 1) 90 */ 91 int update(in double[int] f, int label) @trusted 92 in { 93 assert(label == -1 || label == 1); 94 assert(f != null); 95 } 96 out(loss) { 97 assert(loss == 0 || loss == 1); 98 } 99 body { 100 immutable margin = getMargin(f); 101 if (margin * label >= 1) return 0; 102 103 immutable confidence = getConfidence(f); 104 immutable beta = 1.0 / (confidence + r); 105 immutable alpha = (1.0 - label * margin) * beta; 106 107 // Update mean 108 foreach(index; f.keys) { 109 mean[index] += alpha * cov[index] * label * f[index]; 110 } 111 112 // Update covariance 113 foreach(index; f.keys) { 114 cov[index] = 1.0 / ((1.0 / cov[index]) + f[index] * f[index] / r); 115 } 116 117 return margin * label < 0 ? 1 : 0; 118 } 119 120 121 /** 122 * Calculate the distance between a vector and the hyperplane 123 * Params: 124 * f = feature 125 * 126 * Returns: Margin(Euclidean distance) 127 */ 128 double getMargin(in double[int] f) @trusted 129 in { 130 assert(f != null); 131 } 132 out(margin) { 133 assert(margin != double.nan); 134 assert(margin != double.nan && margin != -double.infinity); 135 } 136 body { 137 double margin = 0.0; 138 foreach(index; f.keys) { 139 margin += mean[index] * f[index]; 140 } 141 142 return margin; 143 } 144 145 146 /** 147 * Predict 148 * Params: 149 * f = feature vector 150 * Returns: class label (-1, 1) 151 */ 152 int predict(in double[int] f) @trusted 153 in { 154 assert(f != null); 155 } 156 out(label) { 157 assert(label == -1 || label == 1); 158 } 159 body { 160 double m = getMargin(f); 161 return m > 0 ? 1 : -1; 162 } 163 164 } 165