机器学习Week1K邻近算法&决策树

机器学习简介

机器学习是让计算机模拟和实现人类的学习行为,以获取新的知识或技能,重新组织现有得知识结构使之不断 改善自身的性能。

机器学习主要的任务有两类:分类(classification)和回归(regression)

分类就是将数据划分到哦合适的分类中去,例如判断邮件是否是垃圾邮件。

回归就是预测数值型的数据,说起来有点抽象。简单得说。分类的值是离散的,而回归是连续的。

监督学习

监督学习指的就是我们给学习算法一个数据集。这个数据集由“正确答案”组成。例如在分析房价时,我们给了一系列房子的数据,我们给定数据集中每个样本的正确价格,即它们实际的售价然后运用学习算法,算出更多的正确答案。

非监督学习

无监督学习中没有任何的标签或者是有相同的标签或者就是没标签。 针对数据集,无监督学习就能判断出数据有两个不同的聚集簇。这是一个,那是另一个,二者不同。 无监督学习主要包括聚类和密度估计(通过样本紧密程度,估计分组)。

机器学习开发流程
收集数据–>准备数据–>分析数据–>训练数据–>测试数据–>使用算法

numpy快速入门
https://blog.csdn.net/LSGO_MYP/article/details/102988818

k-邻接算法

什么是K邻接算法?
简单的描述,k-近邻算法采用测量不同特征值之间的距离方法进行分类。这里所谓的距离是欧式距离。算法本身通过从样本数据中寻找与待预测的样本数据最接近,也就是距离最短的k个,看看这k个都属于哪一类,类型占比最多的作为预测分类返回。所谓的距离,放在二维空间和三维空间,就是点到点的距离,只是由于数据集,属性可能会更多,所以这里的距离可能建立在超维空间,但是还是那个欧几里得公式.

k-近邻算法的一般流程
收集数据:可以使用任何方法。
准备数据:距离计算所需要的数值,最好是结构化的数据格式。
分析数据:可以使用任何方法。
训练算法:此步骤不适用于k-近邻算法。
测试算法:计算错误率。
使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输 入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
KNN算法伪代码
对未知类别属性的数据集中的每个点依次执行以下操作:

计算已知类别数据集中的点与当前点之间的距离;
按照距离递增次序排序;
选取与当前点距离最小的k个点;
确定前k个点所在类别的出现频率;
返回前k个点出现频率最高的类别作为当前点的预测分类。
python代码

from numpy import * 
import operator      
def createDataSet():
    group=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels=['A','A','B','B']
    return group,labels
def classify0(inX,dataSet,labels,k):
    dataSetSize=dataSet.shape[0]
    diffMat=tile(inX,(dataSetSize,1)) -dataSet
    sqDiffMat=diffMat**2
    sqDistances=sqDiffMat.sum(axis=1)
    distances=sqDistances**0.5
    sortedDistIndicies=distances.argsort()
    classCount={}
    for i in range(k):
        voteIlable=labels[sortedDistIndicies[i]]
        classCount[voteIlable]=classCount.get(voteIlable,0)+1
    sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]

import KNN
group,labels=KNN.createDataSet()
group
array([[1. , 1.1],
[1. , 1. ],
[0. , 0. ],
[0. , 0.1]])

labels
[‘A’, ‘A’, ‘B’, ‘B’]
classify0([0,0],group,labels,3)
输出’B’

1
2
3
4
5
6
7
8
9
10
11
12
测试分类器的方法
使用我们已知答案的数据集,得到分类器的错误率——分类器给出错误结果的次数除以测试执行的总数。最好为0,最坏为1.

任务实战–约会网站配对
任务要求

分类:1.不喜欢的人 2.魅力一般的人 3.极具魅力的人

特征:1.每年获得的飞行常客里程数 2.玩视频游戏所耗时间百分比 3.每周消费的冰淇淋公升数

解析文本数据
数据处理是进行机器学习的第一步,之前的一位老师常说garbage in,garbage out。意思就是如果数据本身是一团浆糊不经过分析处理的话,是不会获得好的模型的。

解析数据主要包括,打开文件,读取每一行数据,提取每一列,添加到结果,循环每一列后,返回训练集特征矩阵。

def file2matrix(filename):
fr = open(filename)
array0Lines= fr.readlines()
numberOfLines=len(array0Lines)
returnMat=zeros((numberOfLines,3))
classLabelVector=[]
index=0
for line in array0Lines:
line=line.strip()
listFromLine=line.split(’\t’)
returnMat[index,:]=listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index+=1
return returnMat,classLabelVector
1
2
3
4
5
6
7
8
9
10
11
12
13
14
运行结果

array([[4.0920000e+04, 8.3269760e+00, 9.5395200e-01],
[1.4488000e+04, 7.1534690e+00, 1.6739040e+00],
[2.6052000e+04, 1.4418710e+00, 8.0512400e-01],
…,
[2.6575000e+04, 1.0650102e+01, 8.6662700e-01],
[4.8111000e+04, 9.1345280e+00, 7.2804500e-01],
[4.3757000e+04, 7.8826010e+00, 1.3324460e+00]])
1
2
3
4
5
6
7
分析数据
分析数据,可以让我们更加直观的看到数据的特性,我们使用matplotlib.pyplot模块进行特征分析。我们可以使用色彩或者大小标记不同样本的分类。这样更加直观。scatter支持这样一种要求,具体的使用方式,我会在后文python函数小结中总结。

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0np.array(datingLabels),15.0np.array(datingLabels))
plt.show()
1
2
3
4
5
6
7

上面两图分别是第二特征和第三特征,第一特征和第二特征展示的类别区间。可见,图二我们可以比较直观的分出类别区间

归一化
归一化是数据处理中一个非常重要的概念。通过对距离公式的定义,我们知道,数字差值最大的属性对于距离结果影响最大,但是所有属性都应该是等权重的。我们可以通过归一化实现等权重。所谓的归一化就是把原先的数值范围压缩到一个统一的很小的范围区间内。一般选择压缩在0到1之间,或者-1到1之间。实现起来也很简单。用下面的公式。

newvalue=(oldvalue-min)/(max-min)

max和min分别是最大特征值,最小特征值,也就是value所在列的最大值最小值。

归一化python实现
def autoNorm(dataSet):
minVals=dataSet.min(0)
maxVals=dataSet.max(0)
ranges=maxVals-minVals
normDataSet=zeros(shape(dataSet))
m=dataSet.shape[0]
normDataSet=dataSet-tile(minVals,(m,1))
normDataSet=normDataSet/tile(ranges,(m,1))
return normDataSet,ranges,minVals
1
2
3
4
5
6
7
8
9
执行结果

array([[0.44832535, 0.39805139, 0.56233353],
[0.15873259, 0.34195467, 0.98724416],
[0.28542943, 0.06892523, 0.47449629],
…,
[0.29115949, 0.50910294, 0.51079493],
[0.52711097, 0.43665451, 0.4290048 ],
[0.47940793, 0.3768091 , 0.78571804]])
1
2
3
4
5
6
7
测试分类器
错误率=错误次数/测试总次数

def datingClassTest():
hoRatio=0.10
datingDataMat,datingLabels=file2matrix(‘datingTestSet2.txt’)
normMat,ranges,minVals=autoNorm(datingDataMat)
m=normMat.shape[0]
numTestVecs=int(m*hoRatio)
errorCount=0.0
for i in range(numTestVecs):
classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
print(“the classifier come back with : %d,the real answer is : %d” %(classifierResult,datingLabels[i]))
if(classifierResult!=datingLabels[i]):errorCount+=1.0
print( ‘the total rate is :%f’%(errorCount/float(numTestVecs)) )
1
2
3
4
5
6
7
8
9
10
11
12
最终我的测试结果为0.05

最后就是根据建立好的分类器,写用户程序就好了。

任务实战–手写识别系统
之前上课的时候老师有给我们展示过这个数据集分类,这也是非常有名的一个开源数据集。

分类要求:将图片分为数字0-9,进行识别

完成这个任务主要在于数据处理,包括,读取每一个文件转换成当行数组,在这里每一个像素可以看出一个特征,所以一共有1024个特征列。通过该例子,我主要学会了更多地数据提取,处理的方法。

def img2vextor(filename): --读取每一个文件转换为单行数组
returnVect=zeros((1,1024))
fr=open(filename)
for i in range(32):
lineStr =fr.readline()
for j in range(32):
returnVect[0,32*i+j]=int(lineStr[j])
return returnVect
def handwritingClassTest(): --完整程序
hwLabels=[]
trainingFileList=listdir(‘trainingDigits’)
m=len(trainingFileList)
traingMat=zeros((m,1024))
for i in range(m):
fileNameStr=trainingFileList[i]
fileStr=fileNameStr.split(’.’)[0]
classNumStr=int(fileStr.split(’’)[0])
hwLabels.append(classNumStr)
traingMat[i,:]=img2vextor(‘trainingDigits/%s’ % fileNameStr)
testFileList=listdir(‘testDigits’)
errorCount=0.0
mTest=len(testFileList)
for i in range(mTest):
fileNameStr=testFileList[i]
fileStr=fileNameStr.split(’.’)[0]
classNumStr=int(fileStr.split(’
’)[0])
vectorUnderTest=img2vextor(‘testDigits/%s’ % fileNameStr)

    classifierResult=classify0(vectorUnderTest,traingMat,hwLabels,3)
    print("output:%d ,real value: %d" % (classifierResult,classNumStr))
    if (classifierResult!=classNumStr):errorCount+=1.0
print("errorcount is %d" % (errorCount))
print("errorrate is:%f" %(errorCount/float(mTest)))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
最终错误率0.010571

本章python函数小结
title函数
tile(A,n),功能是将数组A重复n次,构成一个新的数组

使用方法

b=[1,3,5]
tile(b,[2,3])
array([[1, 3, 5, 1, 3, 5, 1, 3, 5],
[1, 3, 5, 1, 3, 5, 1, 3, 5]])
1
2
3
4
argsort函数
argsort()函数是将a中的元素从小到大排列提取其对应的index(索引),然后输出到b

a=array([3,2,1,9,-1,6])
b=a.argsort()
b的输出为
array([4, 2, 1, 0, 5, 3], dtype=int64)
1
2
3
4
字典的get()方法
Python 字典(Dictionary) get() 函数返回指定键的值,如果值不在字典中返回默认值。

dict.get(key, default=None)
1
key – 字典中要查找的键。

default – 如果指定键的值不存在时,返回该默认值。

字典的sorted排序
sorted(dic,value,reverse)
1
dic为比较函数,value 为排序的对象(这里指键或键值),

reverse:注明升序还是降序,True–降序,False–升序(默认)

看了一篇非常好的sortes方法的讲解,里面涉及具体的排序函数(本章算法会使用)甚至多维排序,链接: https://blog.csdn.net/dongtingzhizi/article/details/12068205

文件的readlines()
特点:一次性读取整个文件;自动将文件内容分析成一个行的列表。

关于matplotlib.pyplot.scatter()
散点图可以根据标签不同配置不同颜色

https://www.jianshu.com/p/05eeb51c5288

决策树

决策树简介
决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是 if-then 规则的集合,也可以认为是定义在特征空间与类空间上的条件概率分布。 下图就是一个简单的决策树。它由判断模块、终止模块、分支组成。

构造决策树
为了需要构造决策树,我们需要找到当前数据集在划分数据时,起决定性作用的特征,我们选择这样一个特征,划分出最好的结果。

构造决策树伪代码如下:

def createBranch():
检测数据集中的所有数据的分类标签是否相同:
If so return 类标签
Else:
寻找划分数据集的最好特征(划分之后信息熵最小,也就是信息增益最大的特征)
划分数据集
创建分支节点
for 每个划分的子集
调用函数 createBranch (创建分支的函数)并增加返回结果到分支节点中
return 分支节点

相关概念

熵: 熵指的是体系的混乱的程度,也被定义为信息的期望值。计算熵的公式。熵越高,则说明混合的数据越多。

信息增益: 在划分数据集前后信息发生的变化称为信息增益。

python计算香农熵,自己跟着书上实现了一下代码

def calcShannonEnt(dataSet):
numEntries=len(dataSet)
labelCounts={}
for featVec in dataSet:
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)
return shannonEnt

通过该函数可以计算出书中例子数据集的熵为0.9709505944546686

划分数据集

def splitDataSet(dataSet,axis,value):
    retDataSet=[]
    for featVec in dataSet:
        if featVec[axis]==value:
            reducedFeatVec=featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet

该函数根据 划分出dataSet中第axis列的值为value的dataSet子集

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)   #se可以对列表去重
        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
        if (infoGain>bestInfoGain):
            bestInfoGain=infoGain
            bestFeature=i
    return bestFeature

寻找最好的划分特征就是遍历将按每个特征划分一遍数据集,找出信息增益最大的特征返回。

信息增益=原信息熵-划分后的信息熵。

递归构建树
如果数据集已经处理了所有的属性,但类标签依然不是唯一的,我们一般采用多数表决的方法。即找数据集中实例中,类比例最大的类。这个算法和KNN算法中的投票表决类似。

def createTree(dataSet,labels):
    classList=[example[-1] for example in dataSet]
    if classList.count(classList[0])==len(classList):
        return classList[0]
    if len(dataSet[0])==1:
        return majorityCnt(classList)
    bestFeature=chooseBestFeatureToSplit(dataSet)   #找到最好分类特征索引值
    bestFeatureLabel=labels[bestFeature]    #转换为标签名
    myTree={bestFeatureLabel:{}}        #用字典表示决策树,key表示父节点(判断节点),value也是一个字典,里面对元素表示其子节点,可以是最叶子节点,或者下一个判断节点
    del(labels[bestFeature])
    featValues=[example[bestFeature] for example in dataSet]
    uniqueVals=set(featValues)
    for value in uniqueVals:
        subLabels=labels[:]   #python 对于list是传引用,因此,需要建立拷贝
        myTree[bestFeatureLabel][value]=createTree(splitDataSet(dataSet,bestFeature,value),subLabels)
    return myTree
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
输出结果为

{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
1

绘制决策树
绘制决策树的目的是为了更加直观的展示决策树。实际在分类过程中是不需要的。因为python中没有专门画树图的模块,因此,需要使用的matplotlib结合annotate注释展示,树形图。其实还挺繁琐的。

以下是我绘制的结果,代码参考,《机器学习实战》

存储决策树
使用Python模块pickle序列化对象,就可以将序列化对象保存在磁盘上了。书上的部分不适用python3。根据相关错误信息,进行调整。

def storeTree(inputTree,filename):
import pickle
fw = open(filename,‘wb’) #以二进制写模式打开文件,注意必须要是二进制模式
pickle.dump(inputTree,fw)
fw.close()

def grabTree(filename):
import pickle
fr = open(filename,‘rb’)

执行完写后,会看到目录下多出一个txt文件。这样决策树就被保存下来了,下一次使用决策树分类的时候,就不需要重新构建决策树了。

实例练习–预测隐形眼镜类型
(1) 收集数据:提供的文本文件。
(2) 准备数据:解析tab键分隔的数据行。
(3) 分析数据:快速检查数据,确保正确地解析数据内容,使用createPlot()函数绘制 最终的树形图。
(4) 训练算法:使用createTree()函数。
(5) 测试算法:编写测试函数验证决策树可以正确分类给定的数据实例。
(6) 使用算法:存储树的数据结构,以便下次使用时无需重新构造树。

通过本例子的学习,学到了使用列表生成器极其简单的读取文件数据生成数据集的方法

fr=open(‘lenses.txt’)
lenses=[inst.strip().split(’\t’) for inst in fr.readlines()]

生成的决策树
{‘tearRate’: {‘normal’: {‘astigmatic’: {‘no’: {‘age’: {‘young’: ‘soft’,
‘pre’: ‘soft’,
‘presbyopic’: {‘prescript’: {‘myope’: ‘no lenses’, ‘hyper’: ‘soft’}}}},
‘yes’: {‘prescript’: {‘myope’: ‘hard’,
‘hyper’: {‘age’: {‘young’: ‘hard’,
‘pre’: ‘no lenses’,
‘presbyopic’: ‘no lenses’}}}}}},
‘reduced’: ‘no lenses’}}

本章python函数小结
List count()方法
count() 方法用于统计某个元素在列表中出现的次数。

list.count(obj)
obj – 列表中统计的对象。

python中的del
del语句作用在变量上,而不是数据对象上 。 python有GC机制 ,只有作用在数据上的引用数为零时,数据对象才会被清楚

https://www.jianshu.com/p/ac0ceeaa8bd8

python中的append和extend
a=[1,2]
b=[3,4]
a.append(b)
a

[1, 2, [3, 4]]

a=[1,2]
b=[3,4]
a.extend(b)
a

[1, 2, 3, 4]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值