机器学习实战笔记:KNN

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)


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值