一、机器学习:(1)有监督学习:(分类、回归)k-近邻、朴素贝叶斯、支持向量机、决策树
(2)无监督学习:(聚类、密度估计)k-均值、DBSCAN
→如何选择?(1)预测目标变量的值:选择有监督学习 ①目标变量为离散型 选择分类算法(如是/否 红/黄/黑 1/2/3) ②目标变量为连续型数值 选择回归算法
(2)不预测目标变量的值:选择无监督学习 ①只需将数据划为离散的组 选择聚类算法 ②还需估计数据与每个组的相似程度 选择密度估计算法
二、K-近邻算法(KNN):存在一个有标签的训练样本集,输入没有标签的新数据后,将新数据的每个特征与样本集中数据的每个特征进行比较,提取出特征最相似的分类标签。只选择样本数据集中前K个最相似的样本(通常K不大于20)。
优点:精度高、对异常值不敏感、无数据输入假定
缺点:计算复杂度、空间复杂度高
适用数据范围:数值型和标称型
示例1:
# -*- coding: UTF-8 -*-
import numpy as np
import operator
def createDataSet():
# 四组二维特征
group = np.array([[1, 101], [5, 89], [108, 5], [115, 8]])
# 四组特征的标签
labels = ['爱情片', '爱情片', '动作片', '动作片']
return group, labels
if __name__ == '__main__':
#创建数据集
group, labels = createDataSet()
#打印数据集
print(group)
print(labels)
def classify0(inX, dataSet, labels, k):
# numpy函数 shape[0]返回dataSet的行数
dataSetSize = dataSet.shape[0]
# 在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
# 二维特征相减后平方
sqDiffMat = diffMat ** 2
# sum()所有元素相加,sum(0)列相加,sum(1)行相加
sqDistances = sqDiffMat.sum(axis=1)
# 开方,计算出距离
distances = sqDistances ** 0.5
# 返回distances中元素从小到大排序后的索引值
sortedDistIndices = distances.argsort()
# 定一个记录类别次数的字典
classCount = {}
for i in range(k):
# 取出前k个元素的类别
voteIlabel = labels[sortedDistIndices[i]]
# dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
# 计算类别次数
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
# python3中用items()替换python2中的iteritems()
# key=operator.itemgetter(1)根据字典的值进行排序
# key=operator.itemgetter(0)根据字典的键进行排序
# reverse降序排序字典
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
# 返回次数最多的类别,即所要分类的类别
return sortedClassCount[0][0]
if __name__ == '__main__':
# 创建数据集
group, labels = createDataSet()
# 测试集
test = [101, 20]
# kNN分类
test_class = classify0(test, group, labels, 3)
# 打印分类结果
print(test_class)
示例2:
示例3:
三、决策树:找到在划分数据分类时起决定作用的特征(所以需评估每一个特征),完成后原始数据集就被分为几个数据子集。如果某个分支下的数据属于同一类型则不需再进行分割,否则则需重复划分。
优点:计算复杂度不高,对中间值的缺失不敏感,可以处理不相关特征数据
缺点:可能产生过度匹配问题
适用数据类型:数值型和标称型
信息增益 :在划分数据集之前之后信息发生的变化成为信息增益。(用来作为特征选择的标准,获得增益最高的特征就是最好的选择)。
(1)为了计算熵,我们需要计算所有类别所有可能值包含的信息期望值(数学期望),通过下面的公式得到:
当熵中的概率由数据估计(特别是最大似然估计)得到时,所对应的熵称为经验熵。我们定义样本数据表中的数据为训练数据集D,则训练数据集D的经验熵为H(D),|D|表示其样本容量,及样本个数。设有K个类Ck, = 1,2,3,...,K,|Ck|为属于类Ck的样本个数,因此经验熵公式就可以写为 :
示例1:计算给定数据集的香农熵
# -*- coding: UTF-8 -*-
import numpy as np
from math import log
def createDataSet():
dataSet=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']]
labels=['no surfacing','flippers']
return dataSet,labels
def calcShannonEnt(dataSet):
numEntries=len(dataSet)#返回数据集长度
labelsCounts={}#保存每个标签出现次数的词典
for featVec in dataSet:#对每组特征向量进行统计
currentLabel=featVec[-1]#提取标签信息
if currentLabel not in labelsCounts.keys():#如果标签次数没有放入统计次数的字典,添加进去
labelsCounts[currentLabel]=0
labelsCounts[currentLabel]+=1
shannonEnt=0.0#经验熵(香农熵)
for key in labelsCounts:#计算香农熵
prob =float(labelsCounts[key])/numEntries#选择该标签的概率
shannonEnt-= prob* log (prob,2)#利用公式计算
return shannonEnt
if __name__ =='__main__' :
dataSet,features=createDataSet()
print(dataSet)
print(calcShannonEnt(dataSet))
(2)条件熵H(Y|X)表示在已知随机变量X的条件下随机变量Y的不确定性,随机变量X给定的条件下随机变量Y的条件熵H(Y|X),定义为X给定条件下Y的条件概率分布的熵对X的数学期望:
当条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的条件熵称为条件经验熵。
设特征A有n个不同的取值{a1,a2,···,an},根据特征A的取值将D划分为n个子集{D1,D2,···,Dn},|Di|为Di的样本个数。记子集Di中属于Ck的样本的集合为Dik,即Dik = Di ∩ Ck,|Dik|为Dik的样本个数。于是经验条件熵的公式可以些为:
信息增益是相对于特征而言的。所以,特征A对训练数据集D的信息增益g(D,A),定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差,即:
一般地,熵H(D)与条件熵H(D|A)之差称为互信息。决策树学习中的信息增益等价于训练数据集中类与特征的互信息。
示例2:划分数据集(我们将每个特征划分数据集的结果计算一次信息熵,然后判断按照哪个特征划分数据集最优。
# -*- coding: UTF-8 -*-
import numpy as np
from math import log
def createDataSet():
dataSet=[[0,0,0,0,'no'],[0,0,0,1,'no'],[0,1,0,1,'yes'],[0,1,1,0,'yes'],
[0,0,0,0,'no'],[1,0,0,0,'no'],[1,0,0,1,'no'],[1,1,1,1,'yes'],
[1,0,1,2,'yes'],[1,0,1,2,'yes'],[2,0,1,2,'yes'],[2,0,1,1,'yes'],
[2,1,0,1,'yes'],[2,1,0,2,'yes'],[2,0,0,0,'no']]
labels=['no surfacing','flippers']
return dataSet,labels
def calcShannonEnt(dataSet):
numEntries=len(dataSet)#返回数据集长度
labelsCounts={}#保存每个标签出现次数的词典
for featVec in dataSet:#对每组特征向量进行统计
currentLabel=featVec[-1]#提取标签信息
if currentLabel not in labelsCounts.keys():#如果标签次数没有放入统计次数的字典,添加进去
labelsCounts[currentLabel]=0
labelsCounts[currentLabel]+=1
shannonEnt=0.0#经验熵(香农熵)
for key in labelsCounts:#计算香农熵
prob =float(labelsCounts[key])/numEntries#选择该标签的概率
shannonEnt-= prob* log (prob,2)#利用公式计算
return shannonEnt
#划分数据集
def splitDataSet(dataSet,axis,value):#三个参数:待划分的数据集、划分数据集的特征、需要返回的特征的值
retDataSet=[]#创建返回的数据集列表
for featVec in dataSet:#遍历数据集,按照某个特征划分数据集,将所有符合要求的元素抽出来
if featVec[axis]==value:
reduceFeatVec=featVec[:axis]#去掉特征
reduceFeatVec.extend(featVec[axis+1:])#将符合条件的添加到返回的数据集
retDataSet.append(reduceFeatVec)#append是将列表直接作为下一个元素加入,extend是将列表中的元素分别并入
return retDataSet
def chooseBestFeatureToSplit(dataSet):
numFeatures=len(dataSet[0])-1#特征数量
baseEntroy=calcShannonEnt(dataSet)#计算数据集的香农熵
bestInfoGain=0.0#信息增益
bestFeature= -1#最佳特征索引值
for i in range(numFeatures):
featList=[example[i] for example in dataSet]
uniqueVals=set(featList)#创建set集合,元素不可重复
newEntropy=0.0#条件经验熵
for value in uniqueVals:#计算信息增益
subDataSet=splitDataSet(dataSet,i,value)#划分后的子集
prob=len(subDataSet)/float(len(dataSet))#计算子集的概率
newEntropy+=prob*calcShannonEnt(subDataSet)#计算条件经验熵
infoGain=baseEntroy-newEntropy#计算信息增益
print("第%d个特征的增益为%.3f"%(i,infoGain))
if (infoGain>bestInfoGain):#找到最大的信息增益
bestInfoGain=infoGain
bestFeature=i
return bestFeature
if __name__ =='__main__' :
dataSet,features=createDataSet()
print("最优特征索引值:"+str(chooseBestFeatureToSplit(dataSet)))
ID3算法 :从根结点开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征,建立子节点,再对子结点递归地调用以上方法,构建决策树;直到所有特征的信息增益均很小或没有特征可以选择为止。最后得到一个决策树。
示例3:递归构建决策树
# -*- coding: UTF-8 -*-
import numpy as np
from math import log
import operator
def createDataSet():
dataSet=[[0,0,0,0,'no'],[0,0,0,1,'no'],[0,1,0,1,'yes'],[0,1,1,0,'yes'],
[0,0,0,0,'no'],[1,0,0,0,'no'],[1,0,0,1,'no'],[1,1,1,1,'yes'],
[1,0,1,2,'yes'],[1,0,1,2,'yes'],[2,0,1,2,'yes'],[2,0,1,1,'yes'],
[2,1,0,1,'yes'],[2,1,0,2,'yes'],[2,0,0,0,'no']]
labels=['年龄','工作','房子','信贷情况']
return dataSet,labels
def calcShannonEnt(dataSet):
numEntries=len(dataSet)#返回数据集长度
labelsCounts={}#保存每个标签出现次数的词典
for featVec in dataSet:#对每组特征向量进行统计
currentLabel=featVec[-1]#提取标签信息
if currentLabel not in labelsCounts.keys():#如果标签次数没有放入统计次数的字典,添加进去
labelsCounts[currentLabel]=0
labelsCounts[currentLabel]+=1
shannonEnt=0.0#经验熵(香农熵)
for key in labelsCounts:#计算香农熵
prob =float(labelsCounts[key])/numEntries#选择该标签的概率
shannonEnt-= prob* log (prob,2)#利用公式计算
return shannonEnt
#划分数据集
def splitDataSet(dataSet,axis,value):#三个参数:待划分的数据集、划分数据集的特征、需要返回的特征的值
retDataSet=[]#创建返回的数据集列表
for featVec in dataSet:#遍历数据集,按照某个特征划分数据集,将所有符合要求的元素抽出来
if featVec[axis]==value:
reduceFeatVec=featVec[:axis]#去掉特征
reduceFeatVec.extend(featVec[axis+1:])#将符合条件的添加到返回的数据集
retDataSet.append(reduceFeatVec)#append是将列表直接作为下一个元素加入,extend是将列表中的元素分别并入
return retDataSet
def chooseBestFeatureToSplit(dataSet):
numFeatures=len(dataSet[0])-1#特征数量
baseEntropy=calcShannonEnt(dataSet)#计算数据集的香农熵
bestInfoGain=0.0#信息增益
bestFeature= -1#最佳特征索引值
for i in range(numFeatures):
featList=[example[i] for example in dataSet]
uniqueVals=set(featList)#创建set集合,元素不可重复
newEntropy=0.0#条件经验熵
for value in uniqueVals:#计算信息增益
subDataSet=splitDataSet(dataSet,i,value)#划分后的子集
prob=len(subDataSet)/float(len(dataSet))#计算子集的概率
newEntropy+=prob*calcShannonEnt(subDataSet)#计算条件经验熵
infoGain=baseEntropy-newEntropy#计算信息增益
print("第%d个特征的增益为%.3f"%(i,infoGain))
if (infoGain>bestInfoGain):#找到最大的信息增益
bestInfoGain=infoGain
bestFeature=i
return bestFeature
def majorityCnt(classList):
classCount={}
for vote in classList:#统计classCount中每个元素出现的次数
if vote not in classCount.keys():classCount[vote]=0
classCount[vote]+=1
sortedClassCount=sorted(classCount.items(), key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]#返回classCount出现次数最多的元素
#创建决策树
def createTree(dataSet,labels,featLabels):
classList=[example[-1] for example in dataSet]#取分类标签
if classList.count(classList[0])==len(classList):#如果类别完全相同,则停止划分
return classList[0]
if len(dataSet[0])==1 or len(labels)==0:#遍历完所有特征返回出现次数最多的类标签
return majorityCnt(classList)
bestFeat=chooseBestFeatureToSplit(dataSet)#选择最优特征
bestFeatLabel=labels[bestFeat]#最优特征的标签
featLabels.append(bestFeatLabel)
myTree={bestFeatLabel: {}}#根据最优特征的标签生成树
del(labels[bestFeat])#删除已经使用的特征标签
featValues=[example[bestFeat]for example in dataSet]#得到训练集中最优特征的所有属性值
uniqueVals=set(featValues)#去掉重复的使用值
for value in uniqueVals:#遍历特征,创建决策树
subLabels=labels[:]#复制类标签,并将其存在新列表变量subLabels中(保证每次调用函数时不改变原始列表的内容
myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLabels,featLabels)
return myTree
if __name__ =='__main__' :
dataSet,labels=createDataSet()
featLabels=[]
myTree = createTree(dataSet, labels, featLabels)
print(myTree)
(3)使用matplotlib绘制决策树 未解决
决策树的分类
决策树的存储
示例4 隐形眼镜