k-近邻算法

算法原理

将每个新数据与样本集中的每个特征进行比较,计算距离。把距离递增排序选取前k个距离最小的点,并统计前k个点的标签的出现频率,将出现频率最高的标签作为当前数据的预测分类。

此处使用欧氏距离公式:
欧氏距离公式

代码:

import numpy as np
import operator
import matplotlib
import matplotlib.pylab as plt


"""
函数说明:
    创建数据集的例子

参数:
    无
    
返回值:
    group:数据集
    labels:标签类别
"""


def createDataSet():
    group = np.array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
    labels = ['A', 'A', 'B', 'B']
    return group, labels


"""
函数说明:
    kNN分类器,k-近邻算法
    计算已知类别点和当前点的距离,从前k个距离最小的点中,选取出现频率最高的类别作为当前点的类别
    
参数:
    inx:    用于分类的数据,测试集
    dataset:    训练样本集
    labels:     标签类别
    k:      选取最近邻近的数目
    
返回值:
    sortClassCount[0][0]:       分类结果
"""


def classify0(inx, dataSet, labels, k):
    # 读取矩阵第一维的长度,即行数
    # 注意是shape[0],不是shape(0)
    dataSetSize = dataSet.shape[0]
    # 把inX复制成和dataSet相同行数的矩阵, 并作差
    diffMat = np.tile(inx, (dataSetSize, 1)) - dataSet
    # 将作差的结果平方
    sqDiffMat = diffMat**2
    # 矩阵每行相加
    sqDistances = sqDiffMat.sum(axis=1)
    # 结果开方
    distance = sqDistances**0.5
    # 返回排序的下表索引值
    sortedDistIndicies = distance.argsort()
    # 选取前k个距离最小的点并用classCount记录
    classCount = {}
    for i in range(k):
        # 距离最小的标签
        voteIlabel = labels[sortedDistIndicies[i]]
        # 若标签存在则在标签基础上+1,若不存在返回默认值0,即0+1
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1

    print(classCount)
    sortClassCount = sorted(classCount.items(),
                              key=operator.itemgetter(1), reverse=True)
    print(sortClassCount)
    return sortClassCount[0][0]


"""
函数说明:
    打开文件,读取数据信息
    
参数:
    filename:   文件名
    
返回值
    returnMat:  特征矩阵
    classLabelVector:   类别向量
"""


def file2matrix(filename):
    fr = open(filename)
    # 读取文件所有内容,保存在列表中
    arrayOLines = fr.readlines()
    numberOfLine = len(arrayOLines)
    # 创建numberOfLines行,3列的0矩阵
    returnMat = np.zeros((numberOfLine, 3))
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()
        listFromLine = line.split()
        # 将数据的前3列进行提取保存在returnMat矩阵中,也就是特征矩阵
        returnMat[index, :] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat, classLabelVector


"""
函数说明:
    归一化数值,将特征值转化为0~1区间内的值
    公式:newValue = (oldValue - min) / (max - min)
    
参数:
    dataSet:    特征矩阵
    
返回值:
    normDataSet:    归一化后的特征矩阵
    ranges:     数据范围
    minVals:    最小值
"""


def autoNorm(dataSet):
    # 参数 0 可以使函数从列中选取最小值,而不是行
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    # 创建和 dataset 行列相同的矩阵
    normDataSet = np.zeros(np.shape(dataSet))
    # 获取 datashape 的行数
    m = dataSet.shape[0]
    # 原始值减去最小值
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    # 差值除以ranges
    normDataSet = normDataSet/np.tile(ranges, (m, 1))
    return normDataSet, ranges, minVals


"""
函数说明:
    分类器测试
    
参数:
    无
    
返回值:
    无
"""


def datingClassTest():
    # hoRatio 表示取10%的数据用来测试
    hoRatio = 0.1
    #
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    # 数据归一化
    normMat, ranges, minvals = autoNorm(datingDataMat)
    # m为归一化后矩阵的行数
    m = normMat.shape[0]
    # numTestVecs 是测试数据的行数
    numTestVecs = int(m*hoRatio)
    # 错误次数
    errorCount = 0.0
    for i in range(numTestVecs):
        # 前 numTestVecs 个数据作为测试集,剩下的作为训练集
        # normMat[i, :] 返回 normMat 矩阵第i行的全部
        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)))


# group, labels = createDataSet()
# datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
#
# fig = plt.figure()
# ax = fig.add_subplot(111)
# ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2], 15.0*np.array(datingLabels), 15.0*np.array(datingLabels))
# plt.show()
datingClassTest()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值