KNN-----k近邻算法

```

################knn

####

#计算距离--前k个最近的--投票选择分类

####


from numpy import *

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

###先保存上述文件 再import 记得切换路径到kNN文件

import kNN

group, labels=kNN.createDataSet()


#coding=UTF8

from numpy import *

import operator


def createDataSet():

    """

    函数作用:构建一组训练数据(训练样本),共4个样本

    同时给出了这4个样本的标签,及labels

    """

    group = array([

        [1.0, 1.1],

        [1.0, 1.0],

        [0. , 0. ],

        [0. , 0.1]

    ])

    labels = ['A', 'A', 'B', 'B']

    return group, labels


def classify0(inX, dataset, labels, k):

    """

    inX 是输入的测试样本,是一个[x, y]样式的

    dataset 是训练样本集

    labels 是训练样本标签

    k 是top k最相近的

    """

    # shape返回矩阵的[行数,列数],

    # 那么shape[0]获取数据集的行数,

    # 行数就是样本的数量

    dataSetSize = dataset.shape[0]


    """

    下面的求距离过程就是按照欧氏距离的公式计算的。

    即 根号(x^2+y^2)

    """

    # tile属于numpy模块下边的函数

    # tile(A, reps)返回一个shape=reps的矩阵,矩阵的每个元素是A

    # 比如 A=[0,1,2] 那么,tile(A, 2)= [0, 1, 2, 0, 1, 2]

    # tile(A,(2,2)) = [[0, 1, 2, 0, 1, 2],

    #                  [0, 1, 2, 0, 1, 2]]

    # tile(A,(2,1,2)) = [[[0, 1, 2, 0, 1, 2]],

    #                    [[0, 1, 2, 0, 1, 2]]]

    # 上边那个结果的分开理解就是:

    # 最外层是2个元素,即最外边的[]中包含2个元素,类似于[C,D],而此处的C=D,因为是复制出来的

    # 然后C包含1个元素,即C=[E],同理D=[E]

    # 最后E包含2个元素,即E=[F,G],此处F=G,因为是复制出来的

    # F就是A了,基础元素

    # 综合起来就是(2,1,2)= [C, C] = [[E], [E]] = [[[F, F]], [[F, F]]] = [[[A, A]], [[A, A]]]

    # 这个地方就是为了把输入的测试样本扩展为和dataset的shape一样,然后就可以直接做矩阵减法了。

    # 比如,dataset有4个样本,就是4*2的矩阵,输入测试样本肯定是一个了,就是1*2,为了计算输入样本与训练样本的距离

    # 那么,需要对这个数据进行作差。这是一次比较,因为训练样本有n个,那么就要进行n次比较;

    # 为了方便计算,把输入样本复制n次,然后直接与训练样本作矩阵差运算,就可以一次性比较了n个样本。

    # 比如inX = [0,1],dataset就用函数返回的结果,那么

    # tile(inX, (4,1))= [[ 0.0, 1.0],

    #                    [ 0.0, 1.0],

    #                    [ 0.0, 1.0],

    #                    [ 0.0, 1.0]]

    # 作差之后

    # diffMat = [[-1.0,-0.1],

    #            [-1.0, 0.0],

    #            [ 0.0, 1.0],

    #            [ 0.0, 0.9]]

    diffMat = tile(inX, (dataSetSize, 1)) - dataset


    # diffMat就是输入样本与每个训练样本的差值,然后对其每个x和y的差值进行平方运算。

    # diffMat是一个矩阵,矩阵**2表示对矩阵中的每个元素进行**2操作,即平方。

    # sqDiffMat = [[1.0, 0.01],

    #              [1.0, 0.0 ],

    #              [0.0, 1.0 ],

    #              [0.0, 0.81]]

    sqDiffMat = diffMat ** 2


    # axis=1表示按照横轴,sum表示累加,即按照行进行累加。

    # sqDistance = [[1.01],

    #              [1.0 ],

    #              [1.0 ],

    #              [0.81]]

    sqDistance = sqDiffMat.sum(axis=1)


    # 对平方和进行开根号

    distance = sqDistance ** 0.5


    # 按照升序进行快速排序,返回的是原数组的下标。

    # 比如,x = [30, 10, 20, 40]

    # 升序排序后应该是[10,20,30,40],他们的原下标是[1,2,0,3]

    # 那么,numpy.argsort(x) = [1, 2, 0, 3]

    sortedDistIndicies = distance.argsort()


    # 存放最终的分类结果及相应的结果投票数

    classCount = {}


    # 投票过程,就是统计前k个最近的样本所属类别包含的样本个数

    for i in range(k):

        # index = sortedDistIndicies[i]是第i个最相近的样本下标

        # voteIlabel = labels[index]是样本index对应的分类结果('A' or 'B')

        voteIlabel = labels[sortedDistIndicies[i]]

        # classCount.get(voteIlabel, 0)返回voteIlabel的值,如果不存在,则返回0

        # 然后将票数增1

        # 就是在字典里如果原来不存在这个key就设置这个key值为0,然后加一

        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1


    # 把分类结果进行排序,然后返回得票数最多的分类结果

    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)

    return sortedClassCount[0][0]


if __name__== "__main__":

    # 导入数据

    dataset, labels = createDataSet()

    inX = [0.1, 0.1]

    # 简单分类

    className = classify0(inX, dataset, labels, 3)

    print('the class of test sample is %s' %className)




#####################在约会网站上使用knn

def file2matrix(filename):

    """

    从文件中读入训练数据,并存储为矩阵

    """

    fr = open(filename)

    arrayOlines = fr.readlines()

    numberOfLines = len(arrayOlines)  #获取 n=样本的行数

    returnMat = zeros((numberOfLines,3))  #创建一个2维矩阵用于存放训练样本数据,一共有n行,每一行存放3个数据

    classLabelVector = []    #创建一个1维数组用于存放训练样本标签。 

    index = 0

    for line in arrayOlines:

        # 把回车符号给去掉

        line = line.strip()   

        # 把每一行数据用\t分割

        listFromLine = line.split('\t')

        # 把分割好的数据放至数据集,其中index是该样本数据的下标,就是放到第几行

        returnMat[index,:] = listFromLine[0:3]

        # 把该样本对应的标签放至标签集,顺序与样本集对应。

        classLabelVector.append(int(listFromLine[-1]))

        index += 1

    return returnMat,classLabelVector


def autoNorm(dataSet):

    """

    训练数据归一化

    """

    # 获取数据集中每一列的最小数值

    # 以createDataSet()中的数据为例,group.min(0)=[0,0]

    minVals = dataSet.min(0)

    # 获取数据集中每一列的最大数值

    # group.max(0)=[1, 1.1]

    maxVals = dataSet.max(0)

    # 最大值与最小的差值

    ranges = maxVals - minVals

    # 创建一个与dataSet同shape的全0矩阵,用于存放归一化后的数据

    normDataSet = zeros(shape(dataSet))

    m = dataSet.shape[0]

    # 把最小值扩充为与dataSet同shape,然后作差,具体tile请翻看 第三节 代码中的tile

    normDataSet = dataSet - tile(minVals, (m,1))

    # 把最大最小差值扩充为dataSet同shape,然后作商,是指对应元素进行除法运算,而不是矩阵除法。

    # 矩阵除法在numpy中要用linalg.solve(A,B)

    normDataSet = normDataSet/tile(ranges, (m,1))

    return normDataSet, ranges, minVals


def datingClassTest():

    # 将数据集中10%的数据留作测试用,其余的90%用于训练

    hoRatio = 0.10

    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')      #load data setfrom file

    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)

        print("the classifier came back with: %d, the real answer is: %d, result is :%s" % (classifierResult, datingLabels[i],classifierResult==datingLabels[i]))

        if (classifierResult != datingLabels[i]): errorCount += 1.0

    print("the total error rate is: %f" % (errorCount/float(numTestVecs)))

    print(errorCount)

```

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352