機(jī)器學(xué)習(xí)之分類回歸樹(python實(shí)現(xiàn)CART)

之前有文章介紹過決策樹(ID3)彼哼。簡單回顧一下:ID3每次選取最佳特征來分割數(shù)據(jù)摩瞎,這個(gè)最佳特征的判斷原則是通過信息增益來實(shí)現(xiàn)的。按照某種特征切分?jǐn)?shù)據(jù)后稠氮,該特征在以后切分?jǐn)?shù)據(jù)集時(shí)就不再使用,因此存在切分過于迅速的問題。ID3算法還不能處理連續(xù)性特征。
下面簡單介紹一下其他算法:


屏幕快照 2018-03-03 14.05.44.png

CART 分類回歸樹

CART是Classification And Regerssion Trees的縮寫,既能處理分類任務(wù)也能做回歸任務(wù)易遣。


image.png

CART樹的典型代表時(shí)二叉樹炮温,根據(jù)不同的條件將分類担巩。


image.png

CART樹構(gòu)建算法
與ID3決策樹的構(gòu)建方法類似先匪,直接給出CART樹的構(gòu)建過程。首先與ID3類似采用字典樹的數(shù)據(jù)結(jié)構(gòu)拟糕,包含以下4中元素:

  • 待切分的特征
  • 待切分的特征值
  • 右子樹。當(dāng)不再需要切分的時(shí)候宠蚂,也可以是單個(gè)值
  • 左子樹,類似右子樹忘嫉。

過程如下:

  1. 尋找最合適的分割特征
  2. 如果不能分割數(shù)據(jù)集,該數(shù)據(jù)集作為一個(gè)葉子節(jié)點(diǎn)描滔。
  3. 對數(shù)據(jù)集進(jìn)行二分割
  4. 對分割的數(shù)據(jù)集1重復(fù)1陪腌, 2卵洗,3 步,創(chuàng)建右子樹亏狰。
  5. 對分割的數(shù)據(jù)集2重復(fù)1, 2丁逝,3 步琢感,創(chuàng)建左子樹其垄。

明顯的遞歸算法。

通過數(shù)據(jù)過濾的方式分割數(shù)據(jù)集克懊,返回兩個(gè)子集柜与。

def splitDatas(rows, value, column):
    # 根據(jù)條件分離數(shù)據(jù)集(splitDatas by value, column)
    # return 2 part(list1, list2)

    list1 = []
    list2 = []

    if isinstance(value, int) or isinstance(value, float):
        for row in rows:
            if row[column] >= value:
                list1.append(row)
            else:
                list2.append(row)
    else:
        for row in rows:
            if row[column] == value:
                list1.append(row)
            else:
                list2.append(row)
    return list1, list2

劃分?jǐn)?shù)據(jù)點(diǎn)

創(chuàng)建二進(jìn)制決策樹本質(zhì)上就是遞歸劃分輸入空間的過程。


image.png

代碼如下:

# gini()
def gini(rows):
    # 計(jì)算gini的值(Calculate GINI)

    length = len(rows)
    results = calculateDiffCount(rows)
    imp = 0.0
    for i in results:
        imp += results[i] / length * results[i] / length
    return 1 - imp

構(gòu)建樹

def buildDecisionTree(rows, evaluationFunction=gini):
    # 遞歸建立決策樹, 當(dāng)gain=0拐辽,時(shí)停止回歸
    # build decision tree bu recursive function
    # stop recursive function when gain = 0
    # return tree
    currentGain = evaluationFunction(rows)
    column_lenght = len(rows[0])
    rows_length = len(rows)

    best_gain = 0.0
    best_value = None
    best_set = None

    # choose the best gain
    for col in range(column_lenght - 1):
        col_value_set = set([x[col] for x in rows])
        for value in col_value_set:
            list1, list2 = splitDatas(rows, value, col)
            p = len(list1) / rows_length
            gain = currentGain - p * evaluationFunction(list1) - (1 - p) * evaluationFunction(list2)
            if gain > best_gain:
                best_gain = gain
                best_value = (col, value)
                best_set = (list1, list2)
    dcY = {'impurity': '%.3f' % currentGain, 'sample': '%d' % rows_length}
    #
    # stop or not stop

    if best_gain > 0:
        trueBranch = buildDecisionTree(best_set[0], evaluationFunction)
        falseBranch = buildDecisionTree(best_set[1], evaluationFunction)
        return Tree(col=best_value[0], value = best_value[1], trueBranch = trueBranch, falseBranch=falseBranch, summary=dcY)
    else:
        return Tree(results=calculateDiffCount(rows), summary=dcY, data=rows)

上面代碼的功能是先找到數(shù)據(jù)集切分的最佳位置和分割數(shù)據(jù)集。之后通過遞歸構(gòu)建出上面圖片的整棵樹舔痪。

剪枝

在決策樹的學(xué)習(xí)中痛悯,有時(shí)會造成決策樹分支過多,這是就需要去掉一些分支筒扒,降低過度擬合怯邪。通過決策樹的復(fù)雜度來避免過度擬合的過程稱為剪枝。
后剪枝需要從訓(xùn)練集生成一棵完整的決策樹花墩,然后自底向上對非葉子節(jié)點(diǎn)進(jìn)行考察悬秉。利用測試集判斷是否將該節(jié)點(diǎn)對應(yīng)的子樹替換成葉節(jié)點(diǎn)。
代碼如下:

def prune(tree, miniGain, evaluationFunction=gini):
    # 剪枝 when gain < mini Gain, 合并(merge the trueBranch and falseBranch)
    if tree.trueBranch.results == None:
        prune(tree.trueBranch, miniGain, evaluationFunction)
    if tree.falseBranch.results == None:
        prune(tree.falseBranch, miniGain, evaluationFunction)

    if tree.trueBranch.results != None and tree.falseBranch.results != None:
        len1 = len(tree.trueBranch.data)
        len2 = len(tree.falseBranch.data)
        len3 = len(tree.trueBranch.data + tree.falseBranch.data)

        p = float(len1) / (len1 + len2)

        gain = evaluationFunction(tree.trueBranch.data + tree.falseBranch.data) - p * evaluationFunction(tree.trueBranch.data) - (1 - p) * evaluationFunction(tree.falseBranch.data)

        if gain < miniGain:
            tree.data = tree.trueBranch.data + tree.falseBranch.data
            tree.results = calculateDiffCount(tree.data)
            tree.trueBranch = None
            tree.falseBranch = None

當(dāng)節(jié)點(diǎn)的gain小于給定的 mini Gain時(shí)則合并這兩個(gè)節(jié)點(diǎn).冰蘑。

最后是構(gòu)建樹的代碼:

if __name__ == '__main__':
    dataSet = loadCSV()
    decisionTree = buildDecisionTree(dataSet, evaluationFunction=gini)
    prune(decisionTree, 0.4)
    test_data = [5.9,3,4.2,1.5]
    r = classify(test_data, decisionTree)
    print(r)

可以打印decisionTree可以構(gòu)建出如如上的圖片中的決策樹和泌。
后面找一組數(shù)據(jù)測試看能否得到正確的分類。

完整代碼和數(shù)據(jù)集請查看:
github:CART

總結(jié):

  • CART決策樹
  • 分割數(shù)據(jù)集
  • 遞歸創(chuàng)建樹

參考文章:
CART分類回歸樹分析與python實(shí)現(xiàn)
CART決策樹(Decision Tree)的Python源碼實(shí)現(xiàn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末祠肥,一起剝皮案震驚了整個(gè)濱河市武氓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仇箱,老刑警劉巖县恕,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異剂桥,居然都是意外死亡忠烛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門权逗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來况木,“玉大人垒拢,你說我怎么就攤上這事』鹁” “怎么了求类?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長屹耐。 經(jīng)常有香客問我尸疆,道長,這世上最難降的妖魔是什么惶岭? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任寿弱,我火速辦了婚禮,結(jié)果婚禮上按灶,老公的妹妹穿的比我還像新娘症革。我一直安慰自己,他們只是感情好鸯旁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布噪矛。 她就那樣靜靜地躺著,像睡著了一般铺罢。 火紅的嫁衣襯著肌膚如雪艇挨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天韭赘,我揣著相機(jī)與錄音缩滨,去河邊找鬼。 笑死泉瞻,一個(gè)胖子當(dāng)著我的面吹牛脉漏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播袖牙,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼侧巨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贼陶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤巧娱,失蹤者是張志新(化名)和其女友劉穎碉怔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體禁添,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡撮胧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了老翘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芹啥。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锻离,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出墓怀,到底是詐尸還是另有隱情汽纠,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布傀履,位于F島的核電站虱朵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏钓账。R本人自食惡果不足惜碴犬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望梆暮。 院中可真熱鬧服协,春花似錦、人聲如沸啦粹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卖陵。三九已至遭顶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泪蔫,已是汗流浹背棒旗。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撩荣,地道東北人铣揉。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像餐曹,于是被迫代替她去往敵國和親逛拱。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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