【机器学习实战】2. k-近邻算法

https://github.com/muyimo/MachineLearningAction.git

使用knn算法采用测量不同特征之间的距离来分类

优点 精度高,对异常值不敏感,无数据输入假定
缺点:计算复杂度高、空间复杂度高
使用数据范围:数值型和标称型

工作原理:
  • 存在训练样本集(数据+标签)
  • 输入无标签新数据,将新数据每个特征与样本集特征比较
  • 提取k(<20)个样本集中最相似(近邻)数据的分类标签
  • 统计出现次数最多的分类,作为新分类

k-近邻算法的一般流程
  1. 收集数据:任何方法
  2. 准备数据:距离计算需要的数值,最好是结构化数据格式
  3. 分析数据:任何方法
  4. 训练算法:不适用k-近邻
  5. 测试算法:计算错误了
  6. 使用算法:1)需要输入样本数据和结构化的输出结果
2)运行k-近邻算法判定输入数据类别
3)执行后续处理
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 18/3/1 下午1:25
# @Author  : cicada@hole
# @File    : kNN.py
# @Desc    : k-近邻算法的python实现
# @Link    :


# 导入数据
from numpy import *
import operator # 运算符模块
import matplotlib.pyplot as plt
from os import listdir #列出目录的文件名

def createDataSet():
    group = array([
        [1.0, 1.1],
        [1.0, 1.0],
        [0, 0],
        [0, 0.1]
    ]) # 创建4*2矩阵
    labels = ['A', 'A', 'B', 'B'] # 对应标签
    return group, labels

# k-近邻算法
# (输入向量,输入样本集,标签,最近邻居的数目)
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0] # 4 shape为元祖(4,2)

    # 1. 计算当前点与已知点的距离
    diffMat = tile(inX, (dataSetSize,1)) - dataSet # 计算点之间的差 tile 将输入点 inX行重复4遍,列重复一遍
    sqDiffMat = diffMat**2  # 取平方
    sqDistance = sqDiffMat.sum(axis=1) # 1把该行相加,0把该列相加
    distances = sqDistance**0.5
    sortedDistIndicies = argsort(distances) #将距离升序排列
    # print(sortedDistIndicies)

    classCount={}
    # 2. 选择距离最小的k个点
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1

    # 3. 排序
    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)) # 文件行数*3 矩阵
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()
        listFromLine = line.split('\t') # 截取掉所有回车字符
        returnMat[index,:] = listFromLine[0:3] #前三个元素作为特征

        classLabelVector.append(int(listFromLine[-1])) # 列表元素为int
        index += 1
    return returnMat,classLabelVector

# 分析数据:使用matplotlib创建散点图
def createScatterPic(dataMat,label):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(dataMat[:,1], dataMat[:,2],
               15.0*array(label), 15.0*array(label))
    #展示第2、3列数据,第二参数:横轴纵轴长度 参数3:颜色范围序列
    plt.show()

# 归一化特征值
def autoNorm(dataSet): # 1000*3
    minVals = dataSet.min(0) # 从每列中选最小值 1*3
    maxVals = dataSet.max(0) # 从每列中选最大值
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))# 1000*3
    m = dataSet.shape[0] #行数
    normDataSet = dataSet - tile(minVals, (m,1))
    # print(dataSet,'\n', maxVals,'\n',minVals,'\n', (m,1))
    normDataSet = normDataSet/tile(ranges, (m,1))
    return normDataSet, ranges, minVals

# 分类器针对约会网站的测试代码
def datingClassTest():
    hoRatio = 0.10 # 学习率
    dataDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    normMat, ranges, minVals = autoNorm(dataDataMat) #归一化
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)  #用于测试的行数
    errorCount = 0.0
    for i in range(numTestVecs): # inX, 训练mat,训练label,k
        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 total error rate is: %f"\
          % (errorCount/float(numTestVecs)))

def classifyPersion():
    resultList = ['不喜欢','喜欢一点','非常喜欢']
    percentTats = float(input("每周玩游戏时间?"))
    ffMiles = float(input("飞行里程?"))
    iceCream = float(input("每周吃冰淇淋的磅数?"))
    dataDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    normMat, ranges, minVals = autoNorm(dataDataMat)  # 归一化
    inArr = array([ffMiles, percentTats, iceCream])
    print('---inarr',inArr,'\n',minVals)

    classifierResult = classify0((inArr - minVals)/ranges,
                                 normMat, datingLabels, 3)
    print("你对这个人的喜欢程度:",resultList[classifierResult - 1])


#-----------手写识别系统-----------

# 格式化图像为向量
def img2vector(filename):
    returnVect = zeros((1,1024)) # 1x1024向量
    fr = open(filename)
    for i in range(32): #32x32的二进制图像
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect
# 手写数字识别系统测试
def handwritingClassTest():
    hwLabels = []
    trainingFileList = listdir('digits/trainingDigits')
    m = len(trainingFileList)
    trainingMat = zeros((m, 1024)) #参数shape维度
    for i in range(m):
        fileNameStr = trainingFileList[i] # 0_0.txt
        # print(fileNameStr)
        fileStr = fileNameStr.split('.')[0]  #0_0
        classNumStr = int(fileStr.split('_')[0]) #对应的数字
        # print('-------classNum', classNumStr)
        hwLabels.append(classNumStr) #加入标签中
        trainingMat[i, :] = img2vector('digits/trainingDigits/%s'
                                       %fileNameStr) # 把图像转换为向量
    testFileList = listdir('digits/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('digits/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("\n total number of errors is: %d" %errorCount)
    print("\n total error tate is : %f" % (errorCount/float(mTest)))


def test():

    # group, labels = createDataSet()
    # print(group, labels)
    # print(classify0([0,0], group, labels, 3))
    # dataDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    # # createScatterPic(dataDataMat, datingLabels)
    # autoNorm(dataDataMat)

    # datingClassTest()
    # classifyPersion()
    # vect = img2vector('digits/testDigits/0_13.txt') #32x32图像转换为1x1024向量
    # print(vect[0, 0:111])
    handwritingClassTest()


if __name__ == '__main__':

    test()








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值