西瓜数据集的分类:贝叶斯,决策树

原始数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
色泽 根蒂 敲声 纹理 脐部 触感 好瓜
青绿 蜷缩 浊响 清晰 凹陷 硬滑 是
乌黑 蜷缩 沉闷 清晰 凹陷 硬滑 是
乌黑 蜷缩 浊响 清晰 凹陷 硬滑 是
青绿 蜷缩 沉闷 清晰 凹陷 硬滑 是
浅白 蜷缩 浊响 清晰 凹陷 硬滑 是
青绿 稍蜷 浊响 清晰 稍凹 软粘 是
乌黑 稍蜷 浊响 稍糊 稍凹 软粘 是
乌黑 稍蜷 浊响 清晰 稍凹 硬滑 是
乌黑 稍蜷 沉闷 稍糊 稍凹 硬滑 否
青绿 硬挺 清脆 清晰 平坦 软粘 否
浅白 硬挺 清脆 模糊 平坦 硬滑 否
浅白 蜷缩 浊响 模糊 平坦 软粘 否
青绿 稍蜷 浊响 稍糊 凹陷 硬滑 否
浅白 稍蜷 沉闷 稍糊 凹陷 硬滑 否
乌黑 稍蜷 浊响 清晰 稍凹 软粘 否
浅白 蜷缩 浊响 模糊 平坦 硬滑 否
青绿 蜷缩 沉闷 稍糊 稍凹 硬滑 否

  数据集的第一行为特征和分类标题。一共有6个特征,17组数据,分类标签为是否为好瓜。每个数据用空格隔开。

贝叶斯算法

准备数据集

  由于贝叶斯算法需要计算类别概率,所以在原始数据集中需要将文字的’是’和’否’改写为’1’和’0’。
程序实现:

1
2
3
4
5
6
7
8
9
10
def file2dataSet(filename):
postingList = []
classVec = []
with open(filename) as fr:
next(fr) # 跳过第一行
for line in fr.readlines():
line = line.strip().split(' ')
postingList.append(line[:-1])
classVec.append(eval(line[-1])) # 去掉字符串的双引号
return postingList, classVec

  首先创建一个存储特征和分类的空列表,然后使用with语句打开文件。由于第一行是标题,所以要跳过该行,next()函数返回可迭代对象的下一个值。
  然后用strip()函数将原始数据集中的空白,换行符等都删掉。原始数据集是用空格隔开的,所以可用split(‘ ‘)函数将其分隔开,然后将特征和分类标签分别添加到特征和分类的列表中。
  line[:-1]表示特征,line[-1]表示标签,因为字符串返回的标签值会带有单引号,不可进行求和运算,eval()函数会把字符串当成有效的表达式来求值并返回计算结果,即可以去掉字符串的引号。

测试数据

  假设有1组西瓜数据:’青绿’, ‘蜷缩’, ‘浊响’, ‘清晰’, ‘凹陷’, ‘硬滑’,利用贝叶斯进行分类预测。
  贝叶斯算法可参照之前的博客。
程序实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == '__main__':
data, labels = file2dataSet("xiguaData.txt")
myVocabList = createVocabList(data)

trainMat = []
for doc in data:
trainMat.append(setOfWords2Vec(myVocabList, doc))
p0V, p1V, pAb = trainNBO(trainMat, labels)

testEntry = {'青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑'}
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
result = classifyNB(thisDoc, p0V, p1V, pAb)
print(testEntry, " is classified as :", result)

  首先利用之前的训练算法得到贝叶斯概率模型,然后将输入的数据转换为分类算法所需要的特征个数列表,即thisDoc,然后将其和概率模型得到的特征概率列表进行运算预测,最终其结果为属于’1’分类,即’好瓜’分类。

决策树算法

准备数据集

  决策树算法的数据集分为两部分,一部分为已知分类类别的数据,另一部分为所有的特征标题,即[‘色泽’, ‘根蒂’, ‘敲声’, ‘纹理’, ‘脐部’, ‘触感’]。
程序实现:

1
2
3
4
5
6
7
8
9
10
def file2dataSet(filename):
dataSet = []
with open(filename) as fr:
next(fr) # 跳过第一行
for line in fr.readlines():
line = line.strip().split(' ')
dataSet.append(line)
labels = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']

return dataSet, labels

  将原始数据集中的每行数据添加到dataSet中。这里的label是特征标签,不是分类标签。决策树是根据特征的熵来选择最佳分类的。

测试数据集

  还是之前的测试数据’青绿’, ‘蜷缩’, ‘浊响’, ‘清晰’, ‘凹陷’, ‘硬滑’,利用决策树进行分类预测。
  决策树算法可参照之前的博客。
  首先编写一个预测函数:
程序实现:

1
2
3
4
5
6
7
8
9
10
11
def classify(inputTree, featLabels, testVec):
firstStr = list(inputTree.keys())[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index(firstStr)
for key in secondDict.keys():
if testVec[featIndex] == key:
if type(secondDict[key]).__name__ == 'dict':
classLabel = classify(secondDict[key], featLabels, testVec)
else:
classLabel = secondDict[key]
return classLabel

  函数有3个参数,生成好的决策树,特征值和待预测的数据。函数使用了递归调用的方法。
  首先获得已知决策树的第一个健的值,即决策树的第一个分类特征,然后获得基于该特征的子树,并对应的找到对于待预测数据的特征是什么值,即判断下面要进入到哪一个子树。然后在判断现在的子树是叶子节点还是仍然是一个决策树,如果仍然是一个决策数,则递归调用自己,直到是叶子节点为止,即往下一层层分类,直到找到最终的叶子节点,也就分类完成了。
  代入具体的测试数据验证:
程序实现:

1
2
3
4
5
6
7
if __name__ == '__main__':
dataSet, labels = file2dataSet("xiguaData.txt")
mytree = createTree(dataSet, labels)
print(mytree)
testVec = ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑']
labels = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']
classLabel = classify(mytree, labels, testVec)

  首先根据之前的决策树算法得到决策树模型,即{‘纹理’: {‘模糊’: ‘否’, ‘清晰’: {‘根蒂’: {‘稍蜷’: {‘色泽’: {‘乌黑’: {‘触感’: {‘软粘’: ‘否’, ‘硬滑’: ‘是’}}, ‘青绿’: ‘是’}}, ‘硬挺’: ‘否’, ‘蜷缩’: ‘是’}}, ‘稍糊’: {‘触感’: {‘软粘’: ‘是’, ‘硬滑’: ‘否’}}}} ,然后将待预测数据写出列表形式,并进行预测分类。此时需要将特征标签重新写一遍(之前训练决策树模型的时候删掉了一个特征),然后代入之前的预测函数,最终得到的结果为”是”好瓜。和实际的结果也是一致的。

谢谢老板!
-------------本文结束感谢您的阅读给个五星好评吧~~-------------