机器学习实战笔记一—— K-近邻算法

'''
KNN 算法流程:
1、计算已知类别数据集中的点与当前点之间的距离
2、按照距离从小到大顺序排序
3、选取与当前点距离最小的k个点
4、统计前k个点所在类别的出现次数
5、出现次数最高的类别作为当前点的类别
'''

from numpy import *
from os import listdir  #列出给点目录的文件名
import operator


#创建数据集和标签
def creatDataSet():
    group=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels=['A','A','B','B']
    return group,labels


'''
KNN分类算法
inX      用于分类的输入向量
dataSet  训练集
labels   标签向量
k        选择最近邻居的数目
'''
def classify0(inX,dataSet,labels,k):

    #计算当前点与数据集中各个点的距离
    dataSetSize=dataSet.shape[0]   #shape[0]返回数据集矩阵行数, sharp[1]返回列数
    diffMat=tile(inX,(dataSetSize,1))-dataSet #将inX扩展为 dataSetSize*1(1表示1倍inX列数)  [(x1-x2),(y1-y2)]
    sqDiffMat=diffMat**2  #数组中对应元素平方 [(x1-x2)^2,(y1-y2)^2]
    sqDistances=sqDiffMat.sum(axis=1) # axis=0 按行求和,axis=1 按列求和
    distances=sqDistances**0.5

    #按距离从小到大排序
    sortedDistIndicies=distances.argsort() #argsort为排序,元素从小到大的顺序返回下标。 eg. [3,1,2] 返回的是[2,1,0]

    classCount={}

    for i in range(k):
        voteIlabel=labels[sortedDistIndicies[i]] #返回距离对应的类别
        classCount[voteIlabel]=classCount.get(voteIlabel,0) +1 #get提取字典里的元素,计算离目标点最近的K个点的类别,这个点是那个类那个类就加1
        sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)

    return sortedClassCount[0][0]
'''
对文本操作,处理样本集输入格式
输入为文件名字符串,输出为训练样本矩阵和类标签向量
'''
def file2matrix(filename):
    fr=open(filename)  #打开文件
    arrayOLines=fr.readlines()  #读取整个文件并保存为列表,每一行为列表的一个元素
    numberOfLines =len(arrayOLines) #数组的行数即为样本的个数(行数)
    returnMat=zeros((numberOfLines,3)) #创建 numberOLines*3 的0矩阵 
    classLabelVector=[] #创建一个空列表存放训练集标签
    index=0

    for line in arrayOLines:  #依次读取每行
        line=line.strip()  #去掉回车字符
        listFromLine=line.split('\t')  #每一行数据用tab分割
        returnMat[index,:]=listFromLine[0:3] #把分隔好的数据存放到数据集中
        classLabelVector.append(int(listFromLine[-1])) #把样本对应的标签放入标签集中,-1表示最后一列
        index +=1
    return returnMat,classLabelVector

#归一化样本集
def autoNorm(dataSet):
    minVals=dataSet.min(0)  #求每列最小值
    maxVals=dataSet.max(0)  #求每列最大值
    ranges=maxVals-minVals
    normDataSet=zeros(shape(dataSet))  #生成dataSet同维度的0矩阵,用来保存归一化后的数据集
    m=dataSet.shape[0]  #返回dataSet的列数
    normDataSet=dataSet-tile(minVals,(m,1))
    normDataSet=normDataSet/tile(ranges,(m,1))
    return normDataSet,ranges,minVals

#测试代码,选择多少数据测试分类器
def datingClassTest():
    hoRatio = 0.10  #从数据集中抽取100个样本作为测试集
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt') #调用函数处理数据集
    normMat,ranges,minVals=autoNorm(datingDataMat)  #归一化数据集normMat
    m=normMat.shape[0]   #统计数据集行数
    numTestVecs=int(m*hoRatio)   #测试集样本数

    errorCount=0.0   #分类错误统计

    for i in range(numTestVecs):  #对测试集进行测试
        #输入参数:normMat[i,:]为测试样本集,表示归一化后的第i行数据
        #         normMat[numTestVecs:m,:]为训练样本集,样本数量为(m-numTestVecs)个
        #         datingLabels[numTestVecs:m]为训练样本对应的标签
        classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],\
            datingLabels[numTestVecs:m],3)
        print("the classifier came back with: %d, the real answer is: %d"\
            %(classifierResult,datingLabels[i]))
        
        #如果分类结果不等于样本标签,则判断出错
        if(classifierResult != datingLabels[i]):  
            errorCount += 1.0
        
    #分类错误个数比总的测试集数
    print('the totle error rate is: %f' %(errorCount/float(numTestVecs)))
    

def classifyPerson():
    resultList = ['Not at all','In small doses','In large doses']
    percentTats = float(input('prencentage of time spent playing video games?'))
    ffMiles = float(input('frequent flier miles earned per years?'))
    iceCrean = float(input('liters of ice cream consumed per years?'))
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
    normMat,ranges,minVals = autoNorm(datingDataMat)
    inArr = array([ffMiles,percentTats,iceCrean])
    classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
    print('You will probably like this persion: ',resultList[classifierResult-1])

"""-----------------------------------------手写体测试程序-------------------------------------------"""

#将图片转换为向量
def img2vector(fliename):
    returnVect = zeros((1,1024))
    fr = open(fliename)
    for i in range(32):
        linstr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j] = int(linstr[j])
    return returnVect 

def handwritingClassTest():
    hwLabels = []  #保存标签向量
    trainingFileList = listdir('trainingDigits')  #将文件夹trainingDigits下的文件名保存在列表trainingFileList中格式为  文件名.扩展名
    m = len(trainingFileList)     #训练集目录中文件的个数
    trainingMat = zeros((m,1024))   #初始化一个2维矩阵,将训练集的所有数据放入其中

    for i in range(m):
        fileNameStr = trainingFileList[i]  #返回训练集目录中第i个文件的文件名,是字符串,不是文件的内容 eg. 4_5.txt
        filestr = fileNameStr.split('.')[0]  #以'.'分割fileNameStr,并取出第0个。 eg. fileNameStr = '4_5.txt', filestr = '4_5'
        classNumStr = int(filestr.split('_')[0])  #以'_'分割,取出第0个,并转换为int型,即为标签。  eg.   classNumStr = 4
        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 (classNumStr != classifierResult):
            errorCount += 1.0

    print('\n the total number error is: %d' %errorCount)
    print('\n the total error rate is: %f' %(errorCount/float(mTest)))
        

以下是通过调用 sklearn 实现对数据集 KNN 分类:

# -*- coding: utf-8 -*-
"""
Created on Fri Apr 20 20:04:34 2018

@author: zhangsh
"""
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn.cross_validation import train_test_split
from sklearn import preprocessing

# 1、导入数据集
'''
numpy.loadtxt(fname, dtype=, comments='#', delimiter=None, \
              converters=None, skiprows=0, usecols=None, \
              unpack=False, ndmin=0)
'''
data = np.loadtxt('datingTestSet2.txt')
m,n = data.shape
X = data[:,:3]
y = data[:,-1].reshape(m,1)

# 2、数据预处理:归一化 (0,1)
X = preprocessing.scale(X) 
X_train,X_test,y_train,y_test = train_test_split(X, y, test_size = 0.3, random_state = 40)

# 3、建立模型
knn = KNeighborsClassifier(n_neighbors = 3)  # 创建 KNN 模型
knn.fit(X_train, y_train)  # 训练

classifiedData = knn.predict(X_test) # 测试分类器

errorCount = 0.0
for i in range(classifiedData.size):
    if classifiedData[i] != y_test[i] :
        errorCount += 1
    
errorClassifiedRate = errorCount/classifiedData.size

print('分类器分类结果',classifiedData)
print('分类出错个数:',errorCount)
print('出错率:',errorClassifiedRate)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值