机器学习实践 学习笔记2 Classifying with k-Nearest Neighbors

k-近邻算法(k-Nearest Neighbors,kNN)

工作原理:

knn算法属于监督类型算法。首先我们有样本训练集,知道每一条数据的分类。继而,我们输入没有分类的新数据,将新数据的每个特征与样本集中的对应项进行比较,提取样本集中最相思的数据,这样我们可以获得该数据的分类。一般来说,我们只选择样本集中前k个最相似的数据,通常k不大于20.最后,选择k个相似数据中出现最多的分类,作为新数据的分类,此为k近邻算法。


优点:

精度高,对异常数值不敏感,无数据输入假定。

缺点:计算复杂度高,空间复杂度高。无法给出任何数据的基础结构信息,因此我们也无法知晓平均
实例样本和典型实例样本具有什么特征

适用数据范围:数值型,标称型(numeric values,nominal values)


伪代码:

(1)计算样本数据集中的点与当前带分类数据的点之间的距离(计算相似程度)

(2)按照距离递增排序

(3)选取与当前距离最小的前K个点

(4)确定k个点所在类别的出现频率

(5)返回出现频率最高的类别作为预测分类


python代码:

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


#intX:待分类数据(向量),dataSet,labels:样本训练集,k
def classi0(intX, dataSet, labels, k):
	dataSetSize = dataSet.shape[0]#训练集大小
	diffMat = tile(intX,(dataSetSize,1)) - dataSet#把待分类数据向量复制成与训练集等阶,对应项求差
	sqDiffMat = diffMat**2#各项平方
	sqDistances = sqDiffMat.sum(axis=1)#axis=1,将一个矩阵的每一行向量相加
	distances = sqDistances**0.5#开方,求出距离
	sortedDistIndicies = distances.argsort()#从小到大排序,返回数组的索引
	classCount = {}
	for i in range(k):#遍历前K个样本训练集
		voteILabel = labels[sortedDistIndicies[i]]#对应分类
		classCount[voteILabel] = classCount.get(voteILabel,0) + 1#计数
	sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)#排序
	return sortedClassCount[0][0]#返回统计最多的分类

其中,距离的计算使用了欧式几何:



测试分类器:

错误率是常用的检验分类器的方法:

通过大量已知分类的测试数据,计算出分类器给出错误答案的次数除以测试的总次数。


准备数据:python获取文本数据:

40920 8.3269760.953952 largeDoses
14488 7.1534691.673904 smallDoses
26052 1.4418710.805124 didntLike

假设文本数据保存在datingTestSet.txt文本中

def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()#获取所有数据,以行为单位切割
    numberOfLines = len(arrayOLines)
    returnMat = zeros((numberOfLines,3))#构建矩阵,以0填充
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()
        listFromLine = line.split('\t')#以tab分割为数组
        returnMat[index,:] = listFromLine[0:3]#copy数据
        classLabelVector.append(listFromLine[-1])#保存对应的分类
        index += 1
    return returnMat,classLabelVector

分析数据:

使用Matplotlib创建散点图分析数据:

import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)#add_subplot(mnp)添加子轴、图。subplot(m,n,p)或者subplot(mnp)此函数最常用:subplot是将多个图画到一个平面上的工具。其中,m表示是图排成m行,n表示图排成n列,也就是整个figure中有n个图是排成一行的,一共m行,如果第一个数字是2就是表示2行图。p是指你现在要把曲线画到figure中哪个图上,最后一个如果是1表示是从左到右第一个位置。
ax.scatter(datingDataMat[:,1], datingDataMat[:,2],15.0*array(map(int,datingLabels)),15.0*array(map(int,datingLabels)))#以第二列和第三列为x,y轴画出散列点,给予不同的颜色和大小
#scatter(x,y,s=1,c="g",marker="s",linewidths=0)
#s:散列点的大小,c:散列点的颜色,marker:形状,linewidths:边框宽度
plt.show()

机器学习实践 学习笔记2 Classifying with k-Nearest Neighbors_第1张图片


准备数据:

归一化数据值

为了减少特征值之间因度量不同带来权重的偏差,需要将数据归一化。所谓的归一化,是讲数值范围处理在0~1或-1~1之间。

可以用如下公式:

newValue = (oldValue-min)/(max-min)

max和min分别是该项数据集特征中的最大值和最小值。

据此可写出归一化函数

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


测试算法:

通常只用90%的数据来训练分类器,剩余数据去测试分类器,获取正确/错误率。

def datingClassTest():
    hoRatio = 0.10
    datingDataMat,datingLabels = file2matrix('datingTestSet.txt')
    normMat, ranges, minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classi0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print "the classifier came back with: %s, the real answer is: %s" %  (classifierResult, datingLabels[i])
        if (classifierResult != datingLabels[i]): errorCount += 1.0
    print "the total error rate is: %f" % (errorCount/float(numTestVecs))


实例:数字识别系统

(1)收集数据

提供文字的文本文件,大小都为32*32,每个数字大概有200个样本

机器学习实践 学习笔记2 Classifying with k-Nearest Neighbors_第2张图片

(2)准备数据,把数据转换为上文中分类器可用的一维vector向量,从32*32变为1*24

def img2vector(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

(3)测试算法

def handwritingClassTest():
	hwLabels = []
	trainingFileList = listdir('trainingDigits')#样本数据
	m = len(trainingFileList)
	trainingMat = zeros((m,1024))
	for i in range(m):
		fileNameStr = trainingFileList[i]
		fileStr = fileNameStr.split('.')[0]
		classNumStr = int(fileStr.split('_')[0])
		hwLabels.append(classNumStr)
		trainingMat[i,:] = img2vector('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 = img2vector('testDigits/%s' % fileNameStr)
		classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
		print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr)
		if (classifierResult != classNumStr): errorCount += 1.0
	print "\nthe total number of errors is: %d" % errorCount
	print "\nthe total error rate is: %f" % (errorCount/float(mTest))





你可能感兴趣的:(Machine,learning)