分类
2. K-近邻算法(KNN)
2.1 KNN概述
把需要分类的数据与已分类数据(训练集)进行比较,在前k个最近的样本中,选取分类最多的类别作为该数据的类别。属于无监督学习
- 优点:精度高、对异常值不敏感、无数据输入假定
- 缺点:计算复杂度高、空间复杂度高、无法得到任何数据的基础结构信息
- 适用数据范围:数值型和标称型。
2.2 举例1:改进约会网站配对效果
- 准备数据:从文本文件中解析数据
- 分析数据:用Matplotlib创建散点图
- 准备数据:归一化数值
- normValue = (value - min) / (max - min)
- 测试算法:验证分类器
- 使用算法:构建完整可用系统
2.3 举例2:手写系统识别
2.4 算法实现
def createDataSet():
group = np.array([[1,1.1], [1, 1], [0, 0], [0, 0.1]])
labels = ["A", "A", "B", "B"]
return group, labels
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
sqDiffMat = diffMat ** 2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances ** 0.5
sortedDistIndicies = distances.argsort() ## array排序,返回index顺序
classCount = dict()
for i in range(k):
voteILabel = labels[sortedDistIndicies[i]]
classCount[voteILabel] = classCount.get(voteILabel, 0) + 1
sortedClassCount = sorted(
classCount.iteritems(), # dict转换为tuple list 排序
key=operator.itemgetter(1), # 生成器?
reverse=True
)
return sortedClassCount[0][0]
group, labels = createDataSet()
classify0([0, 0], group, labels, 3) # output: B
3. 决策树(ID3算法)
3.1 决策树的构造
- 优点:计算复杂度低,对中间值的确实不敏感,可以处理不相关的特征数据
- 缺点:可能会产生过度匹配问题
- 适用数据类型:标称型和数值型(需要离散化)
一般流程:
- 收集数据
- 准备数据:如对数值型数据离散化
- 分析数据
- 训练算法:构造数的数据结构
- 测试算法:使用经验树计算错误率
- 使用算法
3.1.1 信息增益
-
信息熵:信息所包含的不确定性
l ( x i ) = − l o g 2 p ( x 1 ) l(x_i) = -log_2p(x_1) l(xi)=−log2p(x1) -
信息增益:信息不确定性减小的程度
H = − Σ i = 1 n p ( x 1 ) l o g 2 p ( x 1 ) H = -\Sigma_{i=1}^n{p(x_1)log_2p(x_1)} H=−Σi=1np(x1)log2p(x1)
分别计算每个特征的信息增益,每次选取信息增益最大的特征进行划分。
3.1.2 划分数据集
根据信息增益选取最佳划分特性
- 循环对每个特征的特征值提取子数据集
- 计算信息增益返回最佳划分特征
3.1.3 递归构建决策树
每次选择最佳特征进行数据集划分,并在划分后的子数据集中继续递归划分,直至每个分支下所有的实例都属于同一个分类。若已处理完所有的属性类标签仍不唯一,通常采用多数表决的方法决定该叶子节点的分类。
3.2 在Python中使用matplotlib注解绘制树形图
3.3 测试和存储分类器
(unfinished)
3.3.1 测试算法
使用测试集对决策树进行测试,并评估模型
3.3.2 使用算法
使用pickle存储决策树,后续要使用的时候直接反序列化读取使用
3.4 示例:使用决策树预测隐形眼镜的类型
(unfinished)
3.5 决策树算法实现
from math import log
## 1. 计算香农熵
def calcShannonEnt(dataSet):
"""
计算香农熵
"""
numEntries = len(dataSet)
labelCountDict = {
}
## 统计分类数
for featVec in dataSet:
currentLabel = featVec[-1]
if currentLabel not in labelCountDict:
labelCountDict[currentLabel] = 0
labelCountDict[currentLabel] += 1
## 计算熵
shannonEnt = 0
for label, count in labelCountDict.items():
prob = 1.0 * count / numEntries
shannonEnt -= prob * log(prob, 2)
return shannonEnt
## 2. 根据信息增益选择最佳划分特征
def splitDataSet(dataSet, axis, value):
"""
按照给定的特征值抽取数据集
"""
retDataSet = list()
for featVec in dataSet:
if featVec[axis] == value:
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet
def chooseBestFeatureToSplit(dataSet):
"""
选择最佳划分数据集
"""
numFeatures = len(dataSet[0]) - 1
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0
bestFeature = -1
for i in range(numFeatures):
featList = [example[i] for example in dataSet]
uniqueVals = set(featList)
newEntropy = 0.0
for value in uniqueVals: # 计算每个特征中特征值的信息熵
subDataSet = splitDataSet(dataSet, i, value)
prob = 1.0 * len(subDataSet) / len(dataSet)
newEntropy += prob * calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy # 计算信息增益:总信息熵-特征信息熵
if (infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeature = i
return bestFeature
## 3. 构建递归决策树
def majorityCnt(classList):
"""
投票表决
"""
classCount = dict()
for vote in classList:
if vote not in classCount:
classCount[vote] = 0
classCount[vote] += 1
sortedClassCount = sorted(classCount.iteritems(), key=lambda x: x[1], reverse=True)
return sortedClassCount[0][0]
def createTree(dataSet, labels):
"""
递归构建回归树
"""
classList = [r[-1] for r in dataSet]
if len(set(classList)) == 1: # 只剩一个分类
return classList[0]
if len(dataSet[0]) == 1: #用完所有的特征,只剩类别标签
return majorityCnt(classList)
bestFeat = chooseBestFeatureToSplit(dataSet)
bestFeatLabel = labels[bestFeat]
myTree = {
bestFeatLabel: {
}}
del labels[bestFeat]
featValues = [r[bestFeat] for r in dataSet]
uniqueVals = set(featValues)
for value in uniqueVals:
subLablels = labels[:] # 拷贝列表
myTree[bestFeatLabel][value] = createTree(
splitDataSet(dataSet, bestFeat, value),
subLablels
)
return myTree
## 4. 创建决策树
def createDataSet():
dataSet = [
[1, 1, 'y'],
[1, 1, 'y'],
[1, 0, 'n'],
[0, 1, 'n'],
[0, 1, 'n'],
]
labels = ["A", "B"]
return dataSet, labels
dataSet, labels = createDataSet()
myTree = createTree(dataSet, labels)
myTree # output:{'A': {0: 'n', 1: {'B': {0: 'n', 1: 'y'}}}}
## 5. 根据决策树测试算法
def classify(inputTree, featLabels, testVec):
firstStr = inputTree.keys()[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index(firstStr)
for k, v in secondDict.items():
if testVec[featIndex] == k:
if isinstance(v, dict):
classLabel = classify(v, featLabels, testVec)
else:
classLabel = v
return classLabel
classify(myTree, ["A", "B"], [1, 1]) # output:yes
4. 基于概率论的分类方法:朴素贝叶斯(Navie Bayes)
朴素:在分类器学习过程只做最原始、最简单的假设, 如假设各特征出现的概率是独立的(独立性假设)。
4.1 基于贝叶斯决策理论的分类方法
朴素贝叶斯:
- 优点:在数据较少的情况下仍然有效,可以处理