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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
| import numpy as np class SVM: def __init__(self, max_iter=100, kernel='linear'): ''' input:max_iter(int):最大训练轮数 kernel(str):核函数,等于'linear'表示线性,等于'poly'表示多项式 ''' self.max_iter = max_iter self._kernel = kernel def init_args(self, features, labels): self.m, self.n = features.shape self.X = features self.Y = labels self.b = 0.0 self.alpha = np.ones(self.m) self.E = [self._E(i) for i in range(self.m)] self.C = 1.0 def _KKT(self, i): y_g = self._g(i)*self.Y[i] if self.alpha[i] == 0: return y_g >= 1 elif 0 < self.alpha[i] < self.C: return y_g == 1 else: return y_g <= 1
def _g(self, i): r = self.b for j in range(self.m): r += self.alpha[j]*self.Y[j]*self.kernel(self.X[i], self.X[j]) return r
def kernel(self, x1, x2): if self._kernel == 'linear': return sum([x1[k]*x2[k] for k in range(self.n)]) elif self._kernel == 'poly': return (sum([x1[k]*x2[k] for k in range(self.n)]) + 1)**2 return 0
def _E(self, i): return self._g(i) - self.Y[i]
def _init_alpha(self): index_list = [i for i in range(self.m) if 0 < self.alpha[i] < self.C] non_satisfy_list = [i for i in range(self.m) if i not in index_list] index_list.extend(non_satisfy_list)
for i in index_list: if self._KKT(i): continue
E1 = self.E[i] if E1 >= 0: j = min(range(self.m), key=lambda x: self.E[x]) else: j = max(range(self.m), key=lambda x: self.E[x]) return i, j
def _compare(self, _alpha, L, H): if _alpha > H: return H elif _alpha < L: return L else: return _alpha
def fit(self, features, labels): ''' input:features(ndarray):特征 label(ndarray):标签 ''' self.init_args(features, labels)
for t in range(self.max_iter): i1, i2 = self._init_alpha()
if self.Y[i1] == self.Y[i2]: L = max(0, self.alpha[i1]+self.alpha[i2]-self.C) H = min(self.C, self.alpha[i1]+self.alpha[i2]) else: L = max(0, self.alpha[i2]-self.alpha[i1]) H = min(self.C, self.C+self.alpha[i2]-self.alpha[i1])
E1 = self.E[i1] E2 = self.E[i2] eta = self.kernel(self.X[i1], self.X[i1]) + self.kernel(self.X[i2], self.X[i2]) - 2*self.kernel(self.X[i1], self.X[i2]) if eta <= 0: continue
alpha2_new_unc = self.alpha[i2] + self.Y[i2] * (E2 - E1) / eta alpha2_new = self._compare(alpha2_new_unc, L, H)
alpha1_new = self.alpha[i1] + self.Y[i1] * self.Y[i2] * (self.alpha[i2] - alpha2_new)
b1_new = -E1 - self.Y[i1] * self.kernel(self.X[i1], self.X[i1]) * (alpha1_new-self.alpha[i1]) - self.Y[i2] * self.kernel(self.X[i2], self.X[i1]) * (alpha2_new-self.alpha[i2])+ self.b b2_new = -E2 - self.Y[i1] * self.kernel(self.X[i1], self.X[i2]) * (alpha1_new-self.alpha[i1]) - self.Y[i2] * self.kernel(self.X[i2], self.X[i2]) * (alpha2_new-self.alpha[i2])+ self.b
if 0 < alpha1_new < self.C: b_new = b1_new elif 0 < alpha2_new < self.C: b_new = b2_new else: b_new = (b1_new + b2_new) / 2
self.alpha[i1] = alpha1_new self.alpha[i2] = alpha2_new self.b = b_new
self.E[i1] = self._E(i1) self.E[i2] = self._E(i2) return 'train done!' def predict(self, data): r = self.b for i in range(self.m): r += self.alpha[i] * self.Y[i] * self.kernel(data, self.X[i]) return 1 if r > 0 else -1 def score(self, X_test, y_test): right_count = 0 for i in range(len(X_test)): result = self.predict(X_test[i]) if result == y_test[i]: right_count += 1 return right_count / len(X_test) def _weight(self): yx = self.Y.reshape(-1, 1)*self.X self.w = np.dot(yx.T, self.alpha) return self.w
|