k_近邻算法

from numpy import *
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import operator


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


group, labels = createDataSet()


def classify0(inX, dataSet, labels, k):
    '''
    分类器
    :param inX: 用于分类的输入向量
    :param dataSet: 输入的训练样本集
    :param labels: 标签向量,标签向量元素数目和矩阵dataSet的行数相同
    :param k: 用于选择最近邻居的数目
    :return: 排序首位的label


    对未知类别属性的数据集中的每个点依次执行以下操作:
    1、计算已知类别数据集中的点与当前点之间的距离
    2、按照距离递增次序排序
    3、选取与当前点距离最小的 k 个点
    4、确定前 k 个点所在类别的出现频率
    5、返回前 k 个点出现频率最高的类别作为当前点的预测分类
    '''

    # ndarray.shape 数组维度的元组,ndarray.shape[0]表示数组行数,ndarray.shape[1]表示列数
    dataSetSize = dataSet.shape[0]
    # print(dataSetSize)

    # 将输入的 inX(1*2) 进行扩展,扩展为 4*2 矩阵,使其与训练样本集中的数据(4*2)矩阵作减法
    # 前面用tile,把一行inX变成4行一模一样的(tile有重复的功能,dataSetSize是重复4遍,后面的1保证重复完了是4行,而不是一行里有四个一样的),然后再减去dataSet,是为了求两点的距离,先要坐标相减,这个就是坐标相减
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet
    # print(diffMat)

    # 上一行得到了坐标相减,然后这里要(x1-x2)^2,要求乘方
    # 将 差值矩阵 的每一项乘方
    sqDiffMat = diffMat ** 2

    # axis=1 计算出每一行的和
    # axis=0表示按列相加,axis=1表示按照行的方向相加,这样得到了(x1-x2)^2+(y1-y2)^2
    sqDistances = sqDiffMat.sum(axis=1)

    # 开根号,这个之后才是距离
    distances = sqDistances ** 0.5

    # argsort是排序,将元素按照由小到大的顺序返回下标,比如([3,1,2]),它返回的就是([1,2,0])
    sortedDistIndicies = distances.argsort()  # 返回的list

    # classCount 字典用于类别统计
    classCount = {}

    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    soredClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return soredClassCount[0][0]


ans = classify0([0, 0], group, labels, 3)


"""
在约会网站上使用 kNN
1.收集数据: 提供文本文件
2.准备数据: 使用 Python 解析文本文件
3.分析数据: 使用 Matplotlib 画二维扩散图
4.训练算法: 此步骤不适合 k-近邻算法
5.测试算法:
    测试样本与非测试样本的区别在于:
        测试样本是已经完成分类的数据,如果预测分类与实际类别不用,则标记为一个错误
6.使用算法: 产生简单的命令行程序,然后可以输入一些特征数据以判断对方是否为自己喜欢的类型
"""
def file2matrix(filename):
    '''
        将文本记录转换NumPy的代码
    :param filename: 文件名
    :return: 转换后的矩阵
    '''
    fr = open(filename)

    # 将文件内容按行读取为一个list
    arrayOLines = fr.readlines()

    # 获取list的长度,即文件内容的行数
    numberOfLines = len(arrayOLines)

    # 生成numberOfLines*3 的零矩阵
    returnMat = np.zeros((numberOfLines, 3))

    # 分类标签 向量
    classLabelVector = []

    #
    index = 0

    # 遍历读入文件的每一行
    for line in arrayOLines:

        #截取调所有的回车符
        line = line.strip()

        # 将 line 以空格符进行分割,分开后赋给listFromLine
        listFromLine = line.split('\t')

        # 将index 行所有元素替换为 listFromLine 中的 [0:3] ,其中[0:3]是左闭右开
        returnMat[index,:] = listFromLine[0:3]

        # 分类标签向量 list 中添加 listFromLine 中的最后一项
        # labels = {'didntLike': 1, 'smallDoses': 2, 'largeDoses': 3}
        # classLabelVector.append(labels[listFromLine[-1]])
        classLabelVector.append(int(listFromLine[-1]))

        index +=1

    return returnMat,classLabelVector



datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')

def get_figure(datingDataMat,datingLabels):
    '''
    直接浏览文本文件方法非常不友好,一般会采用图形化方式展示数据
    :param datingDataMat: 
    :param datingLabels: 
    :return: 
    '''

    fig = plt.figure()
    # “111”表示“1×1网格,第一子图”,“234”表示“2×3网格,第四子图”。
    ax =fig.add_subplot(111)

    # 使用 datingDataMat 矩阵的第二、第三列数据
    # 分别表示特征值“玩视频游戏所消耗时间百分比”和“每周所消费的冰淇淋公升数”
    # ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2])

    # 利用变量 datingLabels 存储的类标签属性,在散点图上绘制色彩不等,尺寸不同的点
    # scatter plot 散点图
    ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1],
               15.0 * np.array(datingLabels), 15.0 * np.array(datingLabels))
    plt.show()


get_figure(datingDataMat,datingLabels)


"""
    数据的归一化处理
"""
def autoNorm(dataSet):
    """
    方程中数字差值最大的属性对计算结果的影响最大,在处理这种不同范围的特征值时,采用数值归一化的方法
    :param dataSet: 输入的数据集
    :return: 归一化后的数据集合
    """

    # dataSet.min(0) 中的参数 0 使得函数可以从列中选取最小值,而不是选当前行的最小值
    # minVals 储存每列中的最小值
    minVals = dataSet.min(0)

    # maxVals 储存每行中的最小值
    maxVals = dataSet.max(0)

    # 求得差值
    ranges = maxVals - minVals

    #
    normDataSet = np.zeros(np.shape(dataSet))

    # 将数据集 dataSet 的行数放入m
    m = dataSet.shape[0]

    # 归一化
    normDataSet = dataSet - np.tile(minVals,(m,1))
    normDataSet = normDataSet / np.tile(ranges,(m,1))
    return normDataSet,ranges,minVals



# normDataSet,ranges,minVals = autoNorm(datingDataMat)
# print(normDataSet)
# print(ranges)
# print(minVals)


def datingClassTest():

    # 选择10% 的数据作为测试数据,90%的数据作为训练数据
    hoRatio =0.10

    #将输入的文件转换为 矩阵形式
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')

    #数据归一化处理
    normDataSet,ranges,minVals = autoNorm(datingDataMat)

    #计算测试向量的数量
    m = normDataSet.shape[0]
    numTestVecs = int(m*hoRatio)

    #错误数量统计
    errorCount = 0.0
    # 遍历 测试向量
    for i in range(numTestVecs):

        # #取数据集 的后10%为测试数据,错误率为5%

        # 调用 classify0() 函数
        # 以归一化后的的数据集 normDataSet 的第 i 行数据作为测试数据,
        # 以 numTestVecs:m 行数据作为训练数据,
        # datingLabels[numTestVecs:m] 作为标签向量,
        # 选择最近的 3 个邻居
        classifierResult = classify0(normDataSet[i, :], normDataSet[numTestVecs:m, :],datingLabels[numTestVecs:m], 3)

        #打印 预测结果 与 实际结果
        print("the classifier came back with: %d," "the real answer is: %d " % (classifierResult, datingLabels[i]))


        # # -----------------------------------------------------------------------
        # # 取 数据集 的后 10% 作为测试数据,错误率为 6%
        # classifierResult = classify0(normDataSet[m-numTestVecs+i, :], normDataSet[:m-numTestVecs, :],
        #                              datingLabels[:m-numTestVecs], 3)
        #
        # print("the classifier came back with: %d,"
        #       "the real answer is: %d " % (classifierResult, datingLabels[m-numTestVecs+i]))
        #
        # if classifierResult != datingLabels[m-numTestVecs+i]:
        #     errorCount += 1.0
        # # -----------------------------------------------------------------------


        # 当预测失败时,错误数量 errorCount += 1
        if classifierResult != datingLabels[i]:
            errorCount += 1.0
    print("the total error rate is : %f" % (errorCount/float(numTestVecs)))

# datingClassTest()

def classifyPerson():
    # 预测结果 list
    resultList = ['not at all', 'in small doses', 'in large doess']

    # 获取用户输入
    percentTats = float(input('percentage of time spent playing video games?'))
    iceCream = float(input('liters of ice cream consumed per year?'))
    ffMile = float(input('frequent flier miles earned per year?'))

    # 归一化数据集
    normDataSet, ranges, minVals = autoNorm(datingDataMat)

    # 将用户输入转化为一个 Matrix
    inArr = np.array([ffMile, percentTats, iceCream])

    # 调用 classify0() ,将用户输入矩阵归一化后进行运算
    classifierResult = classify0((inArr - minVals)/ranges, normDataSet, datingLabels, 3)

    # 打印预测结果
    print('You will probably like this person:', resultList[classifierResult-1])

classifyPerson()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值