1111import operator
1212from math import log
1313import decisionTreePlot as dtPlot
14+ from collections import Counter
1415
1516
1617def createDataSet ():
@@ -45,33 +46,12 @@ def calcShannonEnt(dataSet):
4546 Returns:
4647 返回 每一组feature下的某个分类下,香农熵的信息期望
4748 """
48- # 求list的长度,表示计算参与训练的数据量
49- numEntries = len (dataSet )
50- # 下面输出我们测试的数据集的一些信息
51- # 例如:<type 'list'> numEntries: 5 是下面的代码的输出
52- # print type(dataSet), 'numEntries: ', numEntries
53-
54- # 计算分类标签label出现的次数
55- labelCounts = {}
56- # the the number of unique elements and their occurance
57- for featVec in dataSet :
58- # 将当前实例的标签存储,即每一行数据的最后一个数据代表的是标签
59- currentLabel = featVec [- 1 ]
60- # 为所有可能的分类创建字典,如果当前的键值不存在,则扩展字典并将当前键值加入字典。每个键值都记录了当前类别出现的次数。
61- if currentLabel not in labelCounts .keys ():
62- labelCounts [currentLabel ] = 0
63- labelCounts [currentLabel ] += 1
64- # print '-----', featVec, labelCounts
65-
66- # 对于label标签的占比,求出label标签的香农熵
67- shannonEnt = 0.0
68- for key in labelCounts :
69- # 使用所有类标签的发生频率计算类别出现的概率。
70- prob = float (labelCounts [key ])/ numEntries
71- # log base 2
72- # 计算香农熵,以 2 为底求对数
73- shannonEnt -= prob * log (prob , 2 )
74- # print '---', prob, prob * log(prob, 2), shannonEnt
49+ # 统计标签出现的次数
50+ label_count = Counter (data [- 1 ] for data in dataSet )
51+ # 计算概率
52+ probs = [p [1 ] / len (dataSet ) for p in label_count .items ()]
53+ # 计算香农熵
54+ shannonEnt = sum ([- p * log (p , 2 ) for p in probs ])
7555 return shannonEnt
7656
7757
@@ -83,38 +63,9 @@ def splitDataSet(dataSet, index, value):
8363 index 表示每一行的index列 划分数据集的特征
8464 value 表示index列对应的value值 需要返回的特征的值。
8565 Returns:
86- index列为value的数据集【该数据集需要排除index列】
66+ index列为value的数据集
8767 """
88- retDataSet = []
89- for featVec in dataSet :
90- # index列为value的数据集【该数据集需要排除index列】
91- # 判断index列的值是否为value
92- if featVec [index ] == value :
93- # chop out index used for splitting
94- # [:index]表示前index行,即若 index 为2,就是取 featVec 的前 index 行
95- reducedFeatVec = featVec [:index ]
96- '''
97- 请百度查询一下: extend和append的区别
98- list.append(object) 向列表中添加一个对象object
99- list.extend(sequence) 把一个序列seq的内容添加到列表中
100- 1、使用append的时候,是将new_media看作一个对象,整体打包添加到music_media对象中。
101- 2、使用extend的时候,是将new_media看作一个序列,将这个序列和music_media序列合并,并放在其后面。
102- result = []
103- result.extend([1,2,3])
104- print result
105- result.append([4,5,6])
106- print result
107- result.extend([7,8,9])
108- print result
109- 结果:
110- [1, 2, 3]
111- [1, 2, 3, [4, 5, 6]]
112- [1, 2, 3, [4, 5, 6], 7, 8, 9]
113- '''
114- reducedFeatVec .extend (featVec [index + 1 :])
115- # [index+1:]表示从跳过 index 的 index+1行,取接下来的数据
116- # 收集结果值 index列为value的行【该行需要排除index列】
117- retDataSet .append (reducedFeatVec )
68+ retDataSet = [data for data in dataSet for i , v in enumerate (data ) if i == axis and v == value ]
11869 return retDataSet
11970
12071
@@ -126,36 +77,24 @@ def chooseBestFeatureToSplit(dataSet):
12677 Returns:
12778 bestFeature 最优的特征列
12879 """
129- # 求第一行有多少列的 Feature, 最后一列是label列嘛
130- numFeatures = len (dataSet [0 ]) - 1
131- # label的信息熵
132- baseEntropy = calcShannonEnt (dataSet )
133- # 最优的信息增益值, 和最优的Featurn编号
134- bestInfoGain , bestFeature = 0.0 , - 1
135- # iterate over all the features
136- for i in range (numFeatures ):
137- # create a list of all the examples of this feature
138- # 获取每一个实例的第i+1个feature,组成list集合
139- featList = [example [i ] for example in dataSet ]
140- # get a set of unique values
141- # 获取剔重后的集合,使用set对list数据进行去重
142- uniqueVals = set (featList )
143- # 创建一个临时的信息熵
144- newEntropy = 0.0
145- # 遍历某一列的value集合,计算该列的信息熵
146- # 遍历当前特征中的所有唯一属性值,对每个唯一属性值划分一次数据集,计算数据集的新熵值,并对所有唯一特征值得到的熵求和。
147- for value in uniqueVals :
148- subDataSet = splitDataSet (dataSet , i , value )
149- prob = len (subDataSet )/ float (len (dataSet ))
150- newEntropy += prob * calcShannonEnt (subDataSet )
151- # gain[信息增益]: 划分数据集前后的信息变化, 获取信息熵最大的值
152- # 信息增益是熵的减少或者是数据无序度的减少。最后,比较所有特征中的信息增益,返回最好特征划分的索引值。
153- infoGain = baseEntropy - newEntropy
154- print 'infoGain=' , infoGain , 'bestFeature=' , i , baseEntropy , newEntropy
155- if (infoGain > bestInfoGain ):
156- bestInfoGain = infoGain
157- bestFeature = i
158- return bestFeature
80+ # 计算初始香农熵
81+ base_entropy = calcShannonEnt (dataSet )
82+ best_info_gain = 0
83+ best_feature = - 1
84+ # 遍历每一个特征
85+ for i in range (len (dataSet [0 ]) - 1 ):
86+ # 对当前特征进行统计
87+ feature_count = Counter ([data [i ] for data in dataSet ])
88+ # 计算分割后的香农熵
89+ new_entropy = sum (feature [1 ] / float (len (dataSet )) * calcShannonEnt (splitDataSet (dataSet , i , feature [0 ])) \
90+ for feature in feature_count .items ())
91+ # 更新值
92+ info_gain = base_entropy - new_entropy
93+ print ('No. {0} feature info gain is {1:.3f}' .format (i , info_gain ))
94+ if info_gain > best_info_gain :
95+ best_info_gain = info_gain
96+ best_feature = i
97+ return best_feature
15998
16099
161100def majorityCnt (classList ):
0 commit comments