親手實現(xiàn)決策樹(一)

決策樹的建立

1.整體思路

準備函數(shù)

  • 依據(jù)某個feature對數(shù)據(jù)進行分割為set_1, set_2 --> divide_set
  • 分別對set_1, set_2的分類結果進行統(tǒng)計 --> unique_count
  • 根據(jù)統(tǒng)計的結果計算交叉熵 --> entropy

計算思路

  • 對數(shù)據(jù)的列進行for循環(huán)精绎,選擇出gain最大的feature
  • 根據(jù)此feature進行數(shù)據(jù)集的分割承边,然后再對set_1, set_2進行遞歸
  • 直至gain為0或要進一步判斷的子數(shù)據(jù)集為空

2.python實現(xiàn)

主干代碼

def build_tree(rows, scoref=entropy):
    # 基準情況
    if len(rows) == 0:
        return DecisionNode()

    current_score = scoref(rows)      # 分類前的得分
    best_gain = 0.0
    best_criteria = None
    best_sets = None

    column_count = len(rows[0]) - 1    # 特征數(shù)量
    for col in range(column_count):
        # 在當前列中生成一個由不同值構成的序列
        column_values = {}
        for row in rows:
            column_values[row[col]] = 1
        # 分類
        for value in column_values.keys():
            set_1, set_2 = divide_set(rows, col, value)

            p = float(len(set_1)) / len(rows)
            gain = current_score - p * scoref(set_1) - (1 - p) * scoref(set_2)
            if gain > best_gain and len(set_1) > 0 and len(set_2) > 0:
                best_gain = gain
                best_criteria = (col, value)
                best_sets = (set_1, set_2)
        # 創(chuàng)建子分支
    if best_gain > 0:
        # 不是葉子結點钓试,繼續(xù)遞歸分類野哭,分類結果res=None, 判斷條件(特征)為col,臨界值為value
        true_branch = build_tree(best_sets[0])
        false_branch = build_tree(best_sets[1])
        return DecisionNode(col=best_criteria[0], value=best_criteria[1], tb=true_branch, fb=false_branch)
    else:
        # 不能再分類肋僧,返回分類的計數(shù)結果
        return DecisionNode(results=unique_counts(rows))

DecisionNode類

class DecisionNode:
    def __init__(
            self,
            col=-1,
            value=None,
            results=None,
            tb=None,
            fb=None
    ):
        self.col = col              # the criteria to be tested
        self.value = value          # true value
        self.results = results      # 分類結果,非葉子結點均為None
        self.tb = tb                # true
        self.fb = fb                # false

divide_set分割數(shù)據(jù)

def divide_set(rows, column, value):
    # 根據(jù)value對數(shù)據(jù)進行2分類缸托,set_1中為true, set_2中為false
    split_function = None
    if isinstance(value, int) or isinstance(value, float):
        split_function = lambda row: row[column] >= value
    else:
        split_function = lambda row: row[column] == value

    set_1 = [row for row in rows if split_function(row)]
    set_2 = [row for row in rows if not split_function(row)]

    return set_1, set_2

unique_counts對分類結果計數(shù)

def unique_counts(rows):
    results = {}
    for row in rows:
        r = row[len(row) - 1]    # 分類結果:None, Basic, Premium
        if r not in results:
            results[r] = 0
        results[r] += 1
    return results

entropy計算交叉熵

def entropy(rows):
    results = unique_counts(rows)
    ent = 0.0
    for r in results.keys():
        p = float(results[r]) / len(rows)
        ent -= p * log2(p)
    return ent

3.運行測試

測試數(shù)據(jù)

my_data = [['slashdot', 'USA', 'yes', 18, 'None'],
           ['google', 'France', 'yes', 23, 'Premium'],
           ['digg', 'USA', 'yes', 24, 'Basic'],
           ['kiwibotes', 'France', 'yes', 23, 'Basic'],
           ['google', 'UK', 'no', 21, 'Premium'],
           ['(direct)', 'New Zealand', 'no', 12, 'None'],
           ['(direct)', 'UK', 'no', 21, 'Basic'],
           ['google', 'USA', 'no', 24, 'Premium'],
           ['slashdot', 'France', 'yes', 19, 'None'],
           ['digg', 'USA', 'no', 18, 'None'],
           ['google', 'UK', 'no', 18, 'None'],
           ['kiwitobes', 'UK', 'no', 19, 'None'],
           ['digg', 'New Zealand', 'yes', 12, 'Basic'],
           ['google', 'UK', 'yes', 18, 'Basic'],
           ['kiwitobes', 'France', 'yes', 19, 'Basic']]

展示結果

def print_tree(tree, indent=''):
    # 葉子結點,其results為分類結果瘾蛋;否則俐镐,其results為None
    if tree.results is not None:
        print(str(tree.results))
    else:
        # 打印判斷條件
        print(str(tree.col) + ':' + str(tree.value) + "?")
        # 打印分支
        print(indent + "T->", end='')
        print_tree(tree.tb, indent+'  ')
        print(indent + "F->", end='')
        print_tree(tree.fb, indent+'  ')

運行結果

3:21?
T->0:google?
  T->{'Premium': 3}
  F->{'Basic': 3}
F->2:yes?
  T->0:slashdot?
    T->{'None': 2}
    F->{'Basic': 3}
  F->{'None': 4}

可以驗證,決策樹在訓練集上準確率為100%


最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哺哼,一起剝皮案震驚了整個濱河市佩抹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌取董,老刑警劉巖棍苹,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異茵汰,居然都是意外死亡枢里,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門经窖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人梭灿,你說我怎么就攤上這事画侣。” “怎么了堡妒?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵配乱,是天一觀的道長。 經(jīng)常有香客問我皮迟,道長搬泥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任伏尼,我火速辦了婚禮忿檩,結果婚禮上,老公的妹妹穿的比我還像新娘爆阶。我一直安慰自己燥透,他們只是感情好沙咏,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著班套,像睡著了一般肢藐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吱韭,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天吆豹,我揣著相機與錄音,去河邊找鬼理盆。 笑死痘煤,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的熏挎。 我是一名探鬼主播速勇,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼坎拐!你這毒婦竟也來了烦磁?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤哼勇,失蹤者是張志新(化名)和其女友劉穎都伪,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體积担,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡陨晶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了帝璧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片先誉。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖的烁,靈堂內(nèi)的尸體忽然破棺而出褐耳,到底是詐尸還是另有隱情,我是刑警寧澤渴庆,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布铃芦,位于F島的核電站,受9級特大地震影響襟雷,放射性物質(zhì)發(fā)生泄漏刃滓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一耸弄、第九天 我趴在偏房一處隱蔽的房頂上張望咧虎。 院中可真熱鬧,春花似錦计呈、人聲如沸老客。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胧砰。三九已至鳍鸵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尉间,已是汗流浹背偿乖。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留哲嘲,地道東北人贪薪。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像眠副,于是被迫代替她去往敵國和親画切。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

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