继上一期说完如何选择最优划分属性的原理,这期主要说说划分数据的Python实现
1. 划分数据集
def splitDataSet (dataSet, divFeat, value)
copyDataSet = []
for featVec in dataSet :
if featVec[divFeat] == value :
reducedFeatVec[:divFeat]
reducedFeatVec.extend(featVec[divFeat+1:])
copyDataSet.append(reducedFeatVec)
return copyDataSet
代码解释:
line 1:输入参数为 需要划分的数据集,划分特征,返回的特征值
line 2:由于Python传递的是引用而不是原数据复制,为了保证不改变原数据我扪新建立一个列表
line 3:遍历数据集中的没个元素
line 4:抽取符合的特征值
line 5:将该特征前的所有元素,除了该特征全部放入reducedFeatVec列表中(举例:a = [5,6,7,8,9] : a[:3] -> [5,6,7])
line 6:.extend()使Python列表类型自带的方法,其与append()有相似但结果截然不同的效果(举例:a = [5,6,7] b=[8,9] : a.extend(b) -> [5,6,7,8,9]; a.append(b) -> [5,6,7, [8,9] ]) append() 会将其元素作为一个列表整体放入到a中,a的最后一个元素是一个列表,列表中包含了b中的所有元素。 同时 featVec[divFeat+1:] 意思为 将divFeat 后的所有元素都放入到reducedFeatVec 里表中,+1 的原因是不同于向前,向后是包含的该特征的(举例 a = [5,6,7,8,9] : a[3:] -> [8,9])
line 7:将获得的reducedFeatVec 按照一个一个列表形式存入copyDataSet中
结果展示:
>>>dataSet
[ [1,1,y], [1,0,y], [1,1,n], [0,0,n], [0,1,n] ]
>>>tree.splitDataSet(dataSet,0,1)
[1,1,y], [1,0,y], [1,1,n]
2. 找到最好的划分属性
def bestFeatSplit(dataSet) :
numFeats = len(dataSet[0]) - 1
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0; bestFeat = -1
for i in range(numFeats) :
featList = [featValue[i] for featValue in dataSet]
uniqueVals = set(featureList)
newEntropy = 0.0
for value in uniqueVals :
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
infoGain = beseEntropy - newEntropy
if (infoGain > bestEntropy) :
bestInfoGain = infoGain
bestFeat = i
return bestFeat
代码解释:
line 1:输入参数为 需要划分的数据集
line 2:计算列表所具有的特征数,-1 的原因时最后一项是类标签,不是特征属性(特别注意的是,所有的数据列表必须具有相同的数据长度,同时最后一项必须是类别标签)
line 3:通过上一期的代码计算出初始的熵
line 5:range() 是Python函数,其效果是取 0~numFeats-1 的所有值(举例:range(4) -> [0,1,2,3]),需要特别注意的是,在for之外的地方更改 i 的值不会影响到 for 循环
(举例: for i in range(3)
print i
i +=2
print i
打印结果为:0 2
1 3
2 4)
line 6:使用列表推导来创建新的列表,将数据集中所有第 i 个特征值或者所有可能存在的值写入新的列表中
line 7:set() 取集合,集合中各个值各不相同
line 9:遍历所有唯一的属性值
line 10~12:计算新的熵,原理见上一期
line 13:计算信息增益
line 14~17:找打最大的信息增益,并返回索引值
结果展示:
>>>tree.bestFeatSplit(dataSet)
0
可以看出 如果按照0划分,最后结果有一个n 被错误的分到 y 组,如果按照1划分,将有一个y被错误分到 n 组同时剩下的一组分别是一个 y 和一个 n。由此可见按照 0 划分最佳
下一期将会更新如何使用Python构建决策树
3. 参考
1.《Modern Information Retrieval The Concepts and Technology behind Search》Second Edition – Ricardo Baeza-Yates Berthier Ribeiro-Neto
2.《Machine learning in Action》 – Peter Harrington
3.《Data Mining Concepts and Techniques》 – Jiawei Han, Micheline Kamber, Jian Pei