(參評)機器學習筆記——鳶尾花資料集(KNN、決策樹、樸素貝葉斯分析)
最開始選取鳶尾花資料集來了解決策樹模型時,筆者是按照學習報告的形式來寫得,在這裡將以原形式上傳。格式較為繁複,希望讀者可以耐心看完,謝謝大家。
目錄
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程式設計從入門到實踐——人民郵電出版社
機器學習實戰——人民郵電出版社