我在阅读《Machine Learning In Action》并学习决策树章节。我理解决策树的构建是通过分割数据集来组织分支和叶节点的方式。这样可以在树的顶部获得更可能的信息,并限制需要经过的决策数量。
书中展示了一个计算数据集香农熵的函数:
def calcShannonEnt(dataSet): numEntries = len(dataSet) labelCounts = {} for featVec in dataSet: #the the number of unique elements and their occurance currentLabel = featVec[-1] if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0 labelCounts[currentLabel] += 1 shannonEnt = 0.0 for key in labelCounts: prob = float(labelCounts[key])/numEntries shannonEnt -= prob * log(prob,2) #log base 2 return shannonEnt
其中,输入数据集是一个数组的数组,每个数组代表一个可分类的特征:
dataSet = [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
我不明白的是,为什么书中的香农熵函数只查看特征数组的最后一个元素?看起来它只计算了“yes”或“no”项的熵,而没有计算其他特征的熵?
这对我来说没有意义,因为这个数据集的熵
dataSet = [[1, 1, 'yes'], [1, 'asdfasdf', 'yes'], [1900, 0, 'no'], [0, 1, 'no'], ['ddd', 1, 'no']]
与上面的熵相同,尽管它包含了更多样化的数据。
难道不应该也计算其他特征元素的熵,以便给出数据集的总熵吗,还是我误解了熵计算的目的?
如果有人好奇,这本书的完整源代码(这段代码的来源)可以在这里的Chapter03文件夹下找到。
回答:
这里的潜在模糊性在于,你正在查看的数据集同时包含特征和结果变量,结果变量位于最后一列。你试图解决的问题是“特征1和特征2是否有助于预测结果?”
另一种表述方式是,如果我根据特征1分割数据,我是否能获得关于结果的更好信息?
在这种情况下,不进行分割时,结果变量是[ yes, yes, no, no, no ]。如果按特征1分割,我得到两个组:特征1 = 0 -> 结果是[ no, no ]特征1 = 1 -> 结果是[ yes, yes, no ]
这里的想法是看看分割是否有帮助。最初,你有一定的信息,由[ yes, yes, no, no, no ]的香农熵描述。分割后,你有两个组,对于特征1 = 0的组,你有“更好”的信息:你知道在这种情况下结果是no,这由[ no, no ]的熵来衡量。
换句话说,方法是找出在你可用的特征中,是否有一个特征,如果使用它,可以增加你对你关心的结果变量的信息。树的构建将贪婪地选择每个步骤中信息增益最高的特征,然后看看是否值得进一步分割结果组。