1. 程式人生 > >(參評)機器學習筆記——鳶尾花資料集(KNN、決策樹、樸素貝葉斯分析)

(參評)機器學習筆記——鳶尾花資料集(KNN、決策樹、樸素貝葉斯分析)

最開始選取鳶尾花資料集來了解決策樹模型時,筆者是按照學習報告的形式來寫得,在這裡將以原形式上傳。格式較為繁複,希望讀者可以耐心看完,謝謝大家。

目錄

6.總結

7.問題

1、問題描述

  iris是鳶尾植物,這裡儲存了其萼片和花瓣的長寬,共4個屬性,鳶尾植物分三類。假定現在出現了一株鳶尾植物,如何通過其所具有的特徵來推斷出它屬於三類中的哪一類?這就是機器學習中的分類問題了。該資料集一共包含4個特徵變數,1個類別變數。共有150個樣本,鳶尾有三個亞屬,分別是山鳶尾 (Iris-setosa),變色鳶尾(Iris-versicolor)和維吉尼亞鳶尾(Iris-virginica)。 

2、資料準備與資料預處理

2.1收集資料

  在本次問題過程中,所使用的是一個較經典的資料集,所以在scikit-learn的資料庫中可以找到。也可以在UCI資料集上下載完成。

 

資料集一共分為四個變數,分別為:花萼長度、花萼寬度、花瓣長度、花瓣寬度

2.2劃分資料集

  從上面對樣本集的輸出我們可以看出Iris資料集給出的三種花是按照順序來的,前50個是第0類,51-100是第1類,101~150是第二類,如果我們分訓練集和測試集的時候要把順序打亂。在這裡我們選取120個為訓練集,30個為測試集。為實現隨機性,選取三個部分的每部分的最後十組資料作為測試集元素。

train_data = np.concatenate((iris.data[0:40, :], iris.data[50:90, :], iris.data[100:140, :]), axis = 0)  #訓練集  

train_target = np.concatenate((iris.target[0:40], iris.target[50:90], iris.target[100:140]), axis = 0)  #訓練集樣本類別  

test_data = np.concatenate((iris.data[40:50, :], iris.data[90:100, :], iris.data[140:150, :]), axis = 0)  #測試集  

test_target = np.concatenate((iris.target[40:50], iris.target[90:100], iris.target[140:150]), axis = 0) #測試集樣本類別  

3.資料視覺化

  由於花瓣寬度變化很小,將其省略後根據前三維資料畫出散點圖,如下所示:

 

4、模型基本原理與演算法實現

4.1演算法基本原理及主程式

  k近鄰法是一種基本的多分類和迴歸的演算法,給定一個訓練資料集,對新的輸入例項,在資料集中找到與該例項最近鄰的k個例項,這k個例項的多數屬於某個類,就把該輸入例項分為這個類。kNN的三要素是k,距離度量和分類決策規則。

第一步,計算輸入例項和資料集各個資料的歐氏距離。第二步,將計算的距離按照從小到大排序,統計前k個數據的類別,這裡假設k為3,則前3個距離最近的資料類為AAB。 第三步,將輸入例項判斷為頻率最高的類,本例中A的頻率最高(為2),即輸入例項是A類資料。

以下為主程式段:

def kNN(x, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    distance1 = tile(x, (dataSetSize,1)) - dataSet #歐氏距離計算開始
    distance2 = distance1 ** 2 #每個元素平方
    distance3 = distance2.sum(axis=1) #矩陣每行相加
    distance4 = distance3 ** 0.5 #歐氏距離計算結束
    sortedIndex = distance4.argsort() #返回從小到大排序的索引
    classCount = {}
    for i in range (k): #統計前k個數據類的數量
        label = labels[sortedIndex[i]]
        classCount[label] = classCount.get(label,0) + 1
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) #從大到小按類別數目排序
    return sortedClassCount[0][0]

4.2決策樹模型演算法及基本原理

  決策樹是一個屬性結構的預測模型,代表物件屬性和物件值之間的一種對映關係。它又節點和有向邊組成,其節點有兩種型別:內節點和葉節點,內部節點表示一個特徵或屬性,葉節點表示一個類。決策樹的學習本質上是從訓練集中歸納出一組分類規則,得到與資料集矛盾較小的決策樹,同時具有很好的泛化能力。決策樹學習的損失函式通常是正則化的極大似然函式,通常採用啟發式方法,近似求解這一最優化問題。

  決策樹學習演算法包含特徵選擇、決策樹生成與決策樹的剪枝。決策樹表示的是一個條件概率分佈,所以深淺不同的決策樹對應著不同複雜程度的概率模型。決策樹的生成對應著模型的區域性選擇(區域性最優),決策樹的剪枝對應著全域性選擇(全域性最優)。決策樹常用的演算法有ID3,C4.5,CART。

  為了計算資訊增益,引入熵的概念,通過計算夏農熵來將資料集劃分不同的類別。

程式段:

def calcShannonEnt(dataSet):
       numEntries = len(dataSet)
    labelCounts = {}
    for featVec in dataSet:
        currentLabel = featVec[-1]
        if currentLabel not in labelCounts.keys(): 
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1
    shannonEnt = 0.0
    for key in labelCounts:
        prob = float(labelCounts[key]) / numEntries
        shannonEnt -= prob * log(prob,2) # 以2為底的對數
    return shannonEnt

  在計算了資訊增益後,應選擇最好的資料集劃分方式,在這裡選擇ID3演算法進而繪製決策樹。

def chooseBestFeatureToSplitByID3(dataSet):#選擇最好的資料集劃分方式
    umFeatures = len(dataSet[0]) - 1 
    baseEntropy = calcShannonEnt(dataSet)
    bestInfoGain = 0.0
    bestFeature = -1
    for i in range(numFeatures):  # 遍歷所有特徵
        infoGain = calcInformationGain(dataSet, baseEntropy, i)     # 計算資訊增益
        if (infoGain > bestInfoGain):  # 選擇最大的資訊增益
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature  
def majorityCnt(classList):# 採用多數表決的方法決定葉結點的分類
    classCount={}
    for vote in classList:                         if vote not in classCount.keys():
            classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) 
    return sortedClassCount[0][0]

def createTree(dataSet,labels):#建立決策樹
    classList = [example[-1] for example in dataSet]
    if classList.count(classList[0]) == len(classList): 
        return classList[0]            
    if len(dataSet[0]) == 1:        
        return majorityCnt(classList)   
    bestFeat = chooseBestFeatureToSplitByID3(dataSet)   
    bestFeatLabel = labels[bestFeat]
    myTree = {bestFeatLabel:{}}         
    del(labels[bestFeat])
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)
    for value in uniqueVals:
        subLabels = labels[:]       
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
    return myTree

4.3樸素貝葉斯演算法及基本原理

  樸素貝葉斯的思想基礎是這樣的:對於給出的待分類項,求解在此項出現的條件下各個類別出現的概率,哪個最大,就認為此待分類項屬於哪個類別。樸素貝葉斯分類的核心演算法如下:


那麼現在的關鍵就是如何計算第3步中的各個條件概率。我們可以這麼:

1、已知分類的待分類項集合,這個集合叫做訓練樣本

2、統計得到在各類別下各個特徵屬性的條件概率估計。

3、如果各個特徵屬性是條件獨立的,則根據貝葉斯定理有如下推導:


因為分母對於所有類別為常數,因為我們只要將分子最大化皆可。又因為各特徵屬性是條件獨立的,所以有:


為樸素貝葉斯的工作流程圖:


 5、測試方法與結果

5.1測試結果

  對150個鳶尾花樣本進行隨機分割後,選取了其中的30個作為測試集,120個作為訓練集,再計算他們的準確率、召回率和F值。結果如下:

  看出準確率在93%,召回率為90%,說明是一次較為成功的訓練。

5.2決策樹測試結果

 

   看出在決策樹訓練的樣本中,30組測試集完全正確,但這有可能是由以下原因造成的:

1、測試集和訓練集數目都太少,在數值上可能並不太符合要求。

2、決策樹本身演算法易出現過擬合的現象,需要注意。

繪製結果如下:


5.3樸素貝葉斯測試結果

  本次作業中關於應用樸素貝葉斯方法進行分類和測試,我是使用了sklearn中自帶的分類器,並應用了其中兩種相關演算法。分別是:多項式樸素貝葉斯和高斯樸素貝葉斯

結果如下:


  可以看出,兩種樸素貝葉斯的相關演算法在此訓練集上都有較好的應用。

6.總結

  通過本次學習,我瞭解到決策樹學習演算法包含特徵選擇、決策樹的生成與剪枝過程。決策樹易於理解和實現,人們在在學習過程中不需要使用者瞭解很多的背景知識,這同時是它的能夠直接體現資料的特點,只要通過解釋後都有能力去理解決策樹所表達的意義,非常直觀。但是從此次實驗的結果可以看出,30個測試樣本全部正確,決策樹演算法非常容易過擬合,可以通過設定節點最少樣本數量和限制決策樹深度來改進。

  而KNN演算法是一種簡單,易於理解,易於實現,無需估計引數,無需訓練的方法,但是它的缺點是計算量較大,因為對每一個待分類的文字都要計算它到全體已知樣本的距離,才能求得它的K個最近鄰點。如需改變其準確率可以通過改變其k值來進行測試,找到最優的分類方法。

  樸素貝葉斯樸素貝葉斯模型發源於古典數學理論,有穩定的分類效率。對缺失資料不太敏感,演算法也比較簡單,常用於文字分類。但是需要知道先驗概率,且先驗概率很多時候取決於假設,假設的模型可以有很多種,因此在某些時候會由於假設的先驗模型的原因導致預測效果不佳。

7.問題

 1、如何解決決策樹中的過擬合問題?

 2、樸素貝葉斯方法“對輸入資料的表達形式很敏感”是什麼意思?

 3、如何最優選擇KNN演算法中的K?

注:本文所使用的為64位系統,Python3.64版本,其中匯入了與scikit-learn相關的資料包例如:DecisionTreeClassifier、sklearn.externals.six、pydot等。

本文部分程式參考:

  CSDN論壇

  Python機器學習基礎教程——人民郵電出版社

  Python程式設計從入門到實踐——人民郵電出版社

  機器學習實戰——人民郵電出版社