吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

決策樹的原理和決策樹構建的準備工作,機器學習決策樹的原理

電子工程師 ? 來源:未知 ? 作者:李倩 ? 2018-10-08 14:26 ? 次閱讀

一、前言

本篇討論決策樹的原理和決策樹構建的準備工作,機器學習決策樹的原理,以及如何選擇最優特征作為分類特征,決策樹構建,決策樹可視化,使用決策樹進行分類預測,決策樹的存儲和讀取以及sklearn實戰之預測隱形眼睛類型。

本文出現的所有代碼,均可在github上下載,歡迎Follow、Star:Github地址:https://github.com/yaoguangju/machine_learning

二、決策樹的基礎

1、決策樹是什么

決策樹是什么?決策樹(decision tree)是一種基本的分類與回歸方法。舉個通俗易懂的例子,如下圖所示的流程圖就是一個決策樹,長方形代表判斷模塊(decision block),橢圓形成代表終止模塊(terminating block),表示已經得出結論,可以終止運行。從判斷模塊引出的左右箭頭稱作為分支(branch),它可以達到另一個判斷模塊或者終止模塊。我們還可以這樣理解,分類決策樹模型是一種描述對實例進行分類的樹形結構。決策樹由結點(node)和有向邊(directed edge)組成。結點有兩種類型:內部結點(internal node)和葉結點(leaf node)。內部結點表示一個特征或屬性,葉結點表示一個類。蒙圈沒??

如下圖所示的決策樹,長方形和橢圓形都是結點。長方形的結點屬于內部結點,橢圓形的結點屬于葉結點,從結點引出的左右箭頭就是有向邊。而最上面的結點就是決策樹的根結點(root node)。這樣,結點說法就與模塊說法對應上了。

我們回到這個流程圖,對,你沒看錯,這就是一個假想的相親對象分類系統。它首先檢測相親對方是否有房。如果有房,則對于這個相親對象可以考慮進一步接觸。如果沒有房,則觀察相親對象是否有上進心,如果沒有,直接Say Goodbye,此時可以說:”你人很好,但是我們不合適。”如果有,同樣也值得認真考慮。

不過這只是個簡單的相親對象分類系統,只是做了簡單的分類。真實情況可能要復雜得多,考慮因素也可以是五花八門。脾氣好嗎?會做飯嗎?愿意做家務嗎?家里幾個孩子?父母是干什么的?等等各種因素。

我們可以把決策樹看成一個if-then規則的集合,將決策樹轉換成if-then規則的過程是這樣的:由決策樹的根結點(root node)到葉結點(leaf node)的每一條路徑構建一條規則;路徑上內部結點的特征對應著規則的條件,而葉結點的類對應著規則的結論。決策樹的路徑或其對應的if-then規則集合具有一個重要的性質:互斥并且完備。這就是說,每一個實例都被一條路徑或一條規則所覆蓋,而且只被一條路徑或一條規則所覆蓋。這里所覆蓋是指實例的特征與路徑上的特征一致或實例滿足規則的條件。

使用決策樹做預測需要以下過程:

收集數據:可以使用任何方法。比如想構建一個相親系統,我們可以從媒婆那里,或者通過采訪相親對象獲取數據。根據他們考慮的因素和最終的選擇結果,就可以得到一些供我們利用的數據了。

準備數據:收集完的數據,我們要進行整理,將這些所有收集的信息按照一定規則整理出來,并排版,方便我們進行后續處理。

分析數據:可以使用任何方法,決策樹構造完成之后,我們可以檢查決策樹圖形是否符合預期。

訓練算法:這個過程也就是構造決策樹,同樣也可以說是決策樹學習,就是構造一個決策樹的數據結構。

測試算法:使用經驗樹計算錯誤率。當錯誤率達到了可接收范圍,這個決策樹就可以投放使用了。

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

2、決策樹的構建的準備工作

使用決策樹做預測的每一步驟都很重要,數據收集不到位,將會導致沒有足夠的特征讓我們構建錯誤率低的決策樹。數據特征充足,但是不知道用哪些特征好,將會導致無法構建出分類效果好的決策樹模型。從算法方面看,決策樹的構建是我們的核心內容。

決策樹要如何構建呢?通常,這一過程可以概括為3個步驟:特征選擇、決策樹的生成和決策樹的修剪。

特征選擇

特征選擇在于選取對訓練數據具有分類能力的特征。這樣可以提高決策樹學習的效率,如果利用一個特征進行分類的結果與隨機分類的結果沒有很大差別,則稱這個特征是沒有分類能力的。經驗上扔掉這樣的特征對決策樹學習的精度影響不大。通常特征選擇的標準是信息增益(information gain)或信息增益比,為了簡單,本文使用信息增益作為選擇特征的標準。那么,什么是信息增益?在講解信息增益之前,讓我們看一組實例,貸款申請樣本數據表。

希望通過所給的訓練數據學習一個貸款申請的決策樹,用于對未來的貸款申請進行分類,即當新的客戶提出貸款申請時,根據申請人的特征利用決策樹決定是否批準貸款申請。

特征選擇就是決定用哪個特征來劃分特征空間。比如,我們通過上述數據表得到兩個可能的決策樹,分別由兩個不同特征的根結點構成。

圖(a)所示的根結點的特征是年齡,有3個取值,對應于不同的取值有不同的子結點。圖(b)所示的根節點的特征是工作,有2個取值,對應于不同的取值有不同的子結點。兩個決策樹都可以從此延續下去。問題是:究竟選擇哪個特征更好些?這就要求確定選擇特征的準則。直觀上,如果一個特征具有更好的分類能力,或者說,按照這一特征將訓練數據集分割成子集,使得各個子集在當前條件下有最好的分類,那么就更應該選擇這個特征。信息增益就能夠很好地表示這一直觀的準則。

什么是信息增益呢?在劃分數據集之后信息發生的變化稱為信息增益,知道如何計算信息增益,我們就可以計算每個特征值劃分數據集獲得的信息增益,獲得信息增益最高的特征就是最好的選擇。

(1)香農熵

在可以評測哪個數據劃分方式是最好的數據劃分之前,我們必須學習如何計算信息增益。集合信息的度量方式成為香農熵或者簡稱為熵(entropy),這個名字來源于信息論之父克勞德·香農。

如果看不明白什么是信息增益和熵,請不要著急,因為他們自誕生的那一天起,就注定會令世人十分費解。克勞德·香農寫完信息論之后,約翰·馮·諾依曼建議使用”熵”這個術語,因為大家都不知道它是什么意思。

熵定義為信息的期望值。在信息論與概率統計中,熵是表示隨機變量不確定性的度量。如果待分類的事物可能劃分在多個分類之中,則符號xi的信息定義為 :

其中p(xi)是選擇該分類的概率。有人可能會問,信息為啥這樣定義啊?答曰:前輩得出的結論。這就跟1+1等于2一樣,記住并且會用即可。上述式中的對數以2為底,也可以e為底(自然對數)。

通過上式,我們可以得到所有類別的信息。為了計算熵,我們需要計算所有類別所有可能值包含的信息期望值(數學期望),通過下面的公式得到:

其中n是分類的數目。熵越大,隨機變量的不確定性就越大。

當熵中的概率由數據估計(特別是最大似然估計)得到時,所對應的熵稱為經驗熵(empirical entropy)。什么叫由數據估計?比如有10個數據,一共有兩個類別,A類和B類。其中有7個數據屬于A類,則該A類的概率即為十分之七。其中有3個數據屬于B類,則該B類的概率即為十分之三。淺顯的解釋就是,這概率是我們根據數據數出來的。我們定義貸款申請樣本數據表中的數據為訓練數據集D,則訓練數據集D的經驗熵為H(D),|D|表示其樣本容量,及樣本個數。設有K個類Ck, = 1,2,3,…,K,|Ck|為屬于類Ck的樣本個數,因此經驗熵公式就可以寫為 :

根據此公式計算經驗熵H(D),分析貸款申請樣本數據表中的數據。最終分類結果只有兩類,即放貸和不放貸。根據表中的數據統計可知,在15個數據中,9個數據的結果為放貸,6個數據的結果為不放貸。所以數據集D的經驗熵H(D)為:

經過計算可知,數據集D的經驗熵H(D)的值為0.971。

(2)編寫代碼計算經驗熵

在編寫代碼之前,我們先對數據集進行屬性標注。

年齡:0代表青年,1代表中年,2代表老年;

有工作:0代表否,1代表是;

有自己的房子:0代表否,1代表是;

信貸情況:0代表一般,1代表好,2代表非常好;

類別(是否給貸款):no代表否,yes代表是。

確定這些之后,我們就可以創建數據集,并計算經驗熵了,代碼編寫如下:

代碼運行結果如下圖所示,代碼是先打印訓練數據集,然后打印計算的經驗熵H(D),程序計算的結果與我們統計計算的結果是一致的,程序沒有問題。

(3) 信息增益

在上面,我們已經說過,如何選擇特征,需要看信息增益。也就是說,信息增益是相對于特征而言的,信息增益越大,特征對最終的分類結果影響也就越大,我們就應該選擇對最終分類結果影響最大的那個特征作為我們的分類特征。

在講解信息增益定義之前,我們還需要明確一個概念,條件熵。

熵我們知道是什么,條件熵又是個什么鬼?條件熵H(Y|X)表示在已知隨機變量X的條件下隨機變量Y的不確定性,隨機變量X給定的條件下隨機變量Y的條件熵(conditional entropy)H(Y|X),定義為X給定條件下Y的條件概率分布的熵對X的數學期望:

這里,

同理,當條件熵中的概率由數據估計(特別是極大似然估計)得到時,所對應的條件熵成為條件經驗熵(empirical conditional entropy)。

明確了條件熵和經驗條件熵的概念。接下來,讓我們說說信息增益。前面也提到了,信息增益是相對于特征而言的。所以,特征A對訓練數據集D的信息增益g(D,A),定義為集合D的經驗熵H(D)與特征A給定條件下D的經驗條件熵H(D|A)之差,即:

一般地,熵H(D)與條件熵H(D|A)之差成為互信息(mutual information)。決策樹學習中的信息增益等價于訓練數據集中類與特征的互信息。

設特征A有n個不同的取值{a1,a2,···,an},根據特征A的取值將D劃分為n個子集{D1,D2,···,Dn},|Di|為Di的樣本個數。記子集Di中屬于Ck的樣本的集合為Dik,即Dik = Di ∩ Ck,|Dik|為Dik的樣本個數。于是經驗條件熵的公式可以些為:

說了這么多概念性的東西,沒有聽懂也沒有關系,舉幾個例子,再回來看一下概念,就懂了。

以貸款申請樣本數據表為例進行說明。看下年齡這一列的數據,也就是特征A1,一共有三個類別,分別是:青年、中年和老年。我們只看年齡是青年的數據,年齡是青年的數據一共有5個,所以年齡是青年的數據在訓練數據集出現的概率是十五分之五,也就是三分之一。同理,年齡是中年和老年的數據在訓練數據集出現的概率也都是三分之一。現在我們只看年齡是青年的數據的最終得到貸款的概率為五分之二,因為在五個數據中,只有兩個數據顯示拿到了最終的貸款,同理,年齡是中年和老年的數據最終得到貸款的概率分別為五分之三、五分之四。所以計算年齡的信息增益,過程如下:

同理,計算其余特征的信息增益g(D,A2)、g(D,A3)和g(D,A4)。分別為:

最后,比較特征的信息增益,由于特征A3(有自己的房子)的信息增益值最大,所以選擇A3作為最優特征。

(4) 編寫代碼計算信息增益

我們已經學會了通過公式計算信息增益,接下來編寫代碼,計算信息增益。

#-*-coding:UTF-8-*-frommathimportlog"""函數說明:計算給定數據集的經驗熵(香農熵)Parameters:dataSet-數據集Returns:shannonEnt-經驗熵(香農熵)"""defcalcShannonEnt(dataSet):numEntires=len(dataSet)#返回數據集的行數labelCounts={}#保存每個標簽(Label)出現次數的字典forfeatVecindataSet:#對每組特征向量進行統計currentLabel=featVec[-1]#提取標簽(Label)信息ifcurrentLabelnotinlabelCounts.keys():#如果標簽(Label)沒有放入統計次數的字典,添加進去labelCounts[currentLabel]=0labelCounts[currentLabel]+=1#Label計數shannonEnt=0.0#經驗熵(香農熵)forkeyinlabelCounts:#計算香農熵prob=float(labelCounts[key])/numEntires#選擇該標簽(Label)的概率shannonEnt-=prob*log(prob,2)#利用公式計算returnshannonEnt#返回經驗熵(香農熵)"""函數說明:創建測試數據集Parameters:無Returns:dataSet-數據集labels-特征標簽"""defcreateDataSet():dataSet=[[0,0,0,0,'no'],#數據集[0,0,0,1,'no'],[0,1,0,1,'yes'],[0,1,1,0,'yes'],[0,0,0,0,'no'],[1,0,0,0,'no'],[1,0,0,1,'no'],[1,1,1,1,'yes'],[1,0,1,2,'yes'],[1,0,1,2,'yes'],[2,0,1,2,'yes'],[2,0,1,1,'yes'],[2,1,0,1,'yes'],[2,1,0,2,'yes'],[2,0,0,0,'no']]labels=['年齡','有工作','有自己的房子','信貸情況']#特征標簽returndataSet,labels#返回數據集和分類屬性"""函數說明:選擇最優特征Parameters:dataSet-數據集Returns:bestFeature-信息增益最大的(最優)特征的索引值"""defchooseBestFeatureToSplit(dataSet):numFeatures=len(dataSet[0])-1#特征數量baseEntropy=calcShannonEnt(dataSet)#計算數據集的香農熵bestInfoGain=0.0#信息增益bestFeature=-1#最優特征的索引值foriinrange(numFeatures):#遍歷所有特征#獲取dataSet的第i個所有特征featList=[example[i]forexampleindataSet]uniqueVals=set(featList)#創建set集合{},元素不可重復newEntropy=0.0#經驗條件熵forvalueinuniqueVals:#計算信息增益subDataSet=splitDataSet(dataSet,i,value)#subDataSet劃分后的子集prob=len(subDataSet)/float(len(dataSet))#計算子集的概率newEntropy+=prob*calcShannonEnt(subDataSet)#根據公式計算經驗條件熵infoGain=baseEntropy-newEntropy#信息增益print("第%d個特征的增益為%.3f"%(i,infoGain))#打印每個特征的信息增益if(infoGain>bestInfoGain):#計算信息增益bestInfoGain=infoGain#更新信息增益,找到最大的信息增益bestFeature=i#記錄信息增益最大的特征的索引值returnbestFeature#返回信息增益最大的特征的索引值if__name__=='__main__':dataSet,features=createDataSet()print("最優特征索引值:"+str(chooseBestFeatureToSplit(dataSet)))

splitDataSet函數是用來選擇各個特征的子集的,比如選擇年齡(第0個特征)的青年(用0代表)的自己,我們可以調用splitDataSet(dataSet,0,0)這樣返回的子集就是年齡為青年的5個數據集。chooseBestFeatureToSplit是選擇選擇最優特征的函數。運行代碼結果如下:

對比我們自己計算的結果,發現結果完全正確!最優特征的索引值為2,也就是特征A3(有自己的房子)。

決策樹生成和修剪

我們已經學習了從數據集構造決策樹算法所需要的子功能模塊,包括經驗熵的計算和最優特征的選擇,其工作原理如下:得到原始數據集,然后基于最好的屬性值劃分數據集,由于特征值可能多于兩個,因此可能存在大于兩個分支的數據集劃分。第一次劃分之后,數據集被向下傳遞到樹的分支的下一個結點。在這個結點上,我們可以再次劃分數據。因此我們可以采用遞歸的原則處理數據集。

構建決策樹的算法有很多,比如C4.5、ID3和CART,這些算法在運行時并不總是在每次劃分數據分組時都會消耗特征。由于特征數目并不是每次劃分數據分組時都減少,因此這些算法在實際使用時可能引起一定的問題。目前我們并不需要考慮這個問題,只需要在算法開始運行前計算列的數目,查看算法是否使用了所有屬性即可。

決策樹生成算法遞歸地產生決策樹,直到不能繼續下去未為止。這樣產生的樹往往對訓練數據的分類很準確,但對未知的測試數據的分類卻沒有那么準確,即出現過擬合現象。過擬合的原因在于學習時過多地考慮如何提高對訓練數據的正確分類,從而構建出過于復雜的決策樹。解決這個問題的辦法是考慮決策樹的復雜度,對已生成的決策樹進行簡化。

三、決策樹構建

上篇文章也粗略提到過,構建決策樹的算法有很多。篇幅原因,本篇文章只使用ID3算法構建決策樹。

1、ID3算法

ID3算法的核心是在決策樹各個結點上對應信息增益準則選擇特征,遞歸地構建決策樹。具體方法是:從根結點(root node)開始,對結點計算所有可能的特征的信息增益,選擇信息增益最大的特征作為結點的特征,由該特征的不同取值建立子節點;再對子結點遞歸地調用以上方法,構建決策樹;直到所有特征的信息增益均很小或沒有特征可以選擇為止。最后得到一個決策樹。ID3相當于用極大似然法進行概率模型的選擇。

在使用ID3構造決策樹之前,我們再分析下數據。

利用上篇文章求得的結果,由于特征A3(有自己的房子)的信息增益值最大,所以選擇特征A3作為根結點的特征。它將訓練集D劃分為兩個子集D1(A3取值為”是”)和D2(A3取值為”否”)。由于D1只有同一類的樣本點,所以它成為一個葉結點,結點的類標記為“是”。

對D2則需要從特征A1(年齡),A2(有工作)和A4(信貸情況)中選擇新的特征,計算各個特征的信息增益:

根據計算,選擇信息增益最大的特征A2(有工作)作為結點的特征。由于A2有兩個可能取值,從這一結點引出兩個子結點:一個對應”是”(有工作)的子結點,包含3個樣本,它們屬于同一類,所以這是一個葉結點,類標記為”是”;另一個是對應”否”(無工作)的子結點,包含6個樣本,它們也屬于同一類,所以這也是一個葉結點,類標記為”否”。

這樣就生成了一個決策樹,該決策樹只用了兩個特征(有兩個內部結點),生成的決策樹如下圖所示。

這樣我們就使用ID3算法構建出來了決策樹,接下來,讓我們看看如何進行代實現。

2、編寫代碼構建決策樹

我們使用字典存儲決策樹的結構,比如上小節我們分析出來的決策樹,用字典可以表示為:

{'有自己的房子':{0:{'有工作':{0:'no',1:'yes'}},1:'yes'}}

創建函數majorityCnt統計classList中出現此處最多的元素(類標簽),創建函數createTree用來遞歸構建決策樹。編寫代碼如下:

#-*-coding:UTF-8-*-frommathimportlogimportoperator"""函數說明:計算給定數據集的經驗熵(香農熵)Parameters:dataSet-數據集Returns:shannonEnt-經驗熵(香農熵)"""defcalcShannonEnt(dataSet):numEntires=len(dataSet)#返回數據集的行數labelCounts={}#保存每個標簽(Label)出現次數的字典forfeatVecindataSet:#對每組特征向量進行統計currentLabel=featVec[-1]#提取標簽(Label)信息ifcurrentLabelnotinlabelCounts.keys():#如果標簽(Label)沒有放入統計次數的字典,添加進去labelCounts[currentLabel]=0labelCounts[currentLabel]+=1#Label計數shannonEnt=0.0#經驗熵(香農熵)forkeyinlabelCounts:#計算香農熵prob=float(labelCounts[key])/numEntires#選擇該標簽(Label)的概率shannonEnt-=prob*log(prob,2)#利用公式計算returnshannonEnt#返回經驗熵(香農熵)"""函數說明:創建測試數據集Parameters:無Returns:dataSet-數據集labels-特征標簽"""defcreateDataSet():dataSet=[[0,0,0,0,'no'],#數據集[0,0,0,1,'no'],[0,1,0,1,'yes'],[0,1,1,0,'yes'],[0,0,0,0,'no'],[1,0,0,0,'no'],[1,0,0,1,'no'],[1,1,1,1,'yes'],[1,0,1,2,'yes'],[1,0,1,2,'yes'],[2,0,1,2,'yes'],[2,0,1,1,'yes'],[2,1,0,1,'yes'],[2,1,0,2,'yes'],[2,0,0,0,'no']]labels=['年齡','有工作','有自己的房子','信貸情況']#特征標簽returndataSet,labels#返回數據集和分類屬性"""函數說明:按照給定特征劃分數據集Parameters:dataSet-待劃分的數據集axis-劃分數據集的特征value-需要返回的特征的值Returns:無"""defsplitDataSet(dataSet,axis,value):retDataSet=[]#創建返回的數據集列表forfeatVecindataSet:#遍歷數據集iffeatVec[axis]==value:reducedFeatVec=featVec[:axis]#去掉axis特征reducedFeatVec.extend(featVec[axis+1:])#將符合條件的添加到返回的數據集retDataSet.append(reducedFeatVec)returnretDataSet#返回劃分后的數據集"""函數說明:選擇最優特征Parameters:dataSet-數據集Returns:bestFeature-信息增益最大的(最優)特征的索引值"""defchooseBestFeatureToSplit(dataSet):numFeatures=len(dataSet[0])-1#特征數量baseEntropy=calcShannonEnt(dataSet)#計算數據集的香農熵bestInfoGain=0.0#信息增益bestFeature=-1#最優特征的索引值foriinrange(numFeatures):#遍歷所有特征#獲取dataSet的第i個所有特征featList=[example[i]forexampleindataSet]uniqueVals=set(featList)#創建set集合{},元素不可重復newEntropy=0.0#經驗條件熵forvalueinuniqueVals:#計算信息增益subDataSet=splitDataSet(dataSet,i,value)#subDataSet劃分后的子集prob=len(subDataSet)/float(len(dataSet))#計算子集的概率newEntropy+=prob*calcShannonEnt(subDataSet)#根據公式計算經驗條件熵infoGain=baseEntropy-newEntropy#信息增益#print("第%d個特征的增益為%.3f"%(i,infoGain))#打印每個特征的信息增益if(infoGain>bestInfoGain):#計算信息增益bestInfoGain=infoGain#更新信息增益,找到最大的信息增益bestFeature=i#記錄信息增益最大的特征的索引值returnbestFeature#返回信息增益最大的特征的索引值"""函數說明:統計classList中出現此處最多的元素(類標簽)Parameters:classList-類標簽列表Returns:sortedClassCount[0][0]-出現此處最多的元素(類標簽)"""defmajorityCnt(classList):classCount={}forvoteinclassList:#統計classList中每個元素出現的次數ifvotenotinclassCount.keys():classCount[vote]=0classCount[vote]+=1sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)#根據字典的值降序排序returnsortedClassCount[0][0]#返回classList中出現次數最多的元素"""函數說明:創建決策樹Parameters:dataSet-訓練數據集labels-分類屬性標簽featLabels-存儲選擇的最優特征標簽Returns:myTree-決策樹"""defcreateTree(dataSet,labels,featLabels):classList=[example[-1]forexampleindataSet]#取分類標簽(是否放貸:yesorno)ifclassList.count(classList[0])==len(classList):#如果類別完全相同則停止繼續劃分returnclassList[0]iflen(dataSet[0])==1:#遍歷完所有特征時返回出現次數最多的類標簽returnmajorityCnt(classList)bestFeat=chooseBestFeatureToSplit(dataSet)#選擇最優特征bestFeatLabel=labels[bestFeat]#最優特征的標簽featLabels.append(bestFeatLabel)myTree={bestFeatLabel:{}}#根據最優特征的標簽生成樹del(labels[bestFeat])#刪除已經使用特征標簽featValues=[example[bestFeat]forexampleindataSet]#得到訓練集中所有最優特征的屬性值uniqueVals=set(featValues)#去掉重復的屬性值forvalueinuniqueVals:#遍歷特征,創建決策樹。myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),labels,featLabels)returnmyTreeif__name__=='__main__':dataSet,labels=createDataSet()featLabels=[]myTree=createTree(dataSet,labels,featLabels)print(myTree)

遞歸創建決策樹時,遞歸有兩個終止條件:第一個停止條件是所有的類標簽完全相同,則直接返回該類標簽;第二個停止條件是使用完了所有特征,仍然不能將數據劃分僅包含唯一類別的分組,即決策樹構建失敗,特征不夠用。此時說明數據緯度不夠,由于第二個停止條件無法簡單地返回唯一的類標簽,這里挑選出現數量最多的類別作為返回值。

運行上述代碼,我們可以看到如下結果:

可見,我們的決策樹已經構建完成了。這時候,有的朋友可能會說,這個決策樹看著好別扭,雖然這個能看懂,但是如果多點的結點,就不好看了。能直觀點嗎?完全沒有問題,我們可以使用強大的Matplotlib繪制決策樹。

3、決策樹可視化

這里代碼都是關于Matplotlib的,如果對于Matplotlib不了解的,可以先學習下,Matplotlib的內容這里就不再累述。可視化需要用到的函數:

getNumLeafs:獲取決策樹葉子結點的數目

getTreeDepth:獲取決策樹的層數

plotNode:繪制結點

plotMidText:標注有向邊屬性值

plotTree:繪制決策樹

createPlot:創建繪制面板

對可視化決策樹的程序進行了詳細的注釋,直接看代碼,調試查看即可。為了顯示中文,需要設置FontProperties,代碼編寫如下:

(點擊圖片查看大圖)

不出意外的話,我們就可以得到如下結果,可以看到決策樹繪制完成。plotNode函數的工作就是繪制各個結點,比如有自己的房子、有工作、yes、no,包括內結點和葉子結點。plotMidText函數的工作就是繪制各個有向邊的屬性。

4、使用決策樹執行分類

依靠訓練數據構造了決策樹之后,我們可以將它用于實際數據的分類。在執行數據分類時,需要決策樹以及用于構造樹的標簽向量。然后,程序比較測試數據與決策樹上的數值,遞歸執行該過程直到進入葉子結點;最后將測試數據定義為葉子結點所屬的類型。在構建決策樹的代碼,可以看到,有個featLabels參數。它是用來干什么的?它就是用來記錄各個分類結點的,在用決策樹做預測的時候,我們按順序輸入需要的分類結點的屬性值即可。舉個例子,比如我用上述已經訓練好的決策樹做分類,那么我只需要提供這個人是否有房子,是否有工作這兩個信息即可,無需提供冗余的信息。

用決策樹做分類的代碼很簡單,編寫代碼如下:

(點擊圖片,查看大圖)

這里只增加了classify函數,用于決策樹分類。輸入測試數據[0,1],它代表沒有房子,但是有工作,分類結果如下所示:

看到這里,細心的朋友可能就會問了,每次做預測都要訓練一次決策樹?這也太麻煩了吧?有什么好的解決嗎?

5、決策樹的存儲

構造決策樹是很耗時的任務,即使處理很小的數據集,如前面的樣本數據,也要花費幾秒的時間,如果數據集很大,將會耗費很多計算時間。然而用創建好的決策樹解決分類問題,則可以很快完成。因此,為了節省計算時間,最好能夠在每次執行分類時調用已經構造好的決策樹。為了解決這個問題,需要使用Python模塊pickle序列化對象。序列化對象可以在磁盤上保存對象,并在需要的時候讀取出來。

假設我們已經得到決策樹

{'有自己的房子':{0:{'有工作':{0:'no',1:'yes'}},1:'yes'}}

使用pickle.dump存儲決策樹。

#-*-coding:UTF-8-*-importpickle"""函數說明:存儲決策樹Parameters:inputTree-已經生成的決策樹filename-決策樹的存儲文件名Returns:無"""defstoreTree(inputTree,filename):withopen(filename,'wb')asfw:pickle.dump(inputTree,fw)if__name__=='__main__':myTree={'有自己的房子':{0:{'有工作':{0:'no',1:'yes'}},1:'yes'}}storeTree(myTree,'classifierStorage.txt')

運行代碼,在該Python文件的相同目錄下,會生成一個名為classifierStorage.txt的txt文件,這個文件二進制存儲著我們的決策樹。我們可以使用VScode打開看下存儲結果。

看不懂?沒錯,因為這個是個二進制存儲的文件,我們也無需看懂里面的內容,會存儲,會用即可。那么問題來了。將決策樹存儲完這個二進制文件,然后下次使用的話,怎么用呢?

很簡單使用pickle.load進行載入即可,編寫代碼如下:

#-*-coding:UTF-8-*-importpickle"""函數說明:讀取決策樹Parameters:filename-決策樹的存儲文件名Returns:pickle.load(fr)-決策樹字典"""defgrabTree(filename):fr=open(filename,'rb')returnpickle.load(fr)if__name__=='__main__':myTree=grabTree('classifierStorage.txt')print(myTree)

如果在該Python文件的相同目錄下,有一個名為classifierStorage.txt的文件,那么我們就可以運行上述代碼,運行結果如下圖所示:

從上述結果中,我們可以看到,我們順利加載了存儲決策樹的二進制文件。

四、Sklearn之使用決策樹預測隱形眼睛類型

1、實戰背景

進入本文的正題:眼科醫生是如何判斷患者需要佩戴隱形眼鏡的類型的?一旦理解了決策樹的工作原理,我們甚至也可以幫助人們判斷需要佩戴的鏡片類型。

隱形眼鏡數據集是非常著名的數據集,它包含很多換著眼部狀態的觀察條件以及醫生推薦的隱形眼鏡類型。隱形眼鏡類型包括硬材質(hard)、軟材質(soft)以及不適合佩戴隱形眼鏡(no lenses)。數據來源與UCI數據庫,數據集下載地址:點擊進入鏈接

一共有24組數據,數據的Labels依次是age、prescript、astigmatic、tearRate、class,也就是第一列是年齡,第二列是癥狀,第三列是是否散光,第四列是眼淚數量,第五列是最終的分類標簽。數據如下圖所示:

可以使用已經寫好的Python程序構建決策樹,不過出于繼續學習的目的,本文使用Sklearn實現。

2、使用Sklearn構建決策樹

官方英文文檔地址:

http://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html

sklearn.tree模塊提供了決策樹模型,用于解決分類問題和回歸問題。方法如下圖所示:

本次實戰內容使用的是DecisionTreeClassifier和export_graphviz,前者用于決策樹構建,后者用于決策樹可視化。

DecisionTreeClassifier構建決策樹:

讓我們先看下DecisionTreeClassifier這個函數,一共有12個參數:

參數說明如下:

criterion:特征選擇標準,可選參數,默認是gini,可以設置為entropy。gini是基尼不純度,是將來自集合的某種結果隨機應用于某一數據項的預期誤差率,是一種基于統計的思想。entropy是香農熵,也就是上篇文章講過的內容,是一種基于信息論的思想。Sklearn把gini設為默認參數,應該也是做了相應的斟酌的,精度也許更高些?ID3算法使用的是entropy,CART算法使用的則是gini。

splitter:特征劃分點選擇標準,可選參數,默認是best,可以設置為random。每個結點的選擇策略。best參數是根據算法選擇最佳的切分特征,例如gini、entropy。random隨機的在部分劃分點中找局部最優的劃分點。默認的”best”適合樣本量不大的時候,而如果樣本數據量非常大,此時決策樹構建推薦”random”。

max_features:劃分時考慮的最大特征數,可選參數,默認是None。尋找最佳切分時考慮的最大特征數(n_features為總共的特征數),有如下6種情況:

如果max_features是整型的數,則考慮max_features個特征;

如果max_features是浮點型的數,則考慮int(max_features * n_features)個特征;

如果max_features設為auto,那么max_features = sqrt(n_features);

如果max_features設為sqrt,那么max_featrues = sqrt(n_features),跟auto一樣;

如果max_features設為log2,那么max_features = log2(n_features);

如果max_features設為None,那么max_features = n_features,也就是所有特征都用。

一般來說,如果樣本特征數不多,比如小于50,我們用默認的”None”就可以了,如果特征數非常多,我們可以靈活使用剛才描述的其他取值來控制劃分時考慮的最大特征數,以控制決策樹的生成時間。

max_depth:決策樹最大深,可選參數,默認是None。這個參數是這是樹的層數的。層數的概念就是,比如在貸款的例子中,決策樹的層數是2層。如果這個參數設置為None,那么決策樹在建立子樹的時候不會限制子樹的深度。一般來說,數據少或者特征少的時候可以不管這個值。或者如果設置了min_samples_slipt參數,那么直到少于- - - min_smaples_split個樣本為止。如果模型樣本量多,特征也多的情況下,推薦限制這個最大深度,具體的取值取決于數據的分布。常用的可以取值10-100之間。

min_samples_split:內部節點再劃分所需最小樣本數,可選參數,默認是2。這個值限制了子樹繼續劃分的條件。如果min_samples_split為整數,那么在切分內部結點的時候,min_samples_split作為最小的樣本數,也就是說,如果樣本已經少于min_samples_split個樣本,則停止繼續切分。如果min_samples_split為浮點數,那么min_samples_split就是一個百分比,ceil(min_samples_split * n_samples),數是向上取整的。如果樣本量不大,不需要管這個值。如果樣本量數量級非常大,則推薦增大這個值。

min_samples_leaf:葉子節點最少樣本數,可選參數,默認是1。這個值限制了葉子節點最少的樣本數,如果某葉子節點數目小于樣本數,則會和兄弟節點一起被剪枝。葉結點需要最少的樣本數,也就是最后到葉結點,需要多少個樣本才能算一個葉結點。如果設置為1,哪怕這個類別只有1個樣本,決策樹也會構建出來。如果min_samples_leaf是整數,那么min_samples_leaf作為最小的樣本數。如果是浮點數,那么min_samples_leaf就是一個百分比,同上,celi(min_samples_leaf * n_samples),數是向上取整的。如果樣本量不大,不需要管這個值。如果樣本量數量級非常大,則推薦增大這個值。

min_weight_fraction_leaf:葉子節點最小的樣本權重和,可選參數,默認是0。這個值限制了葉子節點所有樣本權重和的最小值,如果小于這個值,則會和兄弟節點一起被剪枝。一般來說,如果我們有較多樣本有缺失值,或者分類樹樣本的分布類別偏差很大,就會引入樣本權重,這時我們就要注意這個值了。

max_leaf_nodes:最大葉子節點數,可選參數,默認是None。通過限制最大葉子節點數,可以防止過擬合。如果加了限制,算法會建立在最大葉子節點數內最優的決策樹。如果特征不多,可以不考慮這個值,但是如果特征分成多的話,可以加以限制,具體的值可以通過交叉驗證得到。

class_weight:類別權重,可選參數,默認是None,也可以字典、字典列表、balanced。指定樣本各類別的的權重,主要是為了防止訓練集某些類別的樣本過多,導致訓練的決策樹過于偏向這些類別。類別的權重可以通過{class_label:weight}這樣的格式給出,這里可以自己指定各個樣本的權重,或者用balanced,如果使用balanced,則算法會自己計算權重,樣本量少的類別所對應的樣本權重會高。當然,如果你的樣本類別分布沒有明顯的偏倚,則可以不管這個參數,選擇默認的None。

random_state:可選參數,默認是None。隨機數種子。如果是證書,那么random_state會作為隨機數生成器的隨機數種子。隨機數種子,如果沒有設置隨機數,隨機出來的數與當前系統時間有關,每個時刻都是不同的。如果設置了隨機數種子,那么相同隨機數種子,不同時刻產生的隨機數也是相同的。如果是RandomState instance,那么random_state是隨機數生成器。如果為None,則隨機數生成器使用np.random。

min_impurity_split:節點劃分最小不純度,可選參數,默認是1e-7。這是個閾值,這個值限制了決策樹的增長,如果某節點的不純度(基尼系數,信息增益,均方差,絕對差)小于這個閾值,則該節點不再生成子節點。即為葉子節點 。

presort:數據是否預排序,可選參數,默認為False,這個值是布爾值,默認是False不排序。一般來說,如果樣本量少或者限制了一個深度很小的決策樹,設置為true可以讓劃分點選擇更加快,決策樹建立的更加快。如果樣本量太大的話,反而沒有什么好處。問題是樣本量少的時候,我速度本來就不慢。所以這個值一般懶得理它就可以了。

除了這些參數要注意以外,其他在調參時的注意點有:

當樣本數量少但是樣本特征非常多的時候,決策樹很容易過擬合,一般來說,樣本數比特征數多一些會比較容易建立健壯的模型

如果樣本數量少但是樣本特征非常多,在擬合決策樹模型前,推薦先做維度規約,比如主成分分析(PCA),特征選擇(Losso)或者獨立成分分析(ICA)。這樣特征的維度會大大減小。再來擬合決策樹模型效果會好。

推薦多用決策樹的可視化,同時先限制決策樹的深度,這樣可以先觀察下生成的決策樹里數據的初步擬合情況,然后再決定是否要增加深度。

在訓練模型時,注意觀察樣本的類別情況(主要指分類樹),如果類別分布非常不均勻,就要考慮用class_weight來限制模型過于偏向樣本多的類別。

決策樹的數組使用的是numpy的float32類型,如果訓練數據不是這樣的格式,算法會先做copy再運行。

如果輸入的樣本矩陣是稀疏的,推薦在擬合前調用csc_matrix稀疏化,在預測前調用csr_matrix稀疏化。

sklearn.tree.DecisionTreeClassifier()提供了一些方法供我們使用,如下圖所示:

了解到這些,我們就可以編寫代碼了。

注意一點,由于fit()函數不能接收string類型的數據,通過打印的信息可以看到,數據都是string類型的。在使用fit()函數之前,我們需要對數據集進行編碼,這里可以使用兩種方法:

LabelEncoder :將字符串轉換為增量值

OneHotEncoder:使用One-of-K算法將字符串轉換為整數

為了對string類型的數據序列化,需要先生成pandas數據,這樣方便我們的序列化工作。這里我使用的方法是,原始數據->字典->pandas數據,編寫代碼如下:

importpandasaspdif__name__=='__main__':withopen('lenses.txt','r')asfr:#加載文件lenses=[inst.strip().split(' ')forinstinfr.readlines()]#處理文件lenses_target=[]#提取每組數據的類別,保存在列表里foreachinlenses:lenses_target.append(each[-1])lensesLabels=['age','prescript','astigmatic','tearRate']#特征標簽lenses_list=[]#保存lenses數據的臨時列表lenses_dict={}#保存lenses數據的字典,用于生成pandasforeach_labelinlensesLabels:#提取信息,生成字典foreachinlenses:lenses_list.append(each[lensesLabels.index(each_label)])lenses_dict[each_label]=lenses_listlenses_list=[]print(lenses_dict)#打印字典信息lenses_pd=pd.DataFrame(lenses_dict)#生成pandas.DataFrameprint(lenses_pd)

從運行結果可以看出,順利生成pandas數據。

接下來,將數據序列化,編寫代碼如下:

#-*-coding:UTF-8-*-importpandasaspdfromsklearn.preprocessingimportLabelEncoderimportpydotplusfromsklearn.externals.siximportStringIOif__name__=='__main__':withopen('lenses.txt','r')asfr:#加載文件lenses=[inst.strip().split(' ')forinstinfr.readlines()]#處理文件lenses_target=[]#提取每組數據的類別,保存在列表里foreachinlenses:lenses_target.append(each[-1])lensesLabels=['age','prescript','astigmatic','tearRate']#特征標簽lenses_list=[]#保存lenses數據的臨時列表lenses_dict={}#保存lenses數據的字典,用于生成pandasforeach_labelinlensesLabels:#提取信息,生成字典foreachinlenses:lenses_list.append(each[lensesLabels.index(each_label)])lenses_dict[each_label]=lenses_listlenses_list=[]#print(lenses_dict)#打印字典信息lenses_pd=pd.DataFrame(lenses_dict)#生成pandas.DataFrameprint(lenses_pd)#打印pandas.DataFramele=LabelEncoder()#創建LabelEncoder()對象,用于序列化forcolinlenses_pd.columns:#為每一列序列化lenses_pd[col]=le.fit_transform(lenses_pd[col])print(lenses_pd)

從打印結果可以看到,我們已經將數據順利序列化,接下來。我們就可以fit()數據,構建決策樹了。

3、使用Graphviz可視化決策樹

Graphviz的是AT&T Labs Research開發的圖形繪制工具,他可以很方便的用來繪制結構化的圖形網絡,支持多種格式輸出,生成圖片的質量和速度都不錯。它的輸入是一個用dot語言編寫的繪圖腳本,通過對輸入腳本的解析,分析出其中的點,邊以及子圖,然后根據屬性進行繪制。是使用Sklearn生成的決策樹就是dot格式的,因此我們可以直接利用Graphviz將決策樹可視化。

在講解編寫代碼之前,我們需要安裝兩樣東西,即pydotplus和Grphviz。

(1)安裝Pydotplus

pydotplus可以在CMD窗口中,直接使用指令安裝:

pipinstallpydotplus

(2)安裝Graphviz

Graphviz不能使用pip進行安裝,我們需要手動安裝,下載地址:http://www.graphviz.org/Home.php

下載好安裝包,進行安裝,安裝完畢之后,需要設置Graphviz的環境變量。

首先,按快捷鍵win+r,在出現的運行對話框中輸入sysdm.cpl,點擊確定,出現如下對話框:

選擇高級->環境變量。在系統變量的Path變量中,添加Graphviz的環境變量,比如Graphviz安裝在了D盤的根目錄,則添加:D:Graphvizin;

添加好環境變量之后,我們就可以正常使用Graphviz了。

(3)編寫代碼

代碼如下,可視化部分的代碼不難,都是有套路的,直接填參數就好,詳細內容可以查看官方教程:http://scikit-learn.org/stable/modules/tree.html#tree

運行代碼,在該python文件保存的相同目錄下,會生成一個名為tree的PDF文件,打開文件,我們就可以看到決策樹的可視化效果圖了。

確定好決策樹之后,我們就可以做預測了。可以根據自己的眼睛情況和年齡等特征,看一看自己適合何種材質的隱形眼鏡。使用如下代碼就可以看到預測結果:

print(clf.predict([[1,1,1,0]]))#預測

代碼簡單,官方手冊都有,就不全貼出來了。

五、總結

決策樹的一些優點:

易于理解和解釋。決策樹可以可視化。

幾乎不需要數據預處理。其他方法經常需要數據標準化,創建虛擬變量和刪除缺失值。決策樹還不支持缺失值。

使用樹的花費(例如預測數據)是訓練數據點(data points)數量的對數。

可以同時處理數值變量和分類變量。其他方法大都適用于分析一種變量的集合。

可以處理多值輸出變量問題。

使用白盒模型。如果一個情況被觀察到,使用邏輯判斷容易表示這種規則。相反,如果是黑盒模型(例如人工神經網絡),結果會非常難解釋。

即使對真實模型來說,假設無效的情況下,也可以較好的適用。

決策樹的一些缺點:

決策樹學習可能創建一個過于復雜的樹,并不能很好的預測數據。也就是過擬合。修剪機制(現在不支持),設置一個葉子節點需要的最小樣本數量,或者數的最大深度,可以避免過擬合。

決策樹可能是不穩定的,因為即使非常小的變異,可能會產生一顆完全不同的樹。這個問題通過decision trees with an ensemble來緩解。

概念難以學習,因為決策樹沒有很好的解釋他們,例如,XOR, parity or multiplexer problems。

如果某些分類占優勢,決策樹將會創建一棵有偏差的樹。因此,建議在訓練之前,先抽樣使樣本均衡。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 機器學習
    +關注

    關注

    66

    文章

    8438

    瀏覽量

    133080
  • 決策樹
    +關注

    關注

    3

    文章

    96

    瀏覽量

    13587

原文標題:機器學習決策樹算法實戰——理論+詳細的Python3代碼實現

文章出處:【微信號:rgznai100,微信公眾號:rgznai100】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    關于決策樹,這些知識點不可錯過

    `隨著科學技術的發展,AI愛好者越來越多,除了一些精通AI的大神,還有很多的技術小白也對這方面感興趣,他們想學習一些機器學習的入門知識。今天,訊飛開放平臺就帶來機器
    發表于 05-23 09:38

    決策樹機器學習的理論學習與實踐

    決策樹機器學習的理論學習與實踐
    發表于 09-20 12:48

    分類與回歸方法之決策樹

    統計學習方法決策樹
    發表于 11-05 13:40

    機器學習決策樹介紹

    機器學習——決策樹算法分析
    發表于 04-02 11:48

    ML之決策樹與隨機森林

    ML--決策樹與隨機森林
    發表于 07-08 12:31

    決策樹的生成資料

    在本文中,我們將討論一種監督式學習算法。最新一代意法半導體 MEMS 傳感器內置一個基于決策樹分類器的機器學習核心(MLC)。這些產品很容易通過后綴中的 X 來識別(例如,LSM6DS
    發表于 09-08 06:50

    決策樹的介紹

    關于決策樹的介紹,是一些很基礎的介紹,不過是英文介紹。
    發表于 09-18 14:55 ?0次下載

    決策樹構建設計并用Graphviz實現決策樹的可視化

    最近打算系統學習機器學習的基礎算法,避免眼高手低,決定把常用的機器學習基礎算法都實現一遍以便加深印象。本文為這系列博客的第一篇,關于
    發表于 11-15 13:10 ?1.5w次閱讀
    <b class='flag-5'>決策樹</b>的<b class='flag-5'>構建</b>設計并用Graphviz實現<b class='flag-5'>決策樹</b>的可視化

    機器學習決策樹--python

    今天,我們介紹機器學習里比較常用的一種分類算法,決策樹決策樹是對人類認知識別的一種模擬,給你一堆看似雜亂無章的數據,如何用盡可能少的特征,對這些數據進行有效的分類。
    發表于 11-16 01:50 ?1639次閱讀

    決策樹和隨機森林模型

    我們知道決策樹容易過擬合。換句話說,單個決策樹可以很好地找到特定問題的解決方案,但如果應用于以前從未見過的問題則非常糟糕。俗話說三個臭皮匠賽過諸葛亮,隨機森林就利用了多個決策樹,來應對多種不同場景。
    的頭像 發表于 04-19 14:38 ?8049次閱讀
    <b class='flag-5'>決策樹</b>和隨機森林模型

    決策樹的構成要素及算法

    決策樹是一種解決分類問題的算法,決策樹算法采用樹形結構,使用層層推理來實現最終的分類。
    發表于 08-27 09:52 ?4421次閱讀

    決策樹的基本概念/學習步驟/算法/優缺點

    本文將介紹決策樹的基本概念、決策樹學習的3個步驟、3種典型的決策樹算法、決策樹的10個優缺點。
    發表于 01-27 10:03 ?2712次閱讀
    <b class='flag-5'>決策樹</b>的基本概念/<b class='flag-5'>學習</b>步驟/算法/優缺點

    什么是決策樹模型,決策樹模型的繪制方法

    決策樹是一種解決分類問題的算法,本文將介紹什么是決策樹模型,常見的用途,以及如何使用“億圖圖示”軟件繪制決策樹模型。
    發表于 02-18 10:12 ?1.3w次閱讀
    什么是<b class='flag-5'>決策樹</b>模型,<b class='flag-5'>決策樹</b>模型的繪制方法

    決策樹的結構/優缺點/生成

    決策樹(DecisionTree)是機器學習中一種常見的算法,它的思想非常樸素,就像我們平時利用選擇做決策的過程。決策樹是一種基本的分類與回
    發表于 03-04 10:11 ?8387次閱讀

    大數據—決策樹

    大數據————決策樹(decision tree) 決策樹(decision tree):是一種基本的分類與回歸方法,主要討論分類的決策樹。 在分類問題中,表示基于特征對實例進行分類的過程,可以
    的頭像 發表于 10-20 10:01 ?1275次閱讀
    百家乐怎样玩的| 岑巩县| 大发888真人网址| 大发888官方 3000| 大发888娱乐场大发888娱乐场| 全讯网导航| 大发888怎么找| 新塘太阳城巧克力| 大发888促销活动| 足球博彩网| 博e百| 百家乐官网赌牌技巧| 535娱乐城下载| 师宗县| 玩百家乐官网五湖四海娱乐城| 百家乐官网赌博彩| 成都百家乐官网牌具| 百家乐筹码多少钱| 如何看百家乐的玩法技巧和规则| 中骏百家乐的玩法技巧和规则| 全讯网六仔开奖| 德州扑克 盲注| 邮箱| 百家乐官网的薇笑打法| 百家乐官网网上投注作弊| 最新百家乐官网的玩法技巧和规则| 百家乐官网平注秘籍| 百家乐平台注册送现金| 威尼斯人娱乐城老品牌| 网络娱乐| 金榜百家乐官网娱乐城| 百家乐开户代理| 赌场百家乐的玩法技巧和规则| 大发888 com| 百家乐官网作弊演示| 全讯网百家乐官网的玩法技巧和规则| 百家乐怎么刷反水| 威尼斯人娱乐城官方| 百家乐官网乐翻天| 百家乐玩的技巧| 恒宝国际|