KNN自己封装库函数

KNN 概述

k-近邻(kNN, k-NearestNeighbor)算法是一种基本分类与回归方法,我们这里只讨论分类问题中的 k-近邻算法。

k 近邻算法实际上利用训练数据集对特征向量空间进行划分,并作为其分类的“模型”。 k值的选择、距离度量以及分类决策规则是k近邻算法的三个基本要素。

KNN 场景

电影可以按照题材分类,那么如何区分 动作片 和 爱情片 呢?

  1. 动作片:打斗次数更多
  2. 爱情片:亲吻次数更多

基于电影中的亲吻、打斗出现的次数,使用 k-近邻算法构造程序,就可以自动划分电影的题材类型。

电影视频案例

现在根据上面我们得到的样本集中所有电影与未知电影的距离,按照距离递增排序,可以找到 k 个距离最近的电影。
假定 k=3,则三个最靠近的电影依次是, He's Not Really into Dudes 、 Beautiful Woman 和 California Man。
knn 算法按照距离最近的三部电影的类型,决定未知电影的类型,而这三部电影全是爱情片,因此我们判定未知电影是爱情片。

KNN 原理

KNN 工作原理

  1. 假设有一个带有标签的样本数据集(训练样本集),其中包含每条数据与所属分类的对应关系。
  2. 输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较。
    1. 计算新数据与样本数据集中每条数据的距离。
    2. 对求得的所有距离进行排序(从小到大,越小表示越相似)。
    3. 取前 k (k 一般小于等于 20 )个样本数据对应的分类标签。
  3. 求 k 个数据中出现次数最多的分类标签作为新数据的分类。

KNN 通俗理解

给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的 k 个实例,这 k 个实例的多数属于某个类,就把该输入实例分为这个类。

KNN 开发流程

收集数据:任何方法
准备数据:距离计算所需要的数值,最好是结构化的数据格式
分析数据:任何方法
训练算法:此步骤不适用于 k-近邻算法
测试算法:计算错误率
使用算法:输入样本数据和结构化的输出结果,然后运行 k-近邻算法判断输入数据分类属于哪个分类,最后对计算出的分类执行后续处理

KNN 算法特点

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

 

 

将文本记录转换为 NumPy 的解析程序

from numpy import *

def file2matrix(filename):
    """
     Desc:
         导入训练数据
     parameters:
         filename: 数据文件路径
     return:
         数据矩阵 returnMat 和对应的类别 classLabelVector
     """
    fr = open("datingTestSet2.txt")

    arraylines = fr.readlines()
    numberofLines = len(arraylines)

    returnMat =zeros((numberofLines, 3))
    index = 0
    label = []
    for line in arraylines:
        print(line)
        # line=line.strip()
        listFromLine = line.split('\t')
        returnMat[index, :] = listFromLine[0:3]

        label.append(int(listFromLine[-1].strip('\n')))
        index = index + 1
    return returnMat,array([label])

if __name__ == '__main__':
    datingDataMat,datingLabels=file2matrix("datingTestSet2.txt")
自己封装的KNNimport numpy as np
from math import sqrt
from collections import Counter
from metrics import accuracy_score
######测试Counter 的用法
y=[0,0,0,1,1,1,3,3,3]
print(np.array(y).shape[0])==print(len(y))
print(Counter(y))
#Counter({0: 3, 1: 3, 3: 3})
print(Counter(y).most_common(2))
#[(0, 3), (1, 3)]
print(np.argsort([2,5,7,3,1]))
#[4 0 3 1 2]
class KNNClassifier:
    def __init__(self, k):
        assert k >= 1, "k must be valid"
        self.k = k
        self._X_train = None
        self._Y_train = None

    def fit(self, X_train, Y_train):
        assert X_train.shape[0] == Y_train.shape[0], \
            "The size of X_train must be equals to the size of Y-Train"
        assert self.k <= X_train.shape[0], \
            "the feature number of x must be equal to X_train"

        self._X_train = X_train
        self._Y_train = Y_train
        return self

    def predict(self, x_predict):
        return np.array([self._predict(x) for x in x_predict])

    def _predict(self, x):
        distances = [sqrt(np.sum((x_train - x) ** 2)) for x_train in self._X_train]
        nearest = np.argsort(distances)
        votes = [i for i in self._Y_train[nearest[:self.k]]]
        return Counter(votes).most_common(1)[0][0]
    def score(self,X_test,y_test):
        y_predict=self.predict(X_test)
        return accuracy_score(y_test,y_predict)


    def __repr__(self):
        return "knn(k=%d)" % self.k

在求距离时也可用向量法

def classify(inx,dataSet,labels,k = 3):
    m = dataSet.shape[0]
    diffMat = tile(inx,(m,1)) - dataSet
    squareMat = diffMat ** 2
    squareDistance = squareMat.sum(axis = 1)
    distances = squareDistance ** 0.5
    nearest = distances.argsort()
    votes = [i for i in labels[nearest[:k]]]
    return Counter(votes).most_common(1)[0][0]

 

# 2. 选择距离最小的k个点
 classCount = {}
 for i in range(k):
 # 找到该样本的类型
 voteIlabel = labels[sortedDistIndicies[i]]
 # 在字典中将该类型加一
 # 字典的get方法
 # 如:list.get(k,d) 其中 get相当于一条if...else...语句,参数k在字典中,字典将返回list[k];如果参数k不在字典中则返回参数d,如果K在字典中则返回k对应的value值
 # l = {5:2,3:4}
 # print l.get(3,0)返回的值是4;
 # Print l.get(1,0)返回值是0;
 classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
 # 3. 排序并返回出现最多的那个类型
 # 字典的 items() 方法,以列表返回可遍历的(键,值)元组数组。
 # 例如:dict = {'Name': 'Zara', 'Age': 7} print "Value : %s" % dict.items() Value : [('Age', 7), ('Name', 'Zara')]
 # sorted 中的第2个参数 key=operator.itemgetter(1) 这个参数的意思是先比较第几个元素
 # 例如:a=[('b',2),('a',1),('c',0)] b=sorted(a,key=operator.itemgetter(1)) >>>b=[('c',0),('a',1),('b',2)] 可以看到排序是按照后边的0,1,2进行排序的,而不是a,b,c
 # b=sorted(a,key=operator.itemgetter(0)) >>>b=[('a',1),('b',2),('c',0)] 这次比较的是前边的a,b,c而不是0,1,2
 # b=sorted(a,key=opertator.itemgetter(1,0)) >>>b=[('c',0),('a',1),('b',2)] 这个是先比较第2个元素,然后对第一个元素进行排序,形成多级排序。
 sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
 return sortedClassCount[0][0]
  
 # ------------------------------------------------------------------------------------------------------------------------------------------
 # 实现 classify0() 方法的第二种方式
  
 # """
 # 1. 计算距离
  
 # 欧氏距离: 点到点之间的距离
 # 第一行: 同一个点 到 dataSet的第一个点的距离。
 # 第二行: 同一个点 到 dataSet的第二个点的距离。
 # ...
 # 第N行: 同一个点 到 dataSet的第N个点的距离。
  
 # [[1,2,3],[1,2,3]]-[[1,2,3],[1,2,0]]
 # (A1-A2)^2+(B1-B2)^2+(c1-c2)^2
  
 # inx - dataset 使用了numpy broadcasting,见 https://docs.scipy.org/doc/numpy-1.13.0/user/basics.broadcasting.html
 # np.sum() 函数的使用见 https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.sum.html
 # """
 # dist = np.sum((inx - dataset)**2, axis=1)**0.5
  
 # """
 # 2. k个最近的标签
  
 # 对距离排序使用numpy中的argsort函数, 见 https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.sort.html#numpy.sort
 # 函数返回的是索引,因此取前k个索引使用[0 : k]
 # 将这k个标签存在列表k_labels中
 # """
 # k_labels = [labels[index] for index in dist.argsort()[0 : k]]
 # """
 # 3. 出现次数最多的标签即为最终类别
  
 # 使用collections.Counter可以统计各个标签的出现次数,most_common返回出现次数最多的标签tuple,例如[('lable1', 2)],因此[0][0]可以取出标签值
 # """
 # label = Counter(k_labels).most_common(1)[0][0]
 # return label
 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值