1. 程式人生 > >【機器學習實戰】第3章 決策樹

【機器學習實戰】第3章 決策樹

第3章 決策樹

<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>

決策樹_首頁

決策樹 概述

決策樹(Decision Tree)演算法主要用來處理分類問題,是最經常使用的資料探勘演算法之一。

決策樹 場景

一個叫做 "二十個問題" 的遊戲,遊戲的規則很簡單:參與遊戲的一方在腦海中想某個事物,其他參與者向他提問,只允許提 20 個問題,問題的答案也只能用對或錯回答。問問題的人通過推斷分解,逐步縮小待猜測事物的範圍,最後得到遊戲的答案。

一個郵件分類系統,大致工作流程如下:

決策樹-流程圖

首先檢測傳送郵件域名地址。如果地址為 myEmployer.com, 則將其放在分類 "無聊時需要閱讀的郵件"中。
如果郵件不是來自這個域名,則檢測郵件內容裡是否包含單詞 "曲棍球" , 如果包含則將郵件歸類到 "需要及時處理的朋友郵件", 
如果不包含則將郵件歸類到 "無需閱讀的垃圾郵件" 。

決策樹 原理

決策樹 須知概念

資訊熵 & 資訊增益

熵: 熵(entropy)指的是體系的混亂的程度,在不同的學科中也有引申出的更為具體的定義,是各領域十分重要的參量。

資訊熵(夏農熵): 是一種資訊的度量方式,表示資訊的混亂程度,也就是說:資訊越有序,資訊熵越低。例如:火柴有序放在火柴盒裡,熵值很低,相反,熵值很高。

資訊增益: 在劃分資料集前後資訊發生的變化稱為資訊增益。

決策樹 工作原理

如何構造一個決策樹?
我們使用 createBranch() 方法,如下所示:

檢測資料集中的所有資料的分類標籤是否相同:
    If so return 類標籤
    Else:
        尋找劃分資料集的最好特徵(劃分之後資訊熵最小,也就是資訊增益最大的特徵)
        劃分資料集
        建立分支節點
            for 每個劃分的子集
                呼叫函式 createBranch (建立分支的函式)並增加返回結果到分支節點中
        return 分支節點

決策樹 開發流程

收集資料:可以使用任何方法。
準備資料:樹構造演算法只適用於標稱型資料,因此數值型資料必須離散化。
分析資料:可以使用任何方法,構造樹完成之後,我們應該檢查圖形是否符合預期。
訓練演算法:構造樹的資料結構。
測試演算法:使用經驗樹計算錯誤率。(經驗樹沒有搜尋到較好的資料,有興趣的同學可以來補充)
使用演算法:此步驟可以適用於任何監督學習演算法,而使用決策樹可以更好地理解資料的內在含義。

決策樹 演算法特點

優點:計算複雜度不高,輸出結果易於理解,對中間值的缺失不敏感,可以處理不相關特徵資料。
缺點:可能會產生過度匹配問題。
適用資料型別:數值型和標稱型。

決策樹 專案案例

專案案例1: 判定魚類和非魚類

專案概述

根據以下 2 個特徵,將動物分成兩類:魚類和非魚類。

特徵:

  1. 不浮出水面是否可以生存
  2. 是否有腳蹼

開發流程

收集資料:可以使用任何方法
準備資料:樹構造演算法只適用於標稱型資料,因此數值型資料必須離散化
分析資料:可以使用任何方法,構造樹完成之後,我們應該檢查圖形是否符合預期
訓練演算法:構造樹的資料結構
測試演算法:使用決策樹執行分類
使用演算法:此步驟可以適用於任何監督學習演算法,而使用決策樹可以更好地理解資料的內在含義

收集資料:可以使用任何方法

海洋生物資料

我們利用 createDataSet() 函式輸入資料

def createDataSet():
    dataSet = [[1, 1, 'yes'],
            [1, 1, 'yes'],
            [1, 0, 'no'],
            [0, 1, 'no'],
            [0, 1, 'no']]
    labels = ['no surfacing', 'flippers']
    return dataSet, labels

準備資料:樹構造演算法只適用於標稱型資料,因此數值型資料必須離散化

此處,由於我們輸入的資料本身就是離散化資料,所以這一步就省略了。

分析資料:可以使用任何方法,構造樹完成之後,我們應該檢查圖形是否符合預期

熵的計算公式

計算給定資料集的夏農熵的函式

def calcShannonEnt(dataSet):
    # 求list的長度,表示計算參與訓練的資料量
    numEntries = len(dataSet)
    # 計算分類標籤label出現的次數
    labelCounts = {}
    # the the number of unique elements and their occurance
    for featVec in dataSet:
        # 將當前例項的標籤儲存,即每一行資料的最後一個數據代表的是標籤
        currentLabel = featVec[-1]
        # 為所有可能的分類建立字典,如果當前的鍵值不存在,則擴充套件字典並將當前鍵值加入字典。每個鍵值都記錄了當前類別出現的次數。
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1

    # 對於 label 標籤的佔比,求出 label 標籤的夏農熵
    shannonEnt = 0.0
    for key in labelCounts:
        # 使用所有類標籤的發生頻率計算類別出現的概率。
        prob = float(labelCounts[key])/numEntries
        # 計算夏農熵,以 2 為底求對數
        shannonEnt -= prob * log(prob, 2)
    return shannonEnt

按照給定特徵劃分資料集

將指定特徵的特徵值等於 value 的行剩下列作為子資料集。

def splitDataSet(dataSet, index, value):
    """splitDataSet(通過遍歷dataSet資料集,求出index對應的colnum列的值為value的行)
        就是依據index列進行分類,如果index列的資料等於 value的時候,就要將 index 劃分到我們建立的新的資料集中
    Args:
        dataSet 資料集                 待劃分的資料集
        index 表示每一行的index列        劃分資料集的特徵
        value 表示index列對應的value值   需要返回的特徵的值。
    Returns:
        index列為value的資料集【該資料集需要排除index列】
    """
    retDataSet = []
    for featVec in dataSet: 
        # index列為value的資料集【該資料集需要排除index列】
        # 判斷index列的值是否為value
        if featVec[index] == value:
            # chop out index used for splitting
            # [:index]表示前index行,即若 index 為2,就是取 featVec 的前 index 行
            reducedFeatVec = featVec[:index]
            '''
            請百度查詢一下: extend和append的區別
            list.append(object) 向列表中新增一個物件object
            list.extend(sequence) 把一個序列seq的內容新增到列表中
            1、使用append的時候,是將new_media看作一個物件,整體打包新增到music_media物件中。
            2、使用extend的時候,是將new_media看作一個序列,將這個序列和music_media序列合併,並放在其後面。
            result = []
            result.extend([1,2,3])
            print result
            result.append([4,5,6])
            print result
            result.extend([7,8,9])
            print result
            結果:
            [1, 2, 3]
            [1, 2, 3, [4, 5, 6]]
            [1, 2, 3, [4, 5, 6], 7, 8, 9]
            '''
            reducedFeatVec.extend(featVec[index+1:])
            # [index+1:]表示從跳過 index 的 index+1行,取接下來的資料
            # 收集結果值 index列為value的行【該行需要排除index列】
            retDataSet.append(reducedFeatVec)
    return retDataSet

選擇最好的資料集劃分方式

def chooseBestFeatureToSplit(dataSet):
    """chooseBestFeatureToSplit(選擇最好的特徵)

    Args:
        dataSet 資料集
    Returns:
        bestFeature 最優的特徵列
    """
    # 求第一行有多少列的 Feature, 最後一列是label列嘛
    numFeatures = len(dataSet[0]) - 1
    # 資料集的原始資訊熵
    baseEntropy = calcShannonEnt(dataSet)
    # 最優的資訊增益值, 和最優的Featurn編號
    bestInfoGain, bestFeature = 0.0, -1
    # iterate over all the features
    for i in range(numFeatures):
        # create a list of all the examples of this feature
        # 獲取對應的feature下的所有資料
        featList = [example[i] for example in dataSet]
        # get a set of unique values
        # 獲取剔重後的集合,使用set對list資料進行去重
        uniqueVals = set(featList)
        # 建立一個臨時的資訊熵
        newEntropy = 0.0
        # 遍歷某一列的value集合,計算該列的資訊熵 
        # 遍歷當前特徵中的所有唯一屬性值,對每個唯一屬性值劃分一次資料集,計算資料集的新熵值,並對所有唯一特徵值得到的熵求和。
        for value in uniqueVals:
            subDataSet = splitDataSet(dataSet, i, value)
            # 計算概率
            prob = len(subDataSet)/float(len(dataSet))
            # 計算資訊熵
            newEntropy += prob * calcShannonEnt(subDataSet)
        # gain[資訊增益]: 劃分資料集前後的資訊變化, 獲取資訊熵最大的值
        # 資訊增益是熵的減少或者是資料無序度的減少。最後,比較所有特徵中的資訊增益,返回最好特徵劃分的索引值。
        infoGain = baseEntropy - newEntropy
        print 'infoGain=', infoGain, 'bestFeature=', i, baseEntropy, newEntropy
        if (infoGain > bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature
問:上面的 newEntropy 為什麼是根據子集計算的呢?
答:因為我們在根據一個特徵計算夏農熵的時候,該特徵的分類值是相同,這個特徵這個分類的夏農熵為 0;
這就是為什麼計算新的夏農熵的時候使用的是子集。

訓練演算法:構造樹的資料結構

建立樹的函式程式碼如下:

def createTree(dataSet, labels):
    classList = [example[-1] for example in dataSet]
    # 如果資料集的最後一列的第一個值出現的次數=整個集合的數量,也就說只有一個類別,就只直接返回結果就行
    # 第一個停止條件:所有的類標籤完全相同,則直接返回該類標籤。
    # count() 函式是統計括號中的值在list中出現的次數
    if classList.count(classList[0]) == len(classList):
        return classList[0]
    # 如果資料集只有1列,那麼最初出現label次數最多的一類,作為結果
    # 第二個停止條件:使用完了所有特徵,仍然不能將資料集劃分成僅包含唯一類別的分組。
    if len(dataSet[0]) == 1:
        return majorityCnt(classList)

    # 選擇最優的列,得到最優列對應的label含義
    bestFeat = chooseBestFeatureToSplit(dataSet)
    # 獲取label的名稱
    bestFeatLabel = labels[bestFeat]
    # 初始化myTree
    myTree = {bestFeatLabel: {}}
    # 注:labels列表是可變物件,在PYTHON函式中作為引數時傳址引用,能夠被全域性修改
    # 所以這行程式碼導致函式外的同名變數被刪除了元素,造成例句無法執行,提示'no surfacing' is not in list
    del(labels[bestFeat])
    # 取出最優列,然後它的branch做分類
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)
    for value in uniqueVals:
        # 求出剩餘的標籤label
        subLabels = labels[:]
        # 遍歷當前選擇特徵包含的所有屬性值,在每個資料集劃分上遞迴呼叫函式createTree()
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
        # print 'myTree', value, myTree
    return myTree

測試演算法:使用決策樹執行分類

def classify(inputTree, featLabels, testVec):
    """classify(給輸入的節點,進行分類)

    Args:
        inputTree  決策樹模型
        featLabels Feature標籤對應的名稱
        testVec    測試輸入的資料
    Returns:
        classLabel 分類的結果值,需要對映label才能知道名稱
    """
    # 獲取tree的根節點對於的key值
    firstStr = inputTree.keys()[0]
    # 通過key得到根節點對應的value
    secondDict = inputTree[firstStr]
    # 判斷根節點名稱獲取根節點在label中的先後順序,這樣就知道輸入的testVec怎麼開始對照樹來做分類
    featIndex = featLabels.index(firstStr)
    # 測試資料,找到根節點對應的label位置,也就知道從輸入的資料的第幾位來開始分類
    key = testVec[featIndex]
    valueOfFeat = secondDict[key]
    print '+++', firstStr, 'xxx', secondDict, '---', key, '>>>', valueOfFeat
    # 判斷分枝是否結束: 判斷valueOfFeat是否是dict型別
    if isinstance(valueOfFeat, dict):
        classLabel = classify(valueOfFeat, featLabels, testVec)
    else:
        classLabel = valueOfFeat
    return classLabel

使用演算法:此步驟可以適用於任何監督學習演算法,而使用決策樹可以更好地理解資料的內在含義。

專案案例2: 使用決策樹預測隱形眼鏡型別

專案概述

隱形眼鏡型別包括硬材質、軟材質以及不適合佩戴隱形眼鏡。我們需要使用決策樹預測患者需要佩戴的隱形眼鏡型別。

開發流程

  1. 收集資料: 提供的文字檔案。
  2. 解析資料: 解析 tab 鍵分隔的資料行
  3. 分析資料: 快速檢查資料,確保正確地解析資料內容,使用 createPlot() 函式繪製最終的樹形圖。
  4. 訓練演算法: 使用 createTree() 函式。
  5. 測試演算法: 編寫測試函式驗證決策樹可以正確分類給定的資料例項。
  6. 使用演算法: 儲存樹的資料結構,以便下次使用時無需重新構造樹。

收集資料:提供的文字檔案

文字檔案資料格式如下:

young	myope	no	reduced	no lenses
pre	myope	no	reduced	no lenses
presbyopic	myope	no	reduced	no lenses

解析資料:解析 tab 鍵分隔的資料行

lecses = [inst.strip().split('\t') for inst in fr.readlines()]
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']

分析資料:快速檢查資料,確保正確地解析資料內容,使用 createPlot() 函式繪製最終的樹形圖。

>>> treePlotter.createPlot(lensesTree)

訓練演算法:使用 createTree() 函式

>>> lensesTree = trees.createTree(lenses, lensesLabels)
>>> lensesTree
{'tearRate': {'reduced': 'no lenses', 'normal': {'astigmatic':{'yes':
{'prescript':{'hyper':{'age':{'pre':'no lenses', 'presbyopic':
'no lenses', 'young':'hard'}}, 'myope':'hard'}}, 'no':{'age':{'pre':
'soft', 'presbyopic':{'prescript': {'hyper':'soft', 'myope':
'no lenses'}}, 'young':'soft'}}}}}

測試演算法: 編寫測試函式驗證決策樹可以正確分類給定的資料例項。

使用演算法: 儲存樹的資料結構,以便下次使用時無需重新構造樹。

使用 pickle 模組儲存決策樹

def storeTree(inputTree, filename):
    impory pickle
    fw = open(filename, 'w')
    pickle.dump(inputTree, fw)
    fw.close()

def grabTree(filename):
    import pickle
    fr = open(filename)
    return pickle.load(fr)

相關推薦

機器學習實戰3 決策

第3章 決策樹 <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script> 決策

機器學習實戰13 利用 PCA 來簡化數據

light nan 文本 com axis 均值 ... cati 二維空間 第13章 利用 PCA 來簡化數據 降維技術 場景 我們正通過電視觀看體育比賽,在電視的顯示器上有一個球。 顯示器大概包含了100萬像素點,而球則可能是由較少的像素點組成,例如說一千個像素

機器學習實戰2 K-近鄰演算法(k-NearestNeighbor,KNN)

第2章 k-近鄰演算法 <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>

機器學習實戰6 支援向量機(Support Vector Machine / SVM)

第6章 支援向量機 <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>

機器學習實戰1 機器學習基礎

第1章 機器學習基礎機器學習 概述機器學習就是把無序的資料轉換成有用的資訊。獲取海量的資料從海量資料中獲取有用的資訊我們會利用計算機來彰顯資料背後的真實含義,這才是機器學習的意義。機器學習 場景例如:

機器學習實戰10 K-Means(K-均值)聚類演算法

第 10章K-Means(K-均值)聚類演算法 K-Means 演算法 聚類是一種無監督的學習, 它將相似的物件歸到一個簇中, 將不相似物件歸到不同簇中. 相似這一概念取決於所選擇的相似度計算方法. K-Means 是發現給定資料集的 K 個簇的聚類演算法, 之

機器學習實戰6 支援向量機

def smoSimple(dataMatIn, classLabels, C, toler, maxIter): """smoSimple Args: dataMatIn 特徵集合 classLabels 類別標籤 C 鬆弛變數

機器學習實戰----決策

什麼是決策樹 決策樹的概念很好理解,因為它更類似人的思維進行分類,視覺化分類規則,如下圖所示,就是一個簡單的決策樹: 我們根據禮物的不同的特徵來進行劃分,最終可預測出我們是否喜歡這個禮物.樹模型的優點是顯而易見的:計算複雜度不高,輸出結果易於理解,對中間

機器學習實戰決策 程式碼

from math import logimport operatordef calcShannonEnt(dataSet):numEntries=len(dataSet)labelCounts={}for featVec in dataSet:currentLabel=fe

《web安全之機器學習入門》6決策與隨機森林演算法

決策樹識別pop3埠掃描(原書中識別暴力破解,實際上pop3協議的並沒有guess_passwd型別的資料,所以改為識別port_sweep.):待分析資料集:KDD-99資料集,連結:http://kdd.ics.uci.edu/databases/kddcup99/kdd

機器學習實戰2閱讀筆記3 使用K近鄰演算法改進約會網站的配對效果—分步驟詳細講解1——資料準備:從文字檔案中解析資料(附詳細程式碼及註釋)

 本篇使用的資料存放在文字檔案datingTestSet2.txt中,每個樣本資料佔據一行,總共有1000行。 樣本主要包含以下3中特徵: (1)每年獲得飛行常客里程數 (2)玩視訊遊戲所耗時間百分比 (3)每週消費的冰淇淋公升數 在使用分類器之前,需要將處理的檔案格式

吳恩達機器學習筆記:線性迴歸回顧

本章是對線性代數的一些簡單回顧,由於之前學過,所以這裡只是簡單的將課程中的一些例子粘過來 矩陣表示 矩陣加法和標量乘法 矩陣向量乘法 用矩陣向量乘法來同時計算多個預測值 矩陣乘法 用矩陣乘法同時計算多個迴歸

吳恩達機器學習筆記:多變數線性迴歸

目錄 多特徵下的目標函式 多元梯度下降法 多元梯度下降法中的方法 特徵縮放 選擇學習率 特徵和多項式迴歸 正規方程(區別於迭代法的直接解法) 正規方程在矩陣不可逆的情況下的解決方法

西瓜書學習筆記3:線性模型

課程前言: arg max的引數是函式最大化的某個函式的域的點,與全域性最大值相比引數函式的最大輸出,arg max指的是函式輸出儘可能大的輸入或引數 閉式解: 給出任意自變數,就可以求出因變數 最小二乘法: 通過最小化誤差的平方和尋找資料的最佳函式匹配

機器學習實戰 3.2在python 中使用matplotlib註解繪製樹形圖

《機器學習實戰》系列部落格主要是實現並理解書中的程式碼,相當於讀書筆記了。畢竟實戰不能光看書。動手就能遇到許多奇奇怪怪的問題。博文比較粗糙,需結合書本。博主邊查邊學,水平有限,有問題的地方評論區請多指教。書中的程式碼和資料,網上有很多請自行下載。 3.2.

構建之法3 軟件工程師的成長

問題解決 技術 相關 依賴問題 自動操作 層次 nbsp align 思想 1 軟件工程師的成長 積累軟件開發相關的知識,提升技術技能 積累問題領域的知識和經驗 對通用的軟件設計思想和軟件工程思想的理解 提升職業技能 實際成果 2 軟件工程師的思維思維誤區 分析麻痹

機器學習實戰7的一處代碼錯誤

traceback com post cond 解決 elm back document image --------------------------------------------------------------------------- IndexError

機器學習實戰8書本正文缺少一個函數

copy AR 機器 reg str 代碼 var div mean 在8.4.2 lasso的stageWist函數裏使用到了一個用於標準化的函數regularize,這個函數是需要自定義的,但是書中沒有給出來。 在示例代碼中有,是這樣子的: def regularize

Linux學習筆記4 Linux磁盤管理

linux centos 磁盤 格式化 LVM 4.1df命令df 查看文件系統磁盤空間使用情況。文件系統 磁盤總大小(kB) 已使用 可用 已用% 掛載點(目錄)Linux磁盤不能直接訪問,必須要有一個掛載點。參數:-h 可根據磁盤大小顯示適當的單位。帶有tmpfs代表臨時的

Linux學習筆記5 VIM工具

linux centos vim 5.1vim介紹vim是vi的升級版,帶有顏色顯示,先安裝包yum install -y vim-enhancedvim分為三種模式:一般模式、編輯模式、命令模式。 5.2vim顏色顯示和移動光標相同的文件信息在不同目錄下顯示顏色會有差異。相同內容,不同文件名,