决策树算法(C4.5)

决策树算法(C4.5)

ID3具有一定的局限性,即信息增益倾向于选择取值比较多的特征(特征越多,条件熵(特征划分后的类别变量的熵)越小,信息增量就越大),C4.5通过选择最大的信息增益率 gain ratio 来选择节点可以解决该问题。并且C4.5算法可以处理连续和有缺失值的数据。

C4.5与ID3在实现过程中,不同之处在于将计算信息增益的函数改为计算信息增益率。

 

 

 

譬如,对于上一个例子中的湿度这一项的取值改为:

Day

Outlook

Temperature

Humidity

Wind

PlayTennis

1

Sunny

Hot

85

Weak

No

2

Sunny

Hot

90

Strong

No

3

Overcast

Hot

78

Weak

Yes

4

Rain

Mild

96

Weak

Yes

5

Rain

Cool

80

Weak

Yes

6

Rain

Cool

70

Strong

No

7

Overcast

Cool

65

Strong

Yes

8

Sunny

Mild

95

Weak

No

9

Sunny

Cool

70

Weak

Yes

10

Rain

Mild

80

Weak

Yes

11

Sunny

Mild

70

Strong

Yes

12

Overcast

Mild

90

Strong

Yes

13

Overcast

Hot

75

Weak

Yes

14

Rain

Mild

80

Strong

No

 

Gain(Wind) = Entropy(S) – (8/14)* Entrogy(weak)-(6/14)* Entrogy(strong) = 0.048

 

weak = 8;Strong = 6

Feature(Wind) = -8/14*log(8/14)-6/14*log(6/14) = 0.9852

 

RatioGain(Wind) = Gain(Wind)/Feature (Wind) = 0.0487

 

同理:RatioGain(Outlook) = 0.247/1.577 = 0.1566

RatioGain(Temperature)= 0.029/1.556 = 0.018

其中,对于连续值的计算:

1.      对特征的取值进行升序排序

2.      两个特征取值之间的中点作为可能的分裂点,将数据集分成两部分,计算每个可能的分裂点的信息增益(InforGain)。优化算法就是只计算分类属性发生改变的那些特征取值。

3.      选择修正后信息增益(InforGain)最大的分裂点作为该特征的最佳分裂点

4.      计算最佳分裂点的信息增益率(Gain Ratio)作为特征的Gain Ratio。注意,此处需对最佳分裂点的信息增益进行修正:减去log2(N-1)/|D|(N是连续特征的取值个数,D是训练数据数目,此修正的原因在于:当离散属性和连续属性并存时,C4.5算法倾向于选择连续特征做最佳树分裂点)

 

故,划分为:{ 65、70、75、78、80、85、90、95、96 } 这几个特征。

 

 

65

70

75

78

80

85

90

95

96

 

Yes

1

8

3

6

4

5

5

4

7

2

7

2

8

1

8

1

9

0

No

0

5

1

4

1

4

1

4

2

3

3

2

4

1

5

0

5

0

Entropy

0

0.961

0.811

0.971

0.722

0.991

0.65

1

0.764

0.971

0.881

1

0.918

1

0.961

0

0.94

0

Gain

0.048

0.015

0.045

0.090

0.102

0.025

0.011

0.048

0

此时,可以看到当特征小于等于80时,信息增益最大,选取该取值区间作为湿度属性的信息增益。

即Gain(Humidity) = 0.102

Feature(Humidity) = -9/14*log(9/14) – 5/14*log(5/14) = 0.940(两个分支,大于80的和小于等于80的)

RatioGain(Humidity) = 0.102/0.940 = 1.085

 

 

//————————————————

对于ID3算法局限性的理解:

X = [['sunny',    'hot',   'h_85',   'weak'],
     ['sunny',    'hot',   'h_90',   'strong'], 
     ['overcast', 'hot',   'h_78',   'weak'], 
     ['rain',     'mild',  'h_96',   'weak'], 
     ['rain',     'cool',  'h_80', 'weak'], 
     ['rain',     'cool',  'h_70', 'strong'], 
     ['overcast', 'cool',  'h_65', 'strong'], 
     ['sunny',    'mild',  'h_95',   'weak'], 
     ['sunny',    'cool',  'h_70', 'weak'], 
     ['rain',     'mild',  'h_80', 'weak'], 
     ['sunny',    'mild',  'h_70', 'strong'], 
     ['overcast', 'mild',  'h_90',   'strong'], 
     ['overcast', 'hot',   'h_75', 'weak'], 
     ['rain',     'mild',  'h_80',   'strong'], 
]

  对于ID3算法的输入改为,可以看到生成的决策树为:

 <span>决策树算法(C4.5)</span>

可以看到,此时就会出现过拟合的现象。

而采用信息增益率作为判决条件的话:

estimator = Id3Estimator(gain_ratio=1)

  获得的决策树为:

<span>决策树算法(C4.5)</span>

因此,对于使用信息增益作为分类准则和使用信息增益率的区别如上所示。 

//———————————–

 

对于处理数值的理解:

解读python的第三方库,ID3模块(decision-tree-id3

 

在其中id3.py模块中:

Id3Estimator类的fit函数中

for i in range(self.n_features):
            if check_input and check_numerical_array(X_[:, i]):
                self.is_numerical[i] = True
                X_tmp[:, i] = X_[:, i]
            else:
                X_tmp[:, i] = self.X_encoders[i].fit_transform(X_[:, i])

  这里会判断一下传递的特征是名字还是数字,判断的方法在checks.py中:

def check_numerical_array(array):
    """ Check if all values in a 1d array are numerical. Raises error if array
        is more than 1d.

    Parameters
    ----------
    array : nparray
        containing the class names

    Returns
    -------
    result : bool
        True if all values in array are numerical, otherwise false
    """
    try:
        if array.ndim > 1:
            raise ArithmeticError("Found array with dim {}. Expected = 1."
                                  .format(array.ndim))
        array.astype(np.float64)
        return True
    except ValueError:
        return False

  此处会做一个类型转换,如果输入的是数字、字符串形式的数字都会被转为float类型。

(此次我觉得不太妥当,字符串形式的数字不应该转化为数字,说不定人家就是想这样输入作为feature呢,譬如我上面的输入数字的开头还要加一个 ‘h_’)

当特征为数字的时候计算方法在splitter.py文件中:

def _info_numerical(self, x, y):
        """ Info for numerical feature feature_values
        sort values then find the best split value

        Parameters
        ----------
        x : np.array of shape [n remaining examples]
            containing feature values
        y : np.array of shape [n remaining examples]
            containing relevent class

        Returns
        -------
        : float
            information for remaining examples given feature
        : float
            pivot used set1 < pivot <= set2
        """
        n = x.size
        sorted_idx = np.argsort(x, kind='quicksort')
        sorted_y = np.take(y, sorted_idx, axis=0)
        sorted_x = np.take(x, sorted_idx, axis=0)
        min_info = float('inf')
        min_info_pivot = 0
        min_attribute_counts = np.empty(2)
        for i in range(1, n):
            if sorted_x[i - 1] != sorted_x[i]:
                tmp_info = i * self._entropy(sorted_y[0: i]) + \
                           (n - i) * self._entropy(sorted_y[i:])
                if tmp_info < min_info:
                    min_attribute_counts[SplitRecord.LESS] = i
                    min_attribute_counts[SplitRecord.GREATER] = n - i
                    min_info = tmp_info
                    min_info_pivot = (sorted_x[i - 1] + sorted_x[i]) / 2.0
        return CalcRecord(CalcRecord.NUM,
                          min_info * np.true_divide(1, n),
                          pivot=min_info_pivot,
                          attribute_counts=min_attribute_counts)

  

可以看到,其计算过程和上述对于数值的计算过程一样,其min_info为选取的最小的分类后的信息熵,为了得到最大的信息增益。

 

而对于是否使用信息增益率的判断在splitter.py文件中:

def _is_better(self, calc_record1, calc_record2):
        """Compares CalcRecords using gain ratio if present otherwise
           using the  information.

        Parameters
        ----------
        calc_record1 : CalcRecord
        calc_record2 : CalcRecord

        Returns
        -------
        : bool
            if calc_record1 < calc_record2
        """
        if calc_record1 is None:
            return True
        if calc_record2 is None:
            return False
        if self.gain_ratio:
            if calc_record1.gain_ratio is None:
                calc_record1.gain_ratio = self._gain_ratio(calc_record1)
            if calc_record2.gain_ratio is None:
                calc_record2.gain_ratio = self._gain_ratio(calc_record2)
            if self._is_close(calc_record1.gain_ratio,
                              calc_record2.gain_ratio):
                return calc_record1.info > calc_record2.info
            else:
                return calc_record1.gain_ratio < calc_record2.gain_ratio
        else:
            return calc_record1.info > calc_record2.info

  

故,对于C4.5算法,同样可以使用ID3模块,只不过设置参数:gain_ratio=True即可。

得到的决策树为:

<span>决策树算法(C4.5)</span>

 下面我们验证在sunny情况下,humidity的划分便准是否正确:

Day

Outlook

Temperature

Humidity

Wind

PlayTennis

1

Sunny

Hot

85

Weak

No

2

Sunny

Hot

90

Strong

No

8

Sunny

Mild

95

Weak

No

9

Sunny

Cool

70

Weak

Yes

11

Sunny

Mild

70

Strong

Yes

首先计算humidity:

 

70

85

90

95

 

Yes

2

0

2

0

2

0

2

0

No

0

3

1

2

2

1

3

0

Entropy

0

0

0.756

0

0.846

0

0.971

0

Gain

0.971

0.517

0.294

0

Gain(humidity) = 0.971

Feature(humidity) = -2/5*log(-2/5) – 3/5*log(3/5) = 0.971(分两组,小于等于70的有2个数据,大于70的有3个数据)

RatioGain(humidity) = 1

 

Gain(Temperature) = 0.971 –  (-log(0.5) * 2/5) = 0.571

Feature(Temperature) = -2/5*log(-2/5)*2 – 1/5*log(1/5) = 1.522(分三组,分别有2、2、1个数据)

RatioGain(Temperature) = 0.375

 

Gain(Wind) = 0.971 – (3/5*(-1/3*log(1/3)-2/3*log(2/3)) + 2/5( -1/2*log(1/2)-1/2*log(1/2)))= 0.02

Feature(Wind) = 0.971

RatioGain(Wind) = 0.02

 

因此,程序得到的结果是对的。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119483.html原文链接:https://javaforall.net

(0)
上一篇 2021年11月19日 下午12:00
下一篇 2021年11月19日 下午12:00


相关推荐

  • Linux权限详解(chmod、600、644、700、711、755、777、4755、6755、7755)「建议收藏」

    Linux权限详解(chmod、600、644、700、711、755、777、4755、6755、7755)「建议收藏」权限简介Linux系统上对文件的权限有着严格的控制,用于如果相对某个文件执行某种操作,必须具有对应的权限方可执行成功。 Linux下文件的权限类型一般包括读,写,执行。对应字母为r、w、x。 Linux下权限的粒度有拥有者、群组、其它组三种。每个文件都可以针对三个粒度,设置不同的rwx(读写执行)权限。通常情况下,一个文件只能归属于一个用户和组,如果其它的用户想有这个文件的权限…

    2022年4月27日
    59
  • 随机森林算法原理解析

    随机森林算法原理解析集成学习有两个流派 一个是 boosting 派系 它的特点是各个弱学习器之间有依赖关系 另一种是 bagging 流派 它的特点是各个弱学习器之间没有依赖关系 可以并行拟合 1 bagging 的原理在集成学习原理总结中 给出 bagging 的原理图 1 Bagging 的特点 随机采样 随机采集跟训练集个数 m 相同的样本 采集 T 次 得到采样集 注意 GBDT Gr

    2026年3月19日
    7
  • Python 安装matplotlib(命令提示符安装)

    Python 安装matplotlib(命令提示符安装)1 直接打开命令提示符 快捷键 window r 2 若提示安装失败 Python Youareusingp 0 1 howeverversi 0 1isavailable 输入 python mpipinstall Upipsetuptoo 进行升级 安装成功 则下图所示 3 安装成功后 输入 pytho

    2026年3月19日
    3
  • Python处理xml文件_文件格式怎么转换

    Python处理xml文件_文件格式怎么转换由于项目组中原来的文件使用的XML格式作为配置,扩展性很好,但是编辑与阅读不是很直观,特别一些规则的二维表,所以为了方便阅读与编辑,花了一些时间写了一个Python脚本,以实现将XML文件转为Excel文件。这里支持XML文件转为一个Sheet或者多个Sheet:如果第二层所有标签都相同则会转为一个Sheet,所有第二层的标签都会作为行数据如果第二层的标签有多种,则会把第二层的不同标签作为…

    2022年8月22日
    7
  • python3画图中文乱码_pycharm 画图中文乱码

    python3画图中文乱码_pycharm 画图中文乱码importmatplo pyplotasplti 出现中文乱码原因 matplotlib 中找不到中文字体解决方法 1 找到中文字体文件的地址和字体文件名通常 C Windows Fonts 字体文件名 2 加载字体 zh font matplotlib font manager FontProperti fname C Windows Fon

    2025年7月8日
    4
  • excel隐含模块编译错误_打印提示错误

    excel隐含模块编译错误_打印提示错误一、灾难性问题(这是编译的设置引起的):解决办法:Debug换成AnyCPU但是,使用AnyCpu,出现了以下警告所生成项目的处理器架构“MSIL”与引用“ImageViewControlLib”的处理器架构“AMD64”不匹配。这种不匹配可能会导致运行时失败。请考虑通过配置管理器更改您的项目的目标处理器架构,以使您的项目与引用间的处理器架构保持一致,或者为引用关联一个与…

    2025年12月6日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号