h. 為了進行資料集的測試,需要知道每個測試集分類過後的標籤,因此使用find()方法,遞迴的找到每個枝杈上的葉子節點,葉子節點的value值就是當前的分類情況。因為在建立樹的時候已經將每個葉子節點的dim設定為了-1,因此只需要判斷tree.getdim是否為-1就可以知道是否為葉子節點,如果不是則分別在左右子樹上找,直到找到葉子節點:
def find(node, data):
if node.getdim() == -1:
return node.getvalue()
else:
reducedfeatvec1 =
reducedfeatvec1 = data[:node.getdim()]
reducedfeatvec1.extend(data[node.getdim() + 1:])
if data[node.getdim()] > node.getvalue():
return find(node.getleft(), reducedfeatvec1)
elif data[node.getdim()] <= node.getvalue():
return find(node.getright(), reducedfeatvec1)
i. 找到了每個測試集的分類之後就可以進行正確率的判斷,如果**的類和真實標籤相同則+1:
def classify(dataset, tree):
cout = 0
for example in dataset:
a = find(tree, example)
b = example[-1]
if a == b:
cout += 1
return cout
j. 通過預剪枝的方法建造一棵樹,首先判斷停止的條件與上面的相同,傳入的引數多了乙個測試集。用count1和count2分別表示在這個特徵上不分開和分開的正確的個數。首先獲得當前節點的value值,就是通過投票而獲得的當前節點的類標籤,通過這個值和真實標籤作比較。之後對訓練集在這個節點處進行劃分,有得到乙個劃分後的正確率,如果前者大,則停止劃分,將其的dim設定為-1,如果前者小則繼續分叉,在其左子樹和右子樹上進行同樣的操作:
# 預剪枝
def precutting(dataset, tree, testdata):
count1 = 0
count2 = 0
classlist = [example[-1] for example in dataset]
if (classlist.count(classlist[0]) == len(classlist)):
tree.setvalue(classlist[0])
return tree.setdim(-1)
if (len(dataset[0]) == 1):
tree.setvalue(majoritycnt(classlist))
return tree.setdim(-1)
bestvalue1 = tree.getvalue()
for dt in testdata:
if (dt[-1] == bestvalue1):
count1 += 1
bestdim, bestvalue = choosebestbranch(dataset)
tree.setdim(bestdim)
tree.setvalue(bestvalue)
lefttree = treenode()
righttree = treenode()
leftdata, rightdata = splitcontinuousdataset(dataset, bestdim, bestvalue)
lefttdata, righttdata = splitcontinuousdataset(testdata, bestdim, bestvalue)
# left
if (len(lefttdata) > 0 and len(lefttdata[0]) > 0):
classlistleft = [example[-1] for example in lefttdata]
leftvalue = majoritycnt(classlistleft)
for dt in lefttdata:
if (dt[-1] == leftvalue):
count2 += 1
# right
if (len(righttdata) > 0 and len(righttdata[0]) > 0):
classlistright = [example[-1] for example in righttdata]
rightvalue = majoritycnt(classlistright)
for dt in righttdata:
if (dt[-1] == rightvalue):
count2 += 1
if (count1 < count2):
if (len(leftdata) > 0):
precutting(leftdata, lefttree, lefttdata)
if (len(rightdata) > 0):
precutting(rightdata, righttree, righttdata)
tree.setleft(lefttree)
tree.setright(righttree)
k. 後剪枝操作,首先是用create方法生成乙個樹,然後進行後剪枝。從底層節點向上開始考慮,如果該節點的dim值為-1 則返回,之後對上一層進行正確率的判斷。在找葉子節點的同時,也將測試集分成了兩個部分。然後計算這個節點分支後的正確率和不讓這個節點分支的正確率,如果前者的正確率大,則將該節點的dim設定為-1,也就是直接把這個節點變成了葉子:
def posttree(tree, testdata):
# 找到葉子節點
if (tree.getdim() == -1):
return
else:
lefttest, righttest = splitcontinuousdataset(testdata, tree.getdim(), tree.getvalue())
if len(lefttest) > 0:
posttree(tree.getright(), lefttest)
if len(righttest) > 0:
posttree(tree.getright(), righttest)
cout1 = 0
cout2 = 0
classlist1 = [example[-1] for example in testdata]
value = majoritycnt(classlist1)
for ex in testdata:
if (ex[-1] == value):
cout1 += 1
# left
if (len(lefttest) > 0 and len(lefttest[0]) > 0):
classlistleft = [example[-1] for example in lefttest]
leftvalue = majoritycnt(classlistleft)
for dt in lefttest:
if (dt[-1] == leftvalue):
cout2 += 1
# right
if (len(righttest) > 0 and len(righttest[0]) > 0):
classlistright = [example[-1] for example in righttest]
leftvalue = majoritycnt(classlistright)
for dt in righttest:
if (dt[-1] == righttest):
cout2 += 1
if (cout1 < cout2):
return tree.setdim(-1)
l. 進行5折交叉驗證。首先使用了random.shuffle方法,將資料集打亂順序。之後從0-30,30-60,60-90,90-120,120-150,分別作為測試集,用remove方法的到訓練集。分別生成樹,比較其中的正確率:
random.shuffle(dataset)
train1 =dataset[:121]
test1 =dataset[121:]
train2 =dataset[31:]
test2 =dataset[:31]
test3=
train3 =dataset[:]
test4=
train4=dataset[:]
test5=
train5=dataset[:]
for i in range(30,60):
train3.remove(dataset[i])
print(len(dataset))
for i in range(60,90):
train4.remove(dataset[i])
for i in range(90,120):
train5.remove(dataset[i])、
實驗結果截圖:
一共測試了四次次,其中第一行為正常構造決策樹,第二行為使用後剪枝,第三行為使用預剪枝分別得到的正確的樣本個數。總的測試集大小為30。倒數第二行為在測試集和訓練集上測試的結果,發現訓練集的結果高於測試集。(第一行為訓練集本身,第二三行為測試集)
實驗結果分析:
在原來樹的準確率和後剪枝後和預剪枝的準確率上來看(第一行為正常構建的樹,第二行為後剪枝後,第三行為預剪枝構造樹):這棵樹存在過擬合的情況。通過5折交叉驗證可以使這棵樹的準確率為基本為100%
python實現決策樹
決策樹是乙個 模型 他代表的是物件屬性與物件值之間的一種對映關係。樹中每個節點表示某個物件,而每個分叉路徑則代表某個可能的屬性值,而每個葉節點則對應從根節點到該葉節點所經歷的路徑所表示的物件的值。詳細關於決策樹的討論,請自行google。一 找到最優分割位置 1 針對樣本資料,需要在其不同的維度 d...
PHP樹 不需要遞迴的實現方法
php樹 不需要遞迴的實現方法 建立父節點樹形陣列 引數 ar 陣列,鄰接列表方式組織的資料 id 陣列中作為主鍵的下標或關聯鍵名 pid 陣列中作為父鍵的下標或關聯鍵名 返回 多維陣列 function find parent ar,id id pid pid return t 建立子節點樹形陣列...
決策樹演算法 python實現
定義 資訊增益 再劃分資料之前之後資訊發生的變化。香濃熵 簡稱熵 集合資訊的度量方式,熵是資訊的期望值。其實決策樹主要就是選擇最優劃分屬性對給定集合進行劃分,隨著花粉的不斷進行,我們希望最終決策樹所包含的樣本盡量屬於同一類別,即結點的 純度 越來越高。資訊增益的計算 1.資訊熵的計算ent d 越小...