《Machine Learning in Action》—— 剖析支持向量機(jī)这橙,優(yōu)化SMO

《Machine Learning in Action》—— 剖析支持向量機(jī),優(yōu)化SMO

薄霧濃云愁永晝导披,瑞腦銷金獸屈扎。

愁的很,上次不是更新了一篇關(guān)于支持向量機(jī)的文章嘛撩匕,《Machine Learning in Action》—— 剖析支持向量機(jī)鹰晨,單手狂撕線性SVM。雖然效果還算不錯止毕,數(shù)據(jù)集基本都能夠分類正確模蜡,模型訓(xùn)練效率的話也還說的過去,但這是基于我們訓(xùn)練樣本數(shù)據(jù)集比較少扁凛、迭代次數(shù)比較少的前提下忍疾。

假如說我們數(shù)據(jù)集比較大,而且還需要迭代不少次數(shù)的話谨朝,上一篇文章中使用到的SMO算法的效率可就不敢恭維了卤妒,訓(xùn)練的速度可堪比龜龜。月黑風(fēng)高夜字币,殺人放火天则披。不對不對,月黑風(fēng)高夜洗出,瘋狂肝文時士复。既然一般的SMO算法的效率低下,那怎么說也得進(jìn)一步優(yōu)化才行吶翩活。

就在前幾天還聽見收音機(jī)上說阱洪,國內(nèi)外有許多如雷貫耳的大佬都在不斷研究新算法來進(jìn)一步提高SMO算法的訓(xùn)練效率便贵。聞此一言,Taoye心中大喜:"如果我能蹦跶出一個新的優(yōu)化算法冗荸,哥哥我聲名遠(yuǎn)揚(yáng)的大好機(jī)會就來了啊承璃,雄霸天下的抱負(fù)就指日可待了啊俏竞!哈哈哈哈3袼丁!魂毁!"想法雖好玻佩,可是該怎么優(yōu)化呢?在這薄霧濃云席楚、月黑風(fēng)高之夜咬崔,Taoye的思緒漫天飛,愁的很烦秩。

<img>

有心栽花花不開垮斯,無心插柳柳成蔭。

明明已經(jīng)知道SMO算法待優(yōu)化的地方太多了只祠,可是就是不知如何下手兜蠕,想了老半天,腦闊疼的厲害抛寝。此刻實驗室空無一人熊杨,Taoye轉(zhuǎn)著座椅,雙目望向窗外盗舰,皎潔的月光總是給人無限遐想晶府。

罷了罷了,與其木訥在這有心栽花花不開钻趋,倒不如出去轉(zhuǎn)悠轉(zhuǎn)悠川陆,說不定能捕獲個意想不到的收獲,給我來了無心插柳柳成蔭呢蛮位?說走咱就走哇(調(diào)調(diào)有點(diǎn)不對勁~~)较沪,關(guān)上空調(diào),披件外套土至,鎖上室門购对,雙手插袋朝外走去。

或許是空調(diào)吹太久了陶因,亦或?qū)嶒炇掖籼昧耍鰜淼乃查g一股神清氣爽的感覺涌上心頭垂蜗,五音不全的我此時還真想高歌一曲楷扬。頃之解幽,微涼,好在出門前披了件外套烘苹《阒辏活動活動筋骨,朝湖邊走去镣衡。走著走著霜定,不知不覺來到了步行橋,風(fēng)平浪靜的湖面廊鸥,沒有一絲波紋蕩起望浩。左轉(zhuǎn),低頭看著湖面中胡子拉碴且憔悴的自己惰说,此時我的眼角又再一次磨德。。吆视。┭┮﹏┭┮ 典挑。。抬頭看著湖邊零星幾對小情侶啦吧,或有說有笑您觉、或呢喃竊語、或打情罵俏授滓,滋滋滋琳水,有點(diǎn)兒意思,只有我只身一人還在想著如何優(yōu)化SMO算法褒墨。

等會兒炫刷。。郁妈。小情侶浑玛??噩咪?優(yōu)化SMO顾彰??胃碾?

我記得在前面那篇文章中寫到的SMO算法的核心思想里涨享,正是不斷迭代成雙成對的\alpha_i\alpha_j,只不過那個時候的這對“小情侶”是隨意配對仆百,所以導(dǎo)致的排列組合的可能性太多厕隧,從而拉低了整個模型訓(xùn)練的效率。假如說,我那個時候選取這對“小情侶”的時候并不是無意的吁讨,而是有意識髓迎、有條件的去選取,不就可以避開大量沒必要的可能性計算么建丧,這樣一來不就可以大大提高模型的訓(xùn)練效率了么排龄??翎朱?

握了一棵草橄维,乖乖,我真是個天才拴曲,這都被我想到了争舞??疗韵?心頭靈光一閃兑障,猶如饑渴春筍聽到的第一聲驚雷,屁顛屁顛的朝實驗室跑去蕉汪,而一對對小情侶異樣且詫異的眼神朝我看來流译。。者疤。

上述內(nèi)容部分虛構(gòu)福澡,僅做引出下文之用。

在這之前驹马,我們先靜下心來分析一下上篇文章中SMO的核心算法:

image

上圖是我們在講解手撕線性SVM中所寫到的linear_smo方法革砸,詳細(xì)請看:《Machine Learning in Action》—— 剖析支持向量機(jī),單手狂撕線性SVM糯累。其中Taoye圈出了三個代碼塊來給大家介紹下:

第一個代碼塊算利,我們可以發(fā)現(xiàn)代碼行為for i in range(m):,想必大家都知道這是一個循環(huán)語句泳姐,在這個方法中它具體表達(dá)的意思是根據(jù)樣本數(shù)量一次選取索引i效拭,然后通過這個索引來確定\alpha_i的選擇,所以它最終會把所有的樣本都“走一遍”胖秒。

第二個代碼塊缎患,是根據(jù)i的值重新在m中選取一個不與i相同的j,然后根據(jù)這個j來修改對應(yīng)的\alpha_j

第三個就是我們大量的矩陣阎肝、向量進(jìn)行計算的代碼塊了挤渔,我們可以發(fā)現(xiàn),無論前兩個i风题、j的選取是怎樣的判导,第三個代碼塊都會去執(zhí)行嫉父、計算,然而有些計算完全是沒必要的骡楼,這樣就大大拉跨了整個SMO算法的效率熔号,這可不是我們想要的稽鞭。

綜上鸟整,我們需要在\alpha的選取上做點(diǎn)文章,使其在一定的跳過第三個代碼塊的計算朦蕴。

  • 第一個\alpha_i的選取

在上一篇文章中篮条,我們也有提到,大多數(shù)樣本對于決策面的確定都是無用的吩抓,只有少數(shù)部分的樣本點(diǎn)才能確定具體的決策面涉茧。而\alpha與樣本之間滿足如下關(guān)系:

\left\{ \begin{array}{c} \alpha_i=0 \quad <=> \quad y_i(w^T+b)\geq1\\ \alpha_i=C \quad <=> \quad y_i(w^T+b)\leq1\\ 0\leq\alpha_i\leq C \quad <=> \quad y_i(w^T+b)=1\\ \end{array} \right.

對于第一個\alpha_i的選取,初始化的\alpha向量為0疹娶,所以第一次迭代是對所有的樣本點(diǎn)進(jìn)行伴栓。待第一次迭代完成之后,此時的\alpha向量已經(jīng)更新完成了雨饺,在之后的迭代過程中钳垮,我們就不需要對所有的樣本進(jìn)行遍歷了,而是選取在(0, C)區(qū)間的\alpha_i值即可额港,因為其他的\alpha值對于最終決策面的確定沒有什么影響饺窿。

對于第一個\alpha_i的選取,核心代碼思想如下所示移斩,也就是我們的外層循環(huán)肚医。其中data_struct是一個數(shù)據(jù)結(jié)構(gòu),其內(nèi)部保存了一些公有地的屬性向瓷,這個我們后面會講:

"""
    Author:Taoye
    微信公眾號:玩世不恭的Coder
    Explain:外層循環(huán)肠套,選取第一個合適alpha
    Parameters:
        x_data: 樣本屬性特征矩陣
        y_label: 屬性特征對應(yīng)的標(biāo)簽
        C:懲罰參數(shù)
        toler:容錯率
        max_iter:迭代次數(shù)
    Return:
        b: 決策面的參數(shù)b
        alphas:獲取決策面參數(shù)w所需要的alphas
"""
def outer_smo(self, data_struct, x_data, y_label, C, toler, max_iter):
    iter_num, ergodic_flag, alpha_optimization_num = 0, True, 0
    while (iter_num < max_iter) and ((alpha_optimization_num > 0) or (ergodic_flag)):
        alpha_optimization_num = 0
        if ergodic_flag:
            for i in range(data_struct.m):
                alpha_optimization_num += self.inner_smo(i, data_struct)
                print("遍歷所有樣本數(shù)據(jù):第%d次迭代,樣本為:%d猖任,alpha優(yōu)化的次數(shù):%d" % (iter_num, i, alpha_optimization_num))
            iter_num += 1
        else:
            no_zero_index = np.nonzero((data_struct.alphas.A > 0) * (data_struct.alphas.A < C))[0]
            for i in no_zero_index:
                alpha_optimization_num += self.inner_smo(i, data_struct)
                print("非邊界遍歷樣本數(shù)據(jù):第%d次迭代你稚,樣本為:%d,alpha優(yōu)化的次數(shù):%d" % (iter_num, i, alpha_optimization_num))
            iter_num += 1
        if ergodic_flag: ergodic_flag = False
        elif alpha_optimization_num == 0: ergodic_flag = True
        print("迭代次數(shù):%d" % iter_num)
    return data_struct.b, data_struct.alphas
  • 第二個\alpha_j的選取

對于第二個\alpha_j超升,我們不妨先分析一下前篇文章中SMO算法最終優(yōu)化之后的\alpha_2^{new}

\alpha_2^{new}=\frac{y_2(E_1-E_2)}{\eta}+\alpha_2^{old}

我們可以發(fā)現(xiàn)\alpha_2主要是靠更新迭代來進(jìn)行優(yōu)化入宦,而\alpha_2^{old}是已知的,我們沒有選擇的權(quán)利室琢,但是\frac{y_2(E_1-E_2)}{\eta}這一部分的值我們是可控的乾闰,也就是說我們要選擇合適的\alpha_j來使得后一部分的值盡可能的大,從而達(dá)到快速修改\alpha向量的目的,才能更快速的實現(xiàn)訓(xùn)練飽和。

簡單來說就是\alpha_2^{new}的變化依賴于|E_1-E_2|蹦狂,當(dāng)該絕對值越大嗅钻,\alpha_2的變化也就越大错忱。也就是說耙饰,E_1為正的時候罢洲,我們的要選擇盡可能小的E_2宾肺,E_1為負(fù)的時候硫朦,我們要選擇盡可能大的E_2贷腕。根據(jù)這個思想我們就能讓這對“小情侶”完美的配對了,美滋滋~~

對于第一個\alpha_i的選取咬展,核心代碼思想如下所示泽裳,也就是我們的內(nèi)層循環(huán)的所需要選取\alpha_j內(nèi)容:

def select_appropriate_j(self, i, data_struct, E_i):
    max_k, max_delta_E, E_j = -1, 0, 0
    data_struct.E_cache[i] = [1, E_i]
    valid_E_cache_list = np.nonzero(data_struct.E_cache[:, 0].A)[0]
    if (len(valid_E_cache_list) > 1):
        for k in valid_E_cache_list:
            if k == i: continue
            E_k = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, k)
            delta_E = abs(E_i - E_k)
            if (delta_E > max_delta_E): max_k, max_delta_E, E_j = k, delta_E, E_k
        return max_k, E_j
    else: 
        j = self.random_select_alpha_j(i, data_struct.m)
        E_j = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, j)
    return j, E_j

為了方便我們使用有關(guān)數(shù)據(jù)集和模型的一些公共資源,以及方便對它們進(jìn)行操作破婆,我們需要單獨(dú)封裝一個數(shù)據(jù)結(jié)構(gòu)(當(dāng)然了涮总,不封裝也沒什么問題),該數(shù)據(jù)結(jié)構(gòu)有關(guān)屬性解釋如下:

  1. x_data:etablish_data隨機(jī)生成數(shù)據(jù)集中的屬性矩陣
  2. y_label:etablish_data隨機(jī)生成數(shù)據(jù)集中的標(biāo)簽
  3. C:懲罰參數(shù)
  4. toler:容錯率
  5. m:數(shù)據(jù)樣本數(shù)
  6. alphas:SMO算法所需要訓(xùn)練的\alpha向量
  7. b:SMO算法所需要訓(xùn)練的b參數(shù)
  8. E_cache:用于保存誤差祷舀,第一列為有效標(biāo)志位瀑梗,第二列為樣本索引對應(yīng)的誤差E

此外,為了提高代碼的擴(kuò)展性和靈活性裳扯,還單獨(dú)抽離了一個方法update_E_k抛丽,主要用于更新data_struct對象中的E_cache屬性:

def update_E_k(self, data_struct, k):
    E_k = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, k)                                        #計算Ek
    data_struct.E_cache[k] = [1,E_k]

完整代碼:

import numpy as np
import pylab as pl
from matplotlib import pyplot as plt

class DataStruct:
    def __init__(self, x_data, y_label, C, toler):
        self.x_data = x_data
        self.y_label = y_label
        self.C = C
        self.toler = toler
        self.m = x_data.shape[0]
        self.alphas = np.mat(np.zeros((self.m, 1)))
        self.b = 0
        self.E_cache = np.mat(np.zeros((self.m, 2)))

class OptimizeLinearSVM:
    def __init__(self):
        pass

    """
        Author: Taoye
        微信公眾號: 玩世不恭的Coder
        Explain: 用于生成訓(xùn)練數(shù)據(jù)集
        Parameters:
            data_number: 樣本數(shù)據(jù)數(shù)目
        Return:
            x_data: 數(shù)據(jù)樣本的屬性矩陣
            y_label: 樣本屬性所對應(yīng)的標(biāo)簽
    """
    def etablish_data(self, data_number):
        np.random.seed(38)
        x_data = np.concatenate((np.add(np.random.randn(data_number, 2), [3, 3]),       
                                 np.subtract(np.random.randn(data_number, 2), [3, 3])),
                                 axis = 0)      # random隨機(jī)生成數(shù)據(jù),+ -3達(dá)到不同類別數(shù)據(jù)分隔的目的 
        temp_data = np.zeros([data_number])
        temp_data.fill(-1)
        y_label = np.concatenate((temp_data, np.ones([data_number])), axis = 0)
        return x_data, y_label

    """
        Author: Taoye
        微信公眾號: 玩世不恭的Coder
        Explain: 隨機(jī)選取alpha_j
        Parameters:
            alpha_i_index: 第一個alpha的索引
            alpha_number: alpha總數(shù)目
        Return:
            alpha_j_index: 第二個alpha的索引
    """
    def random_select_alpha_j(self, alpha_i_index, alpha_number):
        alpha_j_index = alpha_i_index
        while alpha_j_index == alpha_i_index:
            alpha_j_index = np.random.randint(0, alpha_number)
        return alpha_j_index

    """
        Author: Taoye
        微信公眾號: 玩世不恭的Coder
        Explain: 使得alpha_j在[L, R]區(qū)間之內(nèi)
        Parameters:
            alpha_j: 原始alpha_j
            L: 左邊界值
            R: 右邊界值
        Return:
            L,R,alpha_j: 修改之后的alpha_j
    """
    def modify_alpha(self, alpha_j, L, R):
        if alpha_j < L: return L
        if alpha_j > R: return R
        return alpha_j

    """
        Author: Taoye
        微信公眾號: 玩世不恭的Coder
        Explain: 計算誤差并返回
    """
    def calc_E(self, alphas, y_label, x_data, b, i):
        f_x_i = float(np.dot(np.multiply(alphas, y_label).T, x_data * x_data[i, :].T)) + b
        return f_x_i - float(y_label[i])

    """
        Author: Taoye
        微信公眾號: 玩世不恭的Coder
        Explain: 計算eta并返回
    """
    def calc_eta(self, x_data, i, j):
        eta = 2.0 * x_data[i, :] * x_data[j, :].T \
                - x_data[i, :] * x_data[i, :].T \
                - x_data[j, :] * x_data[j,:].T
        return eta

    """
        Author: Taoye
        微信公眾號: 玩世不恭的Coder
        Explain: 計算b1, b2并返回
    """
    def calc_b(self, b, x_data, y_label, alphas, alpha_i_old, alpha_j_old, E_i, E_j, i, j):
        b1 = b - E_i \
             - y_label[i] * (alphas[i] - alpha_i_old) * x_data[i, :] * x_data[i, :].T \
             - y_label[j] * (alphas[j] - alpha_j_old) * x_data[i, :] * x_data[j, :].T
        b2 = b - E_j \
             - y_label[i] * (alphas[i] - alpha_i_old) * x_data[i, :] * x_data[j, :].T \
             - y_label[j] * (alphas[j] - alpha_j_old) * x_data[j, :] * x_data[j, :].T
        return b1, b2

    def select_appropriate_j(self, i, data_struct, E_i):
        max_k, max_delta_E, E_j = -1, 0, 0
        data_struct.E_cache[i] = [1, E_i]
        valid_E_cache_list = np.nonzero(data_struct.E_cache[:, 0].A)[0]
        if (len(valid_E_cache_list) > 1):
            for k in valid_E_cache_list:
                if k == i: continue
                E_k = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, k)
                delta_E = abs(E_i - E_k)
                if (delta_E > max_delta_E): max_k, max_delta_E, E_j = k, delta_E, E_k
            return max_k, E_j
        else: 
            j = self.random_select_alpha_j(i, data_struct.m)
            E_j = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, j)
        return j, E_j

    def update_E_k(self, data_struct, k):
        E_k = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, k)                                        #計算Ek
        data_struct.E_cache[k] = [1,E_k]
    
    """
        Author: Taoye
        微信公眾號: 玩世不恭的Coder
        Explain: smo內(nèi)層
    """
    def inner_smo(self, i, data_strcut):
        E_i = self.calc_E(data_strcut.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, i)      # 調(diào)用calc_E方法計算樣本i的誤差
        if ((data_struct.y_label[i] * E_i < -data_struct.toler) and (data_struct.alphas[i] < data_struct.C)) or ((data_struct.y_label[i] * E_i > data_struct.toler) and (data_struct.alphas[i] > 0)):
            j, E_j = self.select_appropriate_j(i, data_strcut, E_i)              # 選取一個恰當(dāng)?shù)膉
            alpha_i_old, alpha_j_old = data_struct.alphas[i].copy(), data_struct.alphas[j].copy()
            if (data_struct.y_label[i] != data_struct.y_label[j]):               # 確保alphas在[L, R]區(qū)間內(nèi)
                L, R = max(0, data_struct.alphas[j] - data_struct.alphas[i]), min(data_struct.C, data_struct.C + data_struct.alphas[j] - data_struct.alphas[i])
            else:
                L, R = max(0, data_struct.alphas[j] + data_struct.alphas[i] - data_struct.C), min(data_struct.C, data_struct.alphas[j] + data_struct.alphas[i])
            if L == R: print("L==R"); return 0          # L==R時選取下一個樣本
            eta = self.calc_eta(data_struct.x_data, i, j)                  # 計算eta值
            if eta >= 0: print("eta>=0"); return 0
            data_struct.alphas[j] -= data_struct.y_label[j] * (E_i - E_j) / eta
            data_struct.alphas[j] = self.modify_alpha(data_struct.alphas[j], L, R)     # 修改alpha[j]
            self.update_E_k(data_strcut, j)
            if (abs(data_strcut.alphas[j] - alpha_j_old) < 0.000001): print("alpha_j修改太小了"); return 0
            data_struct.alphas[i] += data_strcut.y_label[j] * data_strcut.y_label[i] * (alpha_j_old - data_strcut.alphas[j])
            self.update_E_k(data_strcut, i)
            b1, b2= self.calc_b(data_struct.b, data_struct.x_data, data_struct.y_label, data_struct.alphas, alpha_i_old, alpha_j_old, E_i, E_j, i, j)    # 計算b值
            if (0 < data_struct.alphas[i]) and (data_struct.C > data_struct.alphas[i]): data_struct.b = b1
            elif (0 < data_struct.alphas[j]) and (data_struct.C > data_struct.alphas[j]): data_struct.b = b2
            else: data_struct.b = (b1 + b2)/2.0
            return 1
        else: return 0

    """
        Author:Taoye
        微信公眾號:玩世不恭的Coder
        Explain:外層循環(huán)嚎朽,選取第一個合適alpha
        Parameters:
            x_data: 樣本屬性特征矩陣
            y_label: 屬性特征對應(yīng)的標(biāo)簽
            C:懲罰參數(shù)
            toler:容錯率
            max_iter:迭代次數(shù)
        Return:
            b: 決策面的參數(shù)b
            alphas:獲取決策面參數(shù)w所需要的alphas
    """
    def outer_smo(self, data_struct, x_data, y_label, C, toler, max_iter):
        iter_num, ergodic_flag, alpha_optimization_num = 0, True, 0
        while (iter_num < max_iter) and ((alpha_optimization_num > 0) or (ergodic_flag)):
            alpha_optimization_num = 0
            if ergodic_flag:
                for i in range(data_struct.m):
                    alpha_optimization_num += self.inner_smo(i, data_struct)
                    print("遍歷所有樣本數(shù)據(jù):第%d次迭代铺纽,樣本為:%d,alpha優(yōu)化的次數(shù):%d" % (iter_num, i, alpha_optimization_num))
                iter_num += 1
            else:
                no_zero_index = np.nonzero((data_struct.alphas.A > 0) * (data_struct.alphas.A < C))[0]
                for i in no_zero_index:
                    alpha_optimization_num += self.inner_smo(i, data_struct)
                    print("非邊界遍歷樣本數(shù)據(jù):第%d次迭代哟忍,樣本為:%d狡门,alpha優(yōu)化的次數(shù):%d" % (iter_num, i, alpha_optimization_num))
                iter_num += 1
            if ergodic_flag: ergodic_flag = False
            elif alpha_optimization_num == 0: ergodic_flag = True
            print("迭代次數(shù):%d" % iter_num)
        return data_struct.b, data_struct.alphas

    """
        Author: Taoye
        微信公眾號: 玩世不恭的Coder
        Explain: 根據(jù)公式計算出w權(quán)值向量
        Parameters:
            x_data: 樣本屬性特征矩陣
            y_label: 屬性特征對應(yīng)的標(biāo)簽
            alphas:linear_smo方法所返回的alphas向量
        Return:
            w: 決策面的參數(shù)w
    """
    def calc_w(self, x_data, y_label, alphas):
        x_data, y_label, alphas = np.array(x_data), np.array(y_label), np.array(alphas)
        return np.dot((np.tile(y_label.reshape(1, -1).T, (1, 2)) * x_data).T, alphas).tolist()

    """
        Author: Taoye
        微信公眾號: 玩世不恭的Coder
        Explain: 繪制出分類結(jié)果
        Parameters:
            x_data: 樣本屬性特征矩陣
            y_label: 屬性特征對應(yīng)的標(biāo)簽
            w:決策面的w參數(shù)
            b:決策面的參數(shù)b
    """
    def plot_result(self, x_data, y_label, w, b):
        data_number, _ = x_data.shape; middle = int(data_number / 2)
        plt.scatter(x_data[:, 0], x_data[:, 1], c = y_label, cmap = pl.cm.Paired)
        x1, x2 = np.max(x_data), np.min(x_data)
        w1, w2 = w[0][0], w[1][0]
        y1, y2 = (-b - w1 * x1) / w2, (-b - w1 * x2) / w2
        plt.plot([float(x1), float(x2)], [float(y1), float(y2)])    # 繪制決策面
        for index, alpha in enumerate(alphas):
            if alpha > 0:
                b_temp = - w1 * x_data[index][0] - w2 * x_data[index][1]
                y1_temp, y2_temp = (-b_temp - w1 * x1) / w2, (-b_temp - w1 * x2) / w2
                plt.plot([float(x1), float(x2)], [float(y1_temp), float(y2_temp)], "k--")    # 繪制支持向量
                plt.scatter(x_data[index][0], x_data[index][1], s=150, c='none', alpha=0.7, linewidth=2, edgecolor='red')   # 圈出支持向量
        plt.show()

if __name__ == '__main__':
    optimize_linear_svm = OptimizeLinearSVM()
    x_data, y_label = optimize_linear_svm.etablish_data(50)
    data_struct = DataStruct(np.mat(x_data), np.mat(y_label).T, 0.8, 0.00001)
    b, alphas = optimize_linear_svm.outer_smo(data_struct, x_data, y_label, data_struct.C, data_struct.toler, 10)
    w = optimize_linear_svm.calc_w(x_data, y_label, alphas)
    optimize_linear_svm.plot_result(x_data, y_label, w, b)

優(yōu)化后的分類結(jié)果:

image

這期的內(nèi)容沒那么多,主要是優(yōu)化了一下上期內(nèi)容中的SMO算法锅很,從而在一定程度上提高模型的訓(xùn)練效率其馏,由于是手動實現(xiàn)該線性SVM算法,所以模型可能達(dá)不到那些框架內(nèi)置的性能爆安,有興趣的讀者可自行慢慢優(yōu)化叛复。

關(guān)于線性SVM應(yīng)該就暫時寫到這里了,后期的話應(yīng)該會更新非線性相關(guān)的內(nèi)容扔仓。

我是Taoye褐奥,愛專研,愛分享翘簇,熱衷于各種技術(shù)撬码,學(xué)習(xí)之余喜歡下象棋、聽音樂版保、聊動漫呜笑,希望借此一畝三分地記錄自己的成長過程以及生活點(diǎn)滴夫否,也希望能結(jié)實更多志同道合的圈內(nèi)朋友,更多內(nèi)容歡迎來訪微信公主號:玩世不恭的Coder

參考資料:

<font style="font-size:13px;opacity:0.7">[1] 《機(jī)器學(xué)習(xí)實戰(zhàn)》:Peter Harrington 人民郵電出版社</font>
<font style="font-size:13px;opacity:0.7">[2] 《統(tǒng)計學(xué)習(xí)方法》:李航 第二版 清華大學(xué)出版社</font>

推薦閱讀

《Machine Learning in Action》—— 剖析支持向量機(jī)叫胁,單手狂撕線性SVM
print( "Hello凰慈,NumPy!" )
干啥啥不行驼鹅,吃飯第一名
Taoye滲透到一家黑平臺總部微谓,背后的真相細(xì)思極恐
《大話數(shù)據(jù)庫》-SQL語句執(zhí)行時,底層究竟做了什么小動作谤民?
那些年堰酿,我們玩過的Git,真香
基于Ubuntu+Python+Tensorflow+Jupyter notebook搭建深度學(xué)習(xí)環(huán)境
網(wǎng)絡(luò)爬蟲之頁面花式解析
手握手帶你了解Docker容器技術(shù)
一文詳解Hexo+Github小白建站
?打開ElasticSearch张足、kibana、logstash的正確方式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坎藐,一起剝皮案震驚了整個濱河市为牍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌岩馍,老刑警劉巖碉咆,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蛀恩,居然都是意外死亡疫铜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門双谆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來壳咕,“玉大人,你說我怎么就攤上這事顽馋∥嚼澹” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵寸谜,是天一觀的道長竟稳。 經(jīng)常有香客問我,道長熊痴,這世上最難降的妖魔是什么他爸? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮果善,結(jié)果婚禮上诊笤,老公的妹妹穿的比我還像新娘。我一直安慰自己岭埠,他們只是感情好盏混,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布蔚鸥。 她就那樣靜靜地躺著,像睡著了一般许赃。 火紅的嫁衣襯著肌膚如雪止喷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天混聊,我揣著相機(jī)與錄音弹谁,去河邊找鬼。 笑死句喜,一個胖子當(dāng)著我的面吹牛预愤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咳胃,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼植康,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了展懈?” 一聲冷哼從身側(cè)響起销睁,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎存崖,沒想到半個月后冻记,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡来惧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年冗栗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片供搀。...
    茶點(diǎn)故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡隅居,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出趁曼,到底是詐尸還是另有隱情军浆,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布挡闰,位于F島的核電站乒融,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏摄悯。R本人自食惡果不足惜赞季,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奢驯。 院中可真熱鬧申钩,春花似錦、人聲如沸瘪阁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至义黎,卻和暖如春禾进,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背廉涕。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工泻云, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狐蜕。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓宠纯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親层释。 傳聞我的和親對象是個殘疾皇子婆瓜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容