日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

机器学习_决策树_ID3算法_C4.5算法_CART算法及各个算法Python实现

發布時間:2024/7/5 python 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 机器学习_决策树_ID3算法_C4.5算法_CART算法及各个算法Python实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

下面的有些敘述基于我個人理解, 可能與專業書籍描述不同, 但是最終都是表達同一個意思, 如果有不同意見的小伙伴, 請在評論區留言, 我不勝感激.

參考:

周志華-機器學習

https://blog.csdn.net/xiaohukun/article/details/78112917

https://blog.csdn.net/fuqiuai/article/details/79456971

決策樹簡介

1. 問題背景

常規方式對樣本進行分類, 會導致很大的性能問題, 樣本需要不斷重復檢測每一項屬性(屬性之間還不能存在相關性), 例如: 人的體重由[年齡, 身高] 決定, 當獲得一組樣本 [20, 178], 可能我們會先將該數據歸到20歲的階段中, 然后判斷身高, 最后判斷體重, 我們也有可能先使用身高, 然后使用年齡, 最后判斷體重, 排列組合的方式得出預測值, 這種毫無準則的選擇判斷會導致很大的計算量; 然而決策樹使用**信息增益(當前屬性對樣本的貢獻率) **, 根據信息增益從大到小選用對應的屬性進行判斷, 有針對性的選擇可以有效地避免無用的計算, 通過選用合適的樣本屬性按照特定的規則進行判斷, 對樣本準確的分類, 現在遇到的問題就是如何構建一棵決策樹, 構建出來的決策樹還能準確預測結果, 下面將針對決策樹定義, 信息量, 建立決策樹需要遵守的規則, 優化等問題來講解.

2. 決策樹定義

決策樹是基于樹結構進行決策, 一棵決策樹包含一個Root根節點(里面包含所有測試集, 測試集從Root處出發, 按照一定的決策方式, 不同的決策將導致每個樣本最終擁有不同的預測結果), 以及若干內部節點和葉子節點, 葉子節點對應最終的決策結果, 每一個內部節點都是一個屬性測試, 從Root到葉子節點的路徑就是一個樣本的決策過程, 當樣本到達葉子節點的時候就是樣本的預測結果.
決策樹如下圖:
Root: 包含所有的樣本集
DECISION: 決策方式
Result: 決策結果

構造決策樹

1. 問題背景

構建決策樹需要有一個構建規則, 不同的構建規則將導致預測結果的不同, 當然, 不同的數據需要使用不同的構建規則, 這樣才能最好地預測出結果, 下面將介紹3中不同的構建規則: 信息增益, 信息增益率, 基尼指數

2. 信息熵

信息熵是度量樣本屬性對最終預測結果的影響程度, 當某一屬性的熵在正常情況下比其他屬性的熵要大的時候, 我們就可以先選用該屬性優先對樣本進行分類(越是影響大的屬性越容易影響預測結果, 越容易預測正確).
信息熵方程定義:

pk: 屬性在樣例中的比例

使用例子說明:
如下圖片, 使用age, income, student, credit屬性來判斷一個人能否買電腦

使用buys_computer計算總的信息熵:
buys_computer包含2個子集 {yes, no}, 正例比例: 9/14, 反例比例: 5/14, 最終得到 Info(D)

同理計算age:
age包含3個子集 {youth, middle_aged, senior}, 分別計算youth, middle_aged, senior各自相對于正反例的比例值, 道理同上, 然后得到 Info_youth(D), Info_middle_aged(D), Info_senior(D).
由于不同子集樣本相對于age數目不同, 所以:

Info_age(D) = youth_權重*Info_youth + middle_aged_權重*Info_middle_aged(D) + senior_權重*Info_senior(D)

最終age的信息熵計算結果:

3. 信息增益(ID3算法)

信息增益: 樣本利用某一屬性分類之后得到多少樣本, 例如: 樣本使用age屬性分類, Gain(D, age) = 總的熵(即Info(D)) - Info_age(D)
信息增益方程定義:

V代表屬性種類; D^V代表每種屬性對應的樣本數目;
Ent(D)代表Info(D); |D^v|/|D| 就是屬性數目在樣本中權重.
下面直接計算Gain(D, age), 計算age相對于總樣本D的信息增益
在前面信息熵的計算中, 我們已經得出Info(D), Info_age(D), 按照公式只需做差

同理我們可以計算出: Gain(income) = 0.029, Gain(student) = 0.151, Gain(credit_rating)=0.048
因為Gain(age)最大, 就可以得出age對樣本的影響程度最高, 因此構建決策樹的時候, 選用age作為Root, 得出如下決策樹:
注: 在離散型數據下, 使用過的屬性就不再使用, 因為該屬性對樣本的影響在之前已經計算過, 再次使用會導致結果錯誤

這只是決策樹第一層樹的建立, 建立第二層的時候, 同理, 用youth對應的分類樣本來說: 我們接下來從 income, student, credit來進行決策, 在當前樣本正返例比例的基礎上分別計算Info(D’), Info_income(D’), Info_student(D’), Info_credit(D’), 使用Info(D’) - Info_XXX(D’)計算信息增益, 然后從3個屬性中選出信息增益最大的屬性作為下一個節點, 根據該節點的子集進行分類決策. 整個過程是一個遞歸的過程, 不斷重復, 直到如下條件時終止:

  • 給定結點的所有樣本屬于同一類(該樣本中全是正例或者反例)
  • 沒有剩余屬性可以用來進一步劃分樣本(例如: 假如樣本經過一系列劃分后, 現在只有income, class兩個標簽, 只有income一個屬性, 沒有多余的屬性進行下一步劃分, 劃分停止), 在樣本中可能存在一部分反例, 一部分正例, 此時使用多數表決, 根據正返例個數決定當前葉子節點的類別.

詳細算法流程如下:

算法文字描述:

  • 樹以代表訓練樣本的單個結點開始(步驟1)。
  • 如果樣本都在同一個類,則該結點成為樹葉,并用該類標號(步驟2 和3)。
  • 否則,算法使用稱為信息增益的基于熵的度量作為啟發信息,選擇能夠最好地將樣本分類的屬性(步驟6)。該屬性成為該結點的“測試”或“判定”屬性(步驟7)。在算法的該版本中,所有的屬性都是分類的,即離散值。連續屬性必須離散化。
  • 對測試屬性的每個已知的值,創建一個分枝,并據此劃分樣本(步驟8-10)。
  • 算法使用同樣的過程,遞歸地形成每個劃分上的樣本判定樹。一旦一個屬性出現在一個結點上,就不必該結點的任何后代上考慮它(步驟13)

注: 上面的決策樹建立方式是ID3算法, 這種算法很容易受信息增益的影響, 當某一屬性對應的樣本分布過于分散, 就比如使用樣本id作為屬性, 那么計算出來的Info_id(D)就會非常大, 對結果造成很大的影響, 下面將介紹信息增益率來減小這種影響
Python實現ID3:

from sklearn.feature_extraction import DictVectorizer import csv from sklearn import tree from sklearn import preprocessing from sklearn.externals.six import StringIO# Read in the csv file and put features into list of dict and list of class label allElectronicsData = open(r'/home/zhoumiao/MachineLearning/01decisiontree/AllElectronics.csv', 'rb') #獲取csv文件中內容 reader = csv.reader(allElectronicsData) headers = reader.next()print(headers)featureList = [] labelList = []#將每一行數據變為字典的形式存入列表中 #例如:[{age:youth, income:high...}, {...}, ...] #直接使用庫將這種格式的數據轉變為0, 1格式 for row in reader:#獲取每一行數據最后的標簽labelList.append(row[len(row)-1])rowDict = {}for i in range(1, len(row)-1):rowDict[headers[i]] = row[i]featureList.append(rowDict)print(featureList)# Vetorize features #使用本身的庫進行轉換,轉變的只是每行對應0 1,并不滿足sklearn需要的格式 vec = DictVectorizer() dummyX = vec.fit_transform(featureList) .toarray() print("dummyX: " + str(dummyX))print(vec.get_feature_names())print("labelList: " + str(labelList))# vectorize class labels #針對每行最后的結果再進一步轉換 lb = preprocessing.LabelBinarizer() dummyY = lb.fit_transform(labelList) print("dummyY: " + str(dummyY))# Using decision tree for classification # clf = tree.DecisionTreeClassifier() #設置分類器,設置不同的參數,使用不同的算法 clf = tree.DecisionTreeClassifier(criterion='entropy') #建模,傳入x,y矩陣 clf = clf.fit(dummyX, dummyY) print("clf: " + str(clf))# Visualize model #將決策樹clf轉變為原始信息,然后存入dot文件中 with open("allElectronicInformationGainOri.dot", 'w') as f:f = tree.export_graphviz(clf, feature_names=vec.get_feature_names(), out_file=f)oneRowX = dummyX[0, :] print("oneRowX: " + str(oneRowX))#修改原始數據,根據模型進行預測 newRowX = oneRowX newRowX[0] = 1 newRowX[2] = 0 print("newRowX: " + str(newRowX))#獲得預測結果 predictedY = clf.predict(newRowX) print("predictedY: " + str(predictedY))

4. 信息增益率(C4.5算法)

相比于ID3算法來說, C4.5算法使用不同的Gain計算方式(計算角度不同, 弱化無關因素對結果預測的影響), 具體Gain計算如下:
信息增益率:

使用age對上面的公式進行解釋:
Gain(D, age) = Info_age(D);
IV(a) = -5/14log(4/14) - 4/14log(4/14) - 5/14log(5/14)
Gain_ratio(D,age) = Info_age(D)/IV(a)
當屬性子集越多, 則IV(a)就會越大, 得到的Gain_ratio就會越小, 從而達到: 避免因為屬性子集過多而導致信息增長過大影響判斷結果.
注:增長率對子集過少的屬性也會有偏好, 就比如id與age, 增長率對age將會表現出偏向, 從而使用age作為節點, 而不是id, 避免結果的預測錯誤.

選用屬性方式:

  • 計算出所有屬性的Gain_ratio, 以及平均Gain_ratio
  • 然后找出高于平均水平的屬性
  • 再從步驟2中找出Gain_ratio最高的屬性作為劃分依據, 隨后的操作就重復即可.
    使用C4.5算法與ID3算法的區別就是選取的Gain不同, 其他操作都是一樣的, 最后的遞歸終止條件與ID3是相同的.
  • 算法描述:

    while (當前節點”不純“) (1)計算當前節點的類別信息熵Info(D) (以類別取值計算) (2)計算當前節點各個屬性的信息熵Info(Ai) (以屬性取值下的類別取值計算) (3)計算各個屬性的信息增益Gain(Ai)=Info(D)-Info(Ai) (4)計算各個屬性的分類信息度量H(Ai) (以屬性取值計算) (5)計算各個屬性的信息增益率IGR(Ai)=Gain(Ai)/H(Ai) end while 當前節點設置為葉子節點

    代碼如下:

    # encoding=utf-8import cv2 import time import numpy as np import pandas as pdfrom sklearn.cross_validation import train_test_split from sklearn.metrics import accuracy_score# 二值化 def binaryzation(img):cv_img = img.astype(np.uint8)cv2.threshold(cv_img,50,1,cv2.THRESH_BINARY_INV,cv_img)return cv_imgdef binaryzation_features(trainset):features = []for img in trainset:img = np.reshape(img,(28,28))cv_img = img.astype(np.uint8)img_b = binaryzation(cv_img)# hog_feature = np.transpose(hog_feature)features.append(img_b)features = np.array(features)features = np.reshape(features,(-1,feature_len))return featuresclass Tree(object):def __init__(self,node_type,Class = None, feature = None):self.node_type = node_type # 節點類型(internal或leaf)self.dict = {} # dict的鍵表示特征Ag的可能值ai,值表示根據ai得到的子樹 self.Class = Class # 葉節點表示的類,若是內部節點則為noneself.feature = feature # 表示當前的樹即將由第feature個特征劃分(即第feature特征是使得當前樹中信息增益最大的特征)def add_tree(self,key,tree):self.dict[key] = treedef predict(self,features): if self.node_type == 'leaf' or (features[self.feature] not in self.dict):return self.Classtree = self.dict.get(features[self.feature])return tree.predict(features)# 計算數據集x的經驗熵H(x) def calc_ent(x):x_value_list = set([x[i] for i in range(x.shape[0])])ent = 0.0for x_value in x_value_list:p = float(x[x == x_value].shape[0]) / x.shape[0]logp = np.log2(p)ent -= p * logpreturn ent# 計算條件熵H(y/x) def calc_condition_ent(x, y):x_value_list = set([x[i] for i in range(x.shape[0])])ent = 0.0for x_value in x_value_list:sub_y = y[x == x_value]temp_ent = calc_ent(sub_y)ent += (float(sub_y.shape[0]) / y.shape[0]) * temp_entreturn ent# 計算信息增益 def calc_ent_grap(x,y):base_ent = calc_ent(y)condition_ent = calc_condition_ent(x, y)ent_grap = base_ent - condition_entreturn ent_grap# C4.5算法 def recurse_train(train_set,train_label,features):LEAF = 'leaf'INTERNAL = 'internal'# 步驟1——如果訓練集train_set中的所有實例都屬于同一類Cklabel_set = set(train_label)if len(label_set) == 1:return Tree(LEAF,Class = label_set.pop())# 步驟2——如果特征集features為空class_len = [(i,len(list(filter(lambda x:x==i,train_label)))) for i in range(class_num)] # 計算每一個類出現的個數(max_class,max_len) = max(class_len,key = lambda x:x[1])if len(features) == 0:return Tree(LEAF,Class = max_class)# 步驟3——計算信息增益,并選擇信息增益最大的特征max_feature = 0max_gda = 0D = train_labelfor feature in features:# print(type(train_set))A = np.array(train_set[:,feature].flat) # 選擇訓練集中的第feature列(即第feature個特征)gda = calc_ent_grap(A,D)if calc_ent(A) != 0: ####### 計算信息增益比,這是與ID3算法唯一的不同gda /= calc_ent(A)if gda > max_gda:max_gda,max_feature = gda,feature# 步驟4——信息增益小于閾值if max_gda < epsilon:return Tree(LEAF,Class = max_class)# 步驟5——構建非空子集sub_features = list(filter(lambda x:x!=max_feature,features))tree = Tree(INTERNAL,feature=max_feature)max_feature_col = np.array(train_set[:,max_feature].flat)feature_value_list = set([max_feature_col[i] for i in range(max_feature_col.shape[0])]) # 保存信息增益最大的特征可能的取值 (shape[0]表示計算行數)for feature_value in feature_value_list:index = []for i in range(len(train_label)):if train_set[i][max_feature] == feature_value:index.append(i)sub_train_set = train_set[index]sub_train_label = train_label[index]sub_tree = recurse_train(sub_train_set,sub_train_label,sub_features)tree.add_tree(feature_value,sub_tree)return treedef train(train_set,train_label,features):return recurse_train(train_set,train_label,features)def predict(test_set,tree):result = []for features in test_set:tmp_predict = tree.predict(features)result.append(tmp_predict)return np.array(result)class_num = 10 # MINST數據集有10種labels,分別是“0,1,2,3,4,5,6,7,8,9” feature_len = 784 # MINST數據集每個image有28*28=784個特征(pixels) epsilon = 0.001 # 設定閾值if __name__ == '__main__':print("Start read data...")time_1 = time.time()raw_data = pd.read_csv('../data/train.csv', header=0) # 讀取csv數據data = raw_data.valuesimgs = data[::, 1::]features = binaryzation_features(imgs) # 圖片二值化(很重要,不然預測準確率很低)labels = data[::, 0]# 避免過擬合,采用交叉驗證,隨機選取33%數據作為測試集,剩余為訓練集train_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size=0.33, random_state=0)time_2 = time.time()print('read data cost %f seconds' % (time_2 - time_1))# 通過C4.5算法生成決策樹print('Start training...')tree = train(train_features,train_labels,list(range(feature_len)))time_3 = time.time()print('training cost %f seconds' % (time_3 - time_2))print('Start predicting...')test_predict = predict(test_features,tree)time_4 = time.time()print('predicting cost %f seconds' % (time_4 - time_3))# print("預測的結果為:")# print(test_predict)for i in range(len(test_predict)):if test_predict[i] == None:test_predict[i] = epsilonscore = accuracy_score(test_labels, test_predict)print("The accruacy score is %f" % score)

    5. 基尼指數(CART決策樹)

    CART決策樹使用基尼指數(所謂的信息熵)作為判斷屬性是否可以作為劃分依據,
    特點:

  • CART 既能是分類樹,又能是回歸樹.
  • 當CART是分類樹時,采用GINI值作為節點分裂的依據;當CART是回歸樹時,采用樣本的最小方差作為節點分裂的依據.
  • 基尼指數計算:


    Gini(D)描述從樣本中隨機抽取兩個樣本, 不一樣概率的大小, Gini越大說明該屬性的樣本越少, 因此該屬性對樣本的總影響就越小.
    a屬性對樣本預測結果的影響, 影響越大,Gini_index(D, a)值越小,反之,則GINI值越大.
    其中,pk表示節點中屬于類k的概率.
    下面使用一個例子說明:
    按照職業屬性劃分, 預測是否結婚

    預測是否結婚:
    Gini(married, occupation) = 3/7[1? (2/3)^2 ? (1/3)^2] + 4/7[1 ? (3/4)^2 ? (1/4)^2]=0.4
    同理可計算看電視時間, 年齡對是否結婚的Gini

    CART決策樹算法流程:
    每次劃分的時候, 需要選擇基尼指數最小的屬性作為最優劃分屬性

    Python使用sklearn代碼實現CRAT:

    from sklearn import datasets from sklearn import tree from sklearn.externals.six import StringIO import pydot# 加載Iris數據集 iris = datasets.load_iris() #不傳入參數, 使用默認算法CRAT實現分類 clf = tree.DecisionTreeClassifier() clf = clf.fit(iris.data, iris.target)dot_data = StringIO() tree.export_graphviz(clf, out_file=dot_data, feature_names=iris.feature_names, class_names=iris.target_names, filled=True, rounded=True, special_characters=True) # tree.export_graphviz(clf, out_file=r"tree.dot") #把這行代碼放開可以生成決策樹的文件 (graph,) = pydot.graph_from_dot_data(dot_data.getvalue()) graph.write_png('iris.png')

    總結:

    三種算法各有自己的Grain計算方式, 構建樹的過程, 區別就在于Grain計算的不同, 最優屬性選擇的不同, 剩下都是相同的.

    如果有什么問題, 請在下方留言, 感覺不錯的話, 請為我點個贊, O(∩_∩)O謝謝

    總結

    以上是生活随笔為你收集整理的机器学习_决策树_ID3算法_C4.5算法_CART算法及各个算法Python实现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。