SMO中选择第二个变量 :param E1: 第一个变量的E1 :param i: 第一个变量α的下标 :return: E2,α2的下标
(self, E1, i)
| 186 | return gxi - self.trainLabelMat[i] |
| 187 | |
| 188 | def getAlphaJ(self, E1, i): |
| 189 | ''' |
| 190 | SMO中选择第二个变量 |
| 191 | :param E1: 第一个变量的E1 |
| 192 | :param i: 第一个变量α的下标 |
| 193 | :return: E2,α2的下标 |
| 194 | ''' |
| 195 | #初始化E2 |
| 196 | E2 = 0 |
| 197 | #初始化|E1-E2|为-1 |
| 198 | maxE1_E2 = -1 |
| 199 | #初始化第二个变量的下标 |
| 200 | maxIndex = -1 |
| 201 | |
| 202 | #这一步是一个优化性的算法 |
| 203 | #实际上书上算法中初始时每一个Ei应当都为-yi(因为g(xi)由于初始α为0,必然为0) |
| 204 | #然后每次按照书中第二步去计算不同的E2来使得|E1-E2|最大,但是时间耗费太长了 |
| 205 | #作者最初是全部按照书中缩写,但是本函数在需要3秒左右,所以进行了一些优化措施 |
| 206 | #-------------------------------------------------- |
| 207 | #在Ei的初始化中,由于所有α为0,所以一开始是设置Ei初始值为-yi。这里修改为与α |
| 208 | #一致,初始状态所有Ei为0,在运行过程中再逐步更新 |
| 209 | #因此在挑选第二个变量时,只考虑更新过Ei的变量,但是存在问题 |
| 210 | #1.当程序刚开始运行时,所有Ei都是0,那挑谁呢? |
| 211 | # 当程序检测到并没有Ei为非0时,将会使用随机函数随机挑选一个 |
| 212 | #2.怎么保证能和书中的方法保持一样的有效性呢? |
| 213 | # 在挑选第一个变量时是有一个大循环的,它能保证遍历到每一个xi,并更新xi的值, |
| 214 | #在程序运行后期后其实绝大部分Ei都已经更新完毕了。下方优化算法只不过是在程序运行 |
| 215 | #的前半程进行了时间的加速,在程序后期其实与未优化的情况无异 |
| 216 | #------------------------------------------------------ |
| 217 | |
| 218 | #获得Ei非0的对应索引组成的列表,列表内容为非0Ei的下标i |
| 219 | nozeroE = [i for i, Ei in enumerate(self.E) if Ei != 0] |
| 220 | #对每个非零Ei的下标i进行遍历 |
| 221 | for j in nozeroE: |
| 222 | #计算E2 |
| 223 | E2_tmp = self.calcEi(j) |
| 224 | #如果|E1-E2|大于目前最大值 |
| 225 | if math.fabs(E1 - E2_tmp) > maxE1_E2: |
| 226 | #更新最大值 |
| 227 | maxE1_E2 = math.fabs(E1 - E2_tmp) |
| 228 | #更新最大值E2 |
| 229 | E2 = E2_tmp |
| 230 | #更新最大值E2的索引j |
| 231 | maxIndex = j |
| 232 | #如果列表中没有非0元素了(对应程序最开始运行时的情况) |
| 233 | if maxIndex == -1: |
| 234 | maxIndex = i |
| 235 | while maxIndex == i: |
| 236 | #获得随机数,如果随机数与第一个变量的下标i一致则重新随机 |
| 237 | maxIndex = int(random.uniform(0, self.m)) |
| 238 | #获得E2 |
| 239 | E2 = self.calcEi(maxIndex) |
| 240 | |
| 241 | #返回第二个变量的E2值以及其索引 |
| 242 | return E2, maxIndex |
| 243 | |
| 244 | def train(self, iter = 100): |
| 245 | #iterStep:迭代次数,超过设置次数还未收敛则强制停止 |