您的位置:首页 > 其它

机器学习实战笔记:KNN

2014-01-09 18:08 309 查看
1 KNN算法:

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

      缺点:计算复杂度高,空间复杂度高

      适用数据范围:数值型和标称型

      算法原理:先给定训练集A,当一个测试集样本t,选择t与A中距离最近的k个训练样本(k通常不大于20),选择这些训练样本中出现次数最多的标签作为t的新标签。

2 采用R实现的代码:

library(hash)
KNN=function(testVec,trainMat,trainLables,k){#分类算法
#testVec=c(0,0);
#trainMat=matrix(c(1,1.1,1,1,0,0,0,0.1),4,2,byrow=T);
#trainLables=c('A','A','B','B');
#k=3;
testMat=matrix(testVec,nrow(trainMat),length(testVec));
diffMat=testMat-trainMat;
#sqDiffMat=diffMat%*%t(diffMat);
#digEle=diag(sqDiffMat);
#distances=sqrt(digEle);
sqDiffMat=diffMat**2;
distances=rowSums(sqDiffMat);
sortedDist=order(distances);
classCount=hash();#hash函数
for (i in 1:k){
#i=2;
label=as.character(trainLables[sortedDist[i]]);
if(has.key(label,classCount)){#如果label存在于hash中
num=classCount[[label]]+1;
}else{
num=1;
}
classCount[label]=num;
#cat(i,label,num,'\n')
}
KLabels=values(classCount);
a=which(KLabels==max(KLabels));
names(a);
}
autoNorm=function(data){#归一化,这里是三列数据
max1=max(data[,1]);
min1=min(data[,1]);
max2=max(data[,2]);
min2=min(data[,2]);
max3=max(data[,3]);
min3=min(data[,3]);
minMat=matrix(c(min1,min2,min3),nrow(data),3,byrow=T);
range1=max1-min1;
range2=max2-min2;
range3=max3-min3;
normData=data-minMat;
normData=normData/matrix(c(range1,range2,range3),nrow(data),3,byrow=T);
normData;
}
#主程序,这里用的是《机器学习实战》第二章里的约会数据前50行
datingData=read.csv("datingTestSet2.tx",sep='\t',header=F);#数据集格式:40920  8.326976	0.953952	3前三个是特征,最后一个是分类
NormData=autoNorm(datingData[,1:3]);#特征的归一化
testVec=c(65000,10,1)#测试样本特征
testLabels=1;#测试样本分类号
label=KNN(testVec,NormData,datingData[,4],3);#测试样本的预测标号
as.numeric(label)==testLabels;#若预测成功则返回T


3 机器学习实战的python代码注释,由于不怎么会python注释一下,以备后查。

from numpy import *
import operator#运算符模块
from os import listdir
import time
def classify0(inX, dataSet, labels, k):#kNN分类器
dataSetSize = dataSet.shape[0]#行数
diffMat = tile(inX, (dataSetSize,1)) - dataSet#tile将inX扩充为dataSetSize行1倍inX列的矩阵,
sqDiffMat = diffMat**2#每个元素平方相当于multiply(diffMat,diffMat)
sqDistances = sqDiffMat.sum(axis=1)#axis=0表示列方向相加,axis=1表示行方向相加
distances = sqDistances**0.5#开方
sortedDistIndicies = distances.argsort()#.argsort对数组升序排序
classCount={}#字典map
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1#map::get(key,default=None)若key没在map里则返回default
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)#map::iteritems()返回键值对的迭代器,items()返回键值对元素,operator.itemgetter(1)指操作的对象是第二个域即value,reverse是否逆序,sorted是排序生成新的序列
return sortedClassCount[0][0]

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 file2matrix(filename):#提取'\t'为分隔符文件的数据
fr = open(filename)#只读方式打开文件
numberOfLines = len(fr.readlines())#对于结构化文件可以读取行数
returnMat = zeros((numberOfLines,3))#全零矩阵
classLabelVector = []#空list
fr = open(filename)#
index = 0
for line in fr.readlines():#readlines读取整个文件并以行构成一个列表,每行作为for的一个循环
line = line.strip()#删除开头和结尾处的空白符(包括'\n', '\r',  '\t',  ' ')
listFromLine = line.split('\t')#以\t为分割,返回一个list
returnMat[index,:] = listFromLine[0:3]#替代每行
classLabelVector.append(int(listFromLine[-1]))#使用负下标选取最后一列
index += 1
return returnMat,classLabelVector

def autoNorm(dataSet):#归一化,矩阵化操作
minVals = dataSet.min(0)#返回最高维的最小值,注意数组a.shape返回(2,3,4)表示最底层数组4个元素,然后3个一维数组,2个二维数组,所以这里最高维指2那个#这里假设dataSet是1000行3列的数组,那么min(0)返回三列的最小值
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))#生成一个和dataset大小一致的全零数组
m = dataSet.shape[0]#返回最高维的元素数目
normDataSet = dataSet - tile(minVals, (m,1))
normDataSet = normDataSet/tile(ranges, (m,1))#归一化
return normDataSet, ranges, minVals#返回归一化矩阵,max-min,min

def datingClassTest():#约会数据测试
hoRatio = 0.50#测试集的比例
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)#1~numTestVecs行是测试集,numTestVecs~m行是训练集
print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])
if (classifierResult != datingLabels[i]): errorCount += 1.0
print "the total error rate is: %f" % (errorCount/float(numTestVecs))
print errorCount#打印错误率

def img2vector(filename):#32×32维的图片矩阵用1×1024的向量表示
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():#手势识别测试程序
start=time.clock()
hwLabels = []
trainingFileList = listdir('trainingDigits') #import os里的listdir是列出目录下的文件名 #训练集
m = len(trainingFileList)
trainingMat = zeros((m,1024))#m×1024维的全零矩阵
for i in range(m):
fileNameStr = trainingFileList[i]#获取文件名,如9_45.txt表示该图片分类是9,它是数字9的第45个实例
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]     #take off .txt
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))
print("Time used:",time.clock()-start)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息