机器学习基础——实现基本的决策树

来源:互联网 发布:网络异常 请重新登录 编辑:程序博客网 时间:2024/06/08 07:07

一、决策树基本流程

 决策树是常见的机器学习方法。我在学习周志华的机器学习的时候,用python实现了最基础的ID3算法,其基本思想是:
基于信息论中的信息增益理论,首先找出判断样本的最高的信息增益的属性(或者说特征),然后依次对按该属性划分成的子集
进行同样的选择信息增益最大的属性并进行划分的过程。这是一个典型的(divide-conquer)的过程。

二、最基本的决策树实现

下面,通过周志华《机器学习》(也叫西瓜书)第四章的例子,我用python实现了基于pandas的DataFrame的数据结构的数据来进行的决策树的实现(属性都是离散属性)。对
连续属性或更一般性的情况,可以调用sklearn的决策树包来做,这块放在最后。
样本如下:
# 决策树# 习题4.3 实现基于信息熵进行划分选择的决策树算法,并为表4.3中数据# 生成一颗决策树# 表4.3既有离散属性,也有连续属性。# _*_ coding:UTF-8 _*_import pandas as pdimport numpy as npimport osfrom math import log2# 离散的特征的完成了,连续的我用sklearn可以做,就不在此处写了def Entrop(data):    entropy = dict()    for i in data.keys():        good = data[i].count('是')        bad = data[i].count('否')        length = len(data[i])        p1 = good / length        p2 = bad / length        if p1 == 0.0 or p2 == 0.0:            entropy[i] = 0        else:            entropy[i] = -(p1 * log2(p1) + p2 * log2(p2))    return entropydef DecisionTree(entropy, data, MaxKey, threshold, category):    for i in entropy:        sub_data = data[data[MaxKey] == i]  # sub_data为子集合        subs_entropy = entropy[i]  # subs_entropy是信息熵        sizes = sub_data.count(0)[0]  # 这个子集合的样本数量        if subs_entropy >= threshold:            gains = dict()  # 信息增益            data_sample = dict()            Ent = dict()  # 信息熵            for j in category:                data_sample[j] = sub_data['好瓜'].groupby(sub_data[j]).sum()                nn = len(data_sample[j])                he = 0                for m in range(nn):                    good = data_sample[j][m].count('是')                    bad = data_sample[j][m].count('否')                    length = len(data_sample[j][m])                    p1 = good / length                    p2 = bad / length                    if good == 0.0 or bad == 0.0 or length == 0:                        Ent[j] = 0                    else:                        Ent[j] = -(p1 * log2(p1) + p2 * log2(p2))                    he += (length * Ent[j]) / sizes                gains[j] = subs_entropy - he            if len(gains) > 0:                maxKey = max(gains.items(), key=lambda x: x[1])[0]                entropys = Entrop(data_sample[maxKey])                category.pop(maxKey)                print('{0}下面的第一分类是{1}'.format(i, maxKey))                DecisionTree(entropys, sub_data, maxKey, threshold, category)            else:                highest_class = max(sub_data['好瓜'].values)                if highest_class == '否':                    print('{0}下面的瓜都是坏瓜'.format(i))                else:                    print('{0}下面的瓜都是好瓜'.format(i))        else:            highest_class = max(sub_data['好瓜'].values)            if highest_class == '否':                print('{0}下面的瓜都是坏瓜'.format(i))            else:                print('{0}下面的瓜都是好瓜'.format(i))def main():    """    主函数    """    dataset_path = './datasets'  # 数据集路径    filename = 'watermalon_simple.xlsx'  # 文件名称    dataset_filepath = os.path.join(dataset_path, filename)  # 数据集文件路径    # step 1:读取数据    data = pd.read_excel(dataset_filepath) # 获取数据    header = data.columns # 获取列名    sums = data.count()[0]  # 样本个数    # print(type(header))    # print(header[1:])    # step 2:取出6个特征中每个特征的子集    category = dict()    for i in header[1:-1]:        category[i] = set(data[i])    # step 3:计算信息熵    # 1) 初始样本的信息熵    Ent = dict()    number = data['好瓜'].groupby(data['好瓜']).sum()    p1 = len(number['是']) / sums  # 好瓜的个数/总共个数    p2 = len(number['否']) / sums  # 坏瓜的个数/总共个数    Ent["总"] = -(p1*log2(p1) + p2*log2(p2))    # 2) 计算每个属性的信息增益    Gain = dict()    data_sample = dict()    for i in category:        data_sample[i] = data['好瓜'].groupby(data[i]).sum()        # 每一个属性有几种维度 如色泽有 青绿、乌黑、浅白三种,则n = 3        n = category[i]        # print(len(data_sample[i]))        # print(data_sample[i])        he = 0        for j in range(len(n)):            good = data_sample[i][j].count('是')            bad = data_sample[i][j].count('否')            length = len(data_sample[i][j])            p1 = good / length            p2 = bad / length            if p1 == 0.0 or p2 == 0.0:                Ent[j] = 0            else:                Ent[j] = -(p1 * log2(p1) + p2 * log2(p2))            he += (length * Ent[j])/sums        Gain[i] = Ent['总'] - he    # 3) 找到value最大对应的key 即找到按增益准则划分的分类最佳情况    #    这里的MaxKey是纹理    MaxKey = max(Gain.items(), key=lambda x: x[1])[0]    print('主分类是{}'.format(MaxKey))    # 4) 根据这个情况,分别计算其子分类的信息熵    #    entropy为字典    entropy = Entrop(data_sample[MaxKey])    print(entropy)    # {'清晰': 0.7642045065086203, '稍糊': 0.7219280948873623, '模糊': 0}    # 4.1)接下来的分类不能再用这个分了:即把这个类别扔掉    category.pop(str(MaxKey))    # print(category)    # 5) 对信息熵大于某一阈值(threshold)的情况进行继续划分,如果小于则统一认为是某种情况,不再    #    继续分类。例如:本例对模糊的Ent=0,所以不对模糊类别进行继续划分。    threshold = 0.05    DecisionTree(entropy, data, MaxKey, threshold, category)if __name__ == "__main__":    main()
上面是我的代码,如果有不清楚的地方可以交流。下面贴上用sklearn的代码:

from sklearn import treeimport numpy as npfrom sklearn.feature_extraction import DictVectorizer# from sklearn import preprocessingfrom sklearn.cross_validation import train_test_splitimport xlrdworkbook = xlrd.open_workbook('watermalon_simple.xlsx')booksheet = workbook.sheet_by_name('Sheet1')X = list()Y = list()for row in range(booksheet.nrows):        row_data = []        ll = dict()        # ll = list()        mm = list()        for col in range(1, booksheet.ncols-1):            cel = booksheet.cell(row, col)            val = cel.value            cat = ['色泽', '根蒂', '敲声', '纹理', '触感']            # ll.append(val)            ll[cat[col-1]] = val        for col in range(booksheet.ncols-1,booksheet.ncols):            cel = booksheet.cell(row, col)            val = cel.value            mm.append(val)        print('第{}行读取完毕'.format(row))        X.append(ll)        Y.append(mm)# X = X[1:] #和下面的效果一样,即把第一列删除X.pop(0); Y.pop(0)# print(X)print(X); print(Y)# 1表示好瓜 0表示坏瓜y = [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0]# Vector FeaturedummyY = np.array(y)vec = DictVectorizer()dummyX = vec.fit_transform(X).toarray()#拆分数据x_train, x_test, y_train, y_test = train_test_split(dummyX, dummyY, test_size=0.3)# using desicionTree for classficationclf = tree.DecisionTreeClassifier(criterion="entropy")# 创建一个分类器,entropy决定了用ID3算法clf = clf.fit(x_train, y_train)# print(clf.feature_importances_)answer=clf.predict(x_test)print(u'系统进行测试')# print(x_train)print(answer)print(y_test)# print(np.mean(answer==y_train))# 可视化with open("alalala.dot", "w") as f:     f = tree.export_graphviz(clf, feature_names=vec.get_feature_names(), out_file = f)
用sklearn的方法有很多人已实现过了。所以在此不细说了,大家可以去查阅scikit-learn的api文档查询^.^


1 0