机器学习算法导论代码——decision_tree_base.py

import numpy as np
from machine_learning.lib.tree_node import Node
'''类决策树基类的实现,类其中有4个成员:root,max_depth,get_score,feature_sample_rate
其中:root记录所生成决策树的根节点,由根节点可唯一的表示这颗决策树
max_depth 记录CART算法中决策树模型的深度限制,有构造函数指定
get_score是分值函数的指针,由构造函数传入。传入方差则实现决策树回归问题的CART算法,传入熵则实现决策树分类的CART算法
feature_sample_rate是[0,1]区间的一个数,有构造函数指定,该算法在随机森林中会用到,决策树不需要
'''
class DecisionTreeBase:
    def __init__(self,max_depth,get_score,feature_sample_rate=1.0):
        self.max_depth=max_depth
        self.get_score=get_score
        self.feature_sample_rate=feature_sample_rate

    def split_data(self,j,theta,X,idx):
        idx1,idx2=list(),list()
        for i in idx:
            if X[i][j]<=theta:
                idx1.append(i)
            else:
                idx2.append(i)
        return idx1,idx2

    def get_random_features(self,n):
        shuffled=np.random.permutation(n)
        size=int(self.feature_sample_rate*n)
        return shuffled[:size]

    def find_best_split(self,X,y,idx):
        m,n=X.shape
        best_score,best_j,best_theta=float("inf"),-1,float("inf")
        best_idx1,best_idx2=list(),list()
        selected_j=self.get_random_features(n) #调用get_random_features函数,按比例随机选取一组特征
        for j in selected_j: #遍历所选出的特征
            thetas=set([x[j] for x in X]) #对每一个特征j,对下标在idx中的所有训练数据计算出特征j的不同取值,将其作为备选阈值
            for theta in thetas: # 遍历所有阈值θ
                idx1,idx2=self.split_data(j,theta,X,idx) #调用split函数,按照特征值j是否大于阈值分为两部分,下标分别在idx1和idx2中
                if min(len(idx1),len(idx2))==0: #判断确保分的两部分不是空集
                    continue
                score1,score2=self.get_score(y,idx1),self.get_score(y,idx2) #每一部分用指定的get_scores函数计算其分值
                w=1.0*len(idx1)/len(idx)
                score=w*score1+(1-w)*score2 #计算出的两部分的分值的加权和,以此作为目标函数
                if score<best_score:
                    best_score,best_j,best_theta=score,j,theta
                    best_idx1,best_idx2=idx1,idx2
        return best_j,best_theta,best_idx1,best_idx2,best_score # 返回所有可行划分中目标函数最小的一组划分
    '''X,y分别表示全体训练数据的特征组与标签,idx是一个下标集合。generate_tree函数
    用下表再idx中的训练数据递归生成一颗不超过d的决策树,并返回生成的决策树的根节点'''
    def generate_tree(self,X,y,idx,d):
        r=Node() #生成节点r,作为建立决策树的根节点
        if d==0 or len(idx)==1: #判断深度是否0、1,若是则不继续划分数据,r为叶节点
            r.p=np.average(y[idx],axis=0) #计算下标在idx中的训练数据标签的平均值。并将其作为r的预测值
            return r
        # score表示最优化划分的目标函数值
        j,theta,idx1,idx2,score=self.find_best_split(X,y,idx) #调用find_best_split函数,采用贪心策略来寻找最优数据划分
        current_score=self.get_score(y,idx) #不做数据划分是得到的目标函数值
        if score>=current_score: #如果得出划分比不划分小,说明划分可带来益处
            return r
        r.j,r.theta=j,theta #记录划分信息
        # 递归的生成当前结点的左右儿子节点,分别对应划分出的两部分数据
        r.left,r.right=self.generate_tree(X,y,idx1,d-1),self.generate_tree(X,y,idx2,d-1)
        return r

    '''fit函数是CART函数的入口,调用generate_tree函数生成一颗深度不超过max_depth的决策树,并将根节点存于成员root中'''
    def fit(self,X,y):
         self.root=self.generate_tree(X,y,range(len(X)),self.max_depth)

    def get_prediction(self,r,x):
        if r.left==None and r.right==None:
            return r.p
        if x[r.j]<=r.theta:
            return self.get_prediction(r.left,x)
        else:
            return self.get_prediction(r.right,x)

    def predict(self,X):
        y=list()
        for i in range(len(X)):
            y.append(self.get_prediction(self.root,X[i]))
        return np.array(y)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值