機(jī)器學(xué)習(xí)之決策樹(上)

終于做到了決策樹柬姚,這是一個(gè)很有意思的分類模型

什么是決策樹

盡管我一直將決策樹理解為一個(gè)分類模型,但實(shí)際上捣域,他也是可以解決回歸問題的焕梅,如何理解決策樹呢贞言?
我們應(yīng)該從以下幾個(gè)方面理解:

1该窗、他是一棵樹
2、他是一堆If - then規(guī)則的集合
3义钉、定義在特征空間與類空間上的條件概率分布捶闸,決策樹實(shí)際上是將特征空間劃分成了互不相交的單元删壮,每個(gè)從根到葉的路徑對(duì)應(yīng)著一個(gè)單元央碟。決策樹所表示的條件概率分布由各個(gè)單元給定條件下類的條件概率分布組成均函。實(shí)際中苞也,哪個(gè)類別有較高的條件概率墩朦,就把該單元中的實(shí)例強(qiáng)行劃分為該類別氓涣。

決策樹有什么優(yōu)點(diǎn)

  • 模型具有可解釋性陋气,容易向業(yè)務(wù)部門人員描述巩趁。
  • 分類速度快

如何用決策樹分類

1议慰、特征選擇
2别凹、決策樹的生成
3、決策樹的剪枝
4堕战、分類

如何進(jìn)行特征選擇

先說為什么要進(jìn)行特征選擇?

我認(rèn)為,我們要搭建決策樹薪介,就要找到一系列的If-then條件汁政,而If-then條件又是依賴于特征空間的烂完,所以我們就要找到真正“管事”的特征抠蚣。

所以我們?cè)撊绾握业揭粋€(gè)管事的特征呢履澳?

很容易知道距贷,如果我們?cè)O(shè)計(jì)的分類規(guī)則帶來的結(jié)果與隨機(jī)分類的結(jié)果相差不大忠蝗,那么就說明這個(gè)我們選取的特征不管事阁最。

所以在這里,我們引入兩個(gè)概念:

  • 信息增益
  • 信息增益率
    我們要理解這兩個(gè)概念的話姜盈,首先要明白什么是熵:

熵馏颂,表示隨機(jī)變量的不確定性


Entropy

現(xiàn)在救拉,來解釋什么是信息增益:
按照上面講的亿絮,理所當(dāng)然葱绒,我們?cè)O(shè)置分類規(guī)則后地淀,這個(gè)點(diǎn)屬于的類別的不確定性應(yīng)該或多或少的有所減少岖是,也就是說豺撑,設(shè)置分類規(guī)則后的熵(條件熵)應(yīng)該比未設(shè)置分類規(guī)則前的熵要小一些聪轿,而小的部分就是信息增益陆错。


information gain

但是呢音瓷,信息增益有一些缺點(diǎn)绳慎,就是某個(gè)類別的樣本數(shù)如果很大的話杏愤,那么他的信息增益一定會(huì)很大。
所以乏奥,為了解決這種不準(zhǔn)確的問題亥曹,昆蘭(大佬)在ID3算法的基礎(chǔ)改進(jìn)媳瞪,提出了C4.5蛇受,利用信息增益率來解決問題兢仰,也就是用信息增益除以對(duì)應(yīng)的條件熵。


information gain ratio

如何生成決策樹

1轻专、ID3算法
通過比較信息增益请垛,獲得最優(yōu)的分類規(guī)則宗收,然后遞歸混稽,生成整個(gè)決策樹荚坞。
需要注意的地方:

  • 當(dāng)訓(xùn)練集(子集)只有一種類別時(shí)菲盾,生成葉子節(jié)點(diǎn)(類別)
    包括只有一個(gè)懒鉴,和都是一種的情況临谱。

2、c4.5算法

trick

將一些我在做的時(shí)候城豁,遇到的唱星,思考的一些有意思的地方:
1跟磨、經(jīng)驗(yàn)熵與經(jīng)驗(yàn)條件熵的估計(jì)方法,在書上我們可以看到哎榴,他簡(jiǎn)單的使用了頻率估計(jì)概率的方法估計(jì)得到了概率迎变,但是我們知道,這樣其實(shí)是不夠準(zhǔn)確的(裝逼的)氏豌,所以理所當(dāng)然的我們要用極大似然估計(jì)啊泵喘。
怎么用呢纪铺?

首先碟渺,我們先來回顧一下苫拍,在樸素貝葉斯的搭建過程中绒极,我們用到的極大似然估計(jì)是怎么回事?
我們通過貝葉斯公式展開了待求的條件概率榔袋,然后有兩個(gè)概率我們需要去估計(jì)一下:


待求概率

我們只說一下后面那個(gè):
首先就是他的實(shí)際意義:當(dāng)類別是Yi時(shí)凰兑,特征向量/第i維特征值是Xi的概率是多少吏够,顯然锅知,對(duì)于這個(gè)條件概率喉镰,我們并不知道該怎么求解惭笑,但是利用極大似然估計(jì)的想法沉噩,我們假設(shè)這個(gè)條件概率符合參數(shù)為thete的某種分布川蒙,當(dāng)然畜眨,如果我們想知道這個(gè)條件概率的話,我們只需要算出參數(shù)theta贰健,然后我們就得到了概率密度函數(shù)伶椿,剩下的就不用多說了氓侧,但是怎么算theta呢?我們就要用到訓(xùn)練數(shù)據(jù)了偎痛,也就是說:X1, X3, X6都是Y1類別的(舉例)看彼,那么出現(xiàn)X1,X3,X6同時(shí)為Y1類別的可能性(似然函數(shù))就非常的大了靖榕,所以后面的大家就都知道了茁计,求偏導(dǎo)谓松,等于零鬼譬,得到theta优质。

那么军洼,對(duì)于決策樹的這個(gè)問題呢匕争?我們?cè)趺蠢脴O大似然估計(jì)解決甘桑,其實(shí)是一樣的跑杭,只不過現(xiàn)在我們要求的不是剛才的第二個(gè)了艘蹋,而是第一個(gè)了女阀,同樣浸策,我們假設(shè)這個(gè)概率符合某種分布庸汗,我們需要求解這個(gè)參數(shù)蚯舱,同樣的我們將所有的為該類的數(shù)據(jù)全部帶入到似然函數(shù)中枉昏,使他最大化,這樣我們就算出來了這個(gè)概率兄裂。
下面是我是實(shí)現(xiàn)的代碼:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2019-02-02 14:19:55
# @Author  : Vophan Lee (vophanlee@gmail.com)
# @Link    : http://www.reibang.com/u/3e6114e983ad

from sklearn.datasets import make_classification
import numpy as np
import math


class decision_tree(object):
    """
    one step to access my dream
    """

    def __init__(self):
        super(decision_tree, self).__init__()
        self.features = 5
        self.samples = 100
        self.data = make_classification(n_samples=self.samples, n_features=self.features, n_classes=2)
        self.data_0 = []
        self.data_1 = []
        for i in enumerate(self.data[1]):
            if i[1] == 0:
                self.data_0.append(self.data[0][i[0]])
            else:
                self.data_1.append(self.data[0][i[0]])
        self.means_1 = np.mean(self.data_1, axis=0, keepdims=True).reshape(self.features)
        self.std_1 = np.std(self.data_1, axis=0, keepdims=True, ddof=1).reshape(self.features)
        self.means_0 = np.mean(self.data_0, axis=0, keepdims=True).reshape(self.features)
        self.std_0 = np.std(self.data_0, axis=0, keepdims=True, ddof=1).reshape(self.features)
        self.std = [self.std_0, self.std_1]
        self.means = [self.means_0, self.means_1]
        self.empirical_entropy = self.cal_emp_entropy()

    def cal_emp_entropy(self):
        all_p = []
        data_list = [self.data_0, self.data_1]
        for i in range(2):
            p = 1
            for dim in range(self.features):
                for data in data_list[i]:
                    # print(self.std[data_list.index(all_data)][dim])
                    p *= (1 / (pow(2 * math.pi, 0.5) * self.std[i][dim])) * pow(math.e, -(pow((data[dim] - self.means[i][dim]), 2) / 2 * pow(self.std[i][dim], 2)))
            all_p.append(p)

        entropy = 0
        for p in all_p:
            entropy += -p * math.log2(p)
        return entropy

2、我還想說些什么呢匾南?
就是蛆楞,書本上我們可以發(fā)現(xiàn)臊岸,給的特征都是離散的尊流,如果我們給幾組連續(xù)的特征呢逻住?比如西瓜書上的例子瞎访,西瓜的含糖率以及密度扒秸,我們應(yīng)該怎么處理呢伴奥?

在這里,有一種方法叫做二分法求最佳劃分點(diǎn)
首先翼闽,我們先對(duì)所有數(shù)據(jù)按照某一個(gè)維度排序拾徙,然后在將每?jī)蓚€(gè)點(diǎn)的中點(diǎn)作為劃分點(diǎn),然后分別計(jì)算他們的信息增益感局,最終確定一個(gè)最佳的劃分點(diǎn)

下面是我的全部代碼:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2019-02-03 15:17:08
# @Author  : Vophan Lee (vophanlee@gmail.com)
# @Link    : http://www.reibang.com/u/3e6114e983ad

from sklearn.datasets import make_classification
import numpy as np
import math


class Decision_Tree(object):
    """
    this is a class to build the decision tree
    """

    feature_list = []
    gain_list = []
    dim_list = []
    index = 0

    def __init__(self):
        super(Decision_Tree, self).__init__()
        self.features = 5
        self.samples = 100
        self.data = make_classification(
            n_samples=self.samples, n_features=self.features, n_classes=2)
        self.empirical_entropy = self.cal_emp_entropy(self.data)

    def cal_emp_entropy(self, data):
        """
        calculate the empirical entropy
        """
        data_0 = []
        data_1 = []
        for i in enumerate(data[1]):
            if i[1] == 0:
                data_0.append(data[0][i[0]])
            else:
                data_1.append(data[0][i[0]])
        entropy = 0
        for data_ in [data_0, data_1]:
            entropy += - \
                (len(data_) / len(data[0])) * \
                 math.log2(len(data_) / len(data[0]))
        return entropy

    def div_point(self, dim_data):
        """
        decide the divided point of each feature,here we sopposed that dim_data is a continuous dataset
        dim_data: tuple
        """
        def dichotomy(dim_data):
            div_points = np.zeros((1, self.samples)).reshape(self.samples)
            for i in enumerate(dim_data):
                if i[0] == len(dim_data) - 1:
                    break
                div_points[i[0]] = (dim_data[i[0] + 1] + i[1]) / 2
            return div_points
        dim_data = list(dim_data)
        dim_data = np.array(dim_data)
        dim_data = dim_data[:, dim_data[0].argsort()]
        dim_data = tuple(dim_data)
        div_points = dichotomy(dim_data[1])
        information_gain_list = []
        for i in div_points:
            div_index = list(div_points).index(i) + 1
            front = dim_data[1][:div_index]
            behind = dim_data[1][div_index:]
            front_flag = dim_data[0][:div_index]
            behind_flag = dim_data[0][div_index:]
            front_data = (front, front_flag)
            behind_data = (behind, behind_flag)
            if len(front_data[0]) == 1 or ((front_data[1] == front_data[1][::-1]).all() and len(front_data[0]) != len(dim_data[0]) / 2):
                behind_entropy = self.cal_emp_entropy(behind_data)
                information_gain = self.empirical_entropy - \
                    (behind_entropy * (len(behind) / len(dim_data[0])))
                information_gain_list.append(information_gain)
            elif len(behind_data[0]) == 1 or ((behind_data[1] == behind_data[1][::-1]).all() and len(front_data[0]) != len(dim_data[0]) / 2):
                front_entropy = self.cal_emp_entropy(front_data)
                information_gain = self.empirical_entropy - \
                    (front_entropy * (len(front) / len(dim_data[0])))
                information_gain_list.append(information_gain)
            elif (front_data[1] == front_data[1][::-1]).all() and len(front_data[0]) == len(dim_data[0]) / 2:

                return -1, div_points[int(len(dim_data[0]) / 2 - 1)]
            else:
                front_entropy = self.cal_emp_entropy(front_data)
                behind_entropy = self.cal_emp_entropy(behind_data)
                information_gain = self.empirical_entropy - (front_entropy * (len(front) / len(
                    dim_data[0])) + behind_entropy * (len(behind) / len(dim_data[0])))
                information_gain_list.append(information_gain)
        max_information_gain = max(information_gain_list)
        return max_information_gain, div_points[information_gain_list.index(max_information_gain)]

    def compare_features(self):
        """
        here we choose a maximium information gain among all features
        """
        gain_list_tmp = []
        point_list = []
        for i in range(self.features):
            information_gain, div_point = self.div_point((self.data[1], self.data[0].transpose()[i]))
            gain_list_tmp.append(information_gain)
            point_list.append(div_point)
        com_matrix = np.array([
            gain_list_tmp,
            point_list,
            range(self.features)
        ])
        com_matrix = com_matrix[:, com_matrix[0].argsort()]
        Decision_Tree.feature_list = list(com_matrix[1])
        Decision_Tree.gain_list = list(com_matrix[0])
        Decision_Tree.dim_list = list(com_matrix[2])

    def planet_tree(self, data):
        """
        here is the process of planeting the tree
        data: without flag
        """
        feature = Decision_Tree.feature_list[Decision_Tree.index]
        dim = Decision_Tree.dim_list[Decision_Tree.index]
        Decision_Tree.index += 1
        if Decision_Tree.gain_list[Decision_Tree.feature_list.index(feature)] == -1 or Decision_Tree.index >= len(Decision_Tree.feature_list) - 1:
            return tree_node([x for x in data.transpose()[int(dim)] if x < feature],
                             [x for x in data.transpose()[int(dim)] if x > feature],
                             feature)
        else:
            return tree_node(self.planet_tree([x for x in data[0] if x < feature]),self.planet_tree([x for x in data[0] if x > feature]), feature)

class tree_node(object):
    """
    this is the node of the decision tree
    """

    def __init__(self, left, right, data):
        self.left=left
        self.right=right
        self.data=data

這就是今天晚上的全部?jī)?nèi)容尼啡,剪枝以及回歸的內(nèi)容請(qǐng)關(guān)注我后續(xù)的文章哦

晚上01:28
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市询微,隨后出現(xiàn)的幾起案子崖瞭,更是在濱河造成了極大的恐慌代态,老刑警劉巖西雀,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)丑孩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門仗岖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來黄痪,“玉大人是嗜,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵果正,是天一觀的道長(zhǎng)潦闲。 經(jīng)常有香客問我,道長(zhǎng)赵辕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任衰粹,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己某弦,他們只是感情好员萍,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著窖张,像睡著了一般辕录。 火紅的嫁衣襯著肌膚如雪副女。 梳的紋絲不亂的頭發(fā)上塞绿,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天棋返,我揣著相機(jī)與錄音酵颁,去河邊找鬼嚷辅。 笑死扁位,一個(gè)胖子當(dāng)著我的面吹牛暇务,可吹牛的內(nèi)容都是我干的腻豌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了忆首?” 一聲冷哼從身側(cè)響起唇聘,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤匈庭,失蹤者是張志新(化名)和其女友劉穎鸽扁,沒想到半個(gè)月后骡和,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年巴元,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡塔粒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤宛逗,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布凶异,位于F島的核電站贴铜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜向臀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一会喝、第九天 我趴在偏房一處隱蔽的房頂上張望岭妖。 院中可真熱鬧,春花似錦、人聲如沸存皂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)信粮。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鲫尊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蜓堕,地道東北人沸毁。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像凯旋,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子味悄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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

  • 一、決策樹應(yīng)用體驗(yàn) 分類 ??從上面可以看出,決策樹對(duì)分類具有線性回歸無可比擬的優(yōu)勢(shì), 如果對(duì)未參與訓(xùn)練的數(shù)據(jù)集是...
    楊強(qiáng)AT南京閱讀 1,242評(píng)論 1 3
  • ??決策樹(Decision Tree)是一種基本的分類與回歸方法翘鸭,其模型呈樹狀結(jié)構(gòu)守伸,在分類問題中尼摹,表示基于特征對(duì)...
    殉道者之花火閱讀 4,514評(píng)論 2 2
  • 決策樹理論在決策樹理論中,有這樣一句話和二,“用較少的東西惕它,照樣可以做很好的事情堡距。越是小的決策樹,越優(yōu)于大的決策樹”。...
    制杖灶灶閱讀 5,840評(píng)論 0 25
  • 運(yùn)行平臺(tái):Windows Python版本:Python3.x IDE:pycharm 一拇勃、決策樹 決策樹是什么?...
    ghostdogss閱讀 1,869評(píng)論 0 1
  • 文/二姑娘 01 放暑假回家的第一天,我爸問我:“期末考得怎么樣?今年還有希望拿獎(jiǎng)學(xué)金嗎捌省?”我閃爍其辭苫纤,無法給出一...
    二姑娘兒閱讀 5,687評(píng)論 142 141