k近邻是一种常用的分类与回归算法,简单直观。
原理:
k近邻模型
模型有3个要素——距离度量方法、k值的选择和分类决策规则。
模型
当3要素确定的时候,对任何实例(训练或输入),它所属的类都是确定的,相当于将特征空间分为一些子空间。
距离度量
扫描二维码关注公众号,回复:
1506624 查看本文章
对n维实数向量空间Rn,经常用Lp距离或曼哈顿Minkowski距离。距离的度量详见博客http://blog.csdn.net/qq_36603091/article/details/78216124
k值的选择
k较小,容易被噪声影响,发生过拟合。
k较大,较远的训练实例也会对预测起作用,容易发生错误。分类决策规则
使用0-1损失函数衡量,那么误分类率是:
Nk是近邻集合,要使左边最小,右边的必须最大,
所以多数表决=经验最小化。
k近邻法的实现:
kd树
算法核心在于怎么快速搜索k个近邻出来,朴素做法是线性扫描,不可取,这里介绍的方法是kd树。
构造kd树
对数据集T中的子集S初始化S=T,取当前节点node=root取维数的序数i=0,对S递归执行:
找出S的第i维的中位数对应的点,通过该点,且垂直于第i维坐标轴做一个超平面。该点加入node的子节点。
该超平面将空间分为两个部分,对这两个部分分别重复此操作(S=S',++i,node=current),直到不可再分。
搜索效率
kd树搜索的平均时间复杂度为logN.。所以,当样本较小时,kd树搜索与暴力搜索接近;但当数据量很大,kd树搜索能节省很多搜索时间。一般来说,k维的数据,数据集超过2k时,kd树能表现的比较好。
python实现
# -*- coding: utf-8 -*- """ Created on Thu Oct 19 13:17:31 2017 @author: lizheng """ #encoding:utf-8 import csv #用于处理csv文件 import random #用于随机数 import math import operator # 函数操作 #加载数据集 def loadDataset(filename,split,trainingSet=[],testSet = []): with open(filename,"r") as csvfile: #这里如果是open("D:\Iris.txt","rb")会提示有错误 #错误为“Error: iterator should return strings, not bytes (did you open the file in text mode?)” lines = csv.reader(csvfile) dataset = list(lines) for x in range(len(dataset)-1): for y in range(4): dataset[x][y] = float(dataset[x][y]) if random.random()<split: trainingSet.append(dataset[x]) else: testSet.append(dataset[y]) #计算距离-欧氏距离 def euclideanDistance(instance1,instance2,length): distance = 0 for x in range(length): distance = pow((instance1[x] - instance2[x]),2) return math.sqrt(distance) #返回K个最近邻 def getNeighbors(trainingSet,testInstance,k): distances = [] length = len(testInstance) -1 #计算每一个测试实例到训练集实例的欧氏距离 for x in range(len(trainingSet)): dist = euclideanDistance(testInstance, trainingSet[x], length) distances.append((trainingSet[x],dist)) #对所有的距离进行排序 distances.sort(key=operator.itemgetter(1)) neighbors = [] #返回k个最近邻 for x in range(k): neighbors.append(distances[x][0]) return neighbors #对k个近邻进行合并,返回value最大的key def getResponse(neighbors): classVotes = {} for x in range(len(neighbors)): response = neighbors[x][-1] if response in classVotes: classVotes[response]+=1 else: classVotes[response] = 1 #排序 sortedVotes = sorted(classVotes.items(),key = operator.itemgetter(1),reverse =True) return sortedVotes[0][0] #计算准确率 def getAccuracy(testSet,predictions): correct = 0 for x in range(len(testSet)): if testSet[x][-1] == predictions[x]: correct+=1 return (correct/float(len(testSet))) * 100.0 def main(): trainingSet = [] #训练数据集 testSet = [] #测试数据集 split = 0.67 #分割的比例 loadDataset(r"D:\Iris.txt", split, trainingSet, testSet) print("Train set :" + repr(len(trainingSet))) print("Test set :" + repr(len(testSet))) predictions = [] k = 3 for x in range(len(testSet)): neighbors = getNeighbors(trainingSet, testSet[x], k) result = getResponse(neighbors) predictions.append(result) print( ">predicted = " + repr(result) + ",actual = " + repr(testSet[x][-1]) ) accuracy = getAccuracy(testSet, predictions) print( "Accuracy:" + repr(accuracy) + "%") if __name__ =="__main__": main()
from sklearn.neighbors import KDTree x =[[2, 3], [5, 4], [9, 6], [4, 7], [8, 1], [7, 2]] s=[[5,3]] x.extend(s) tree = KDTree(x, leaf_size=2, metric='euclidean') tree.query(x, k=3) #生成KDtree dist, ind = tree.query(s, k=7) i = ind[0][1] print("s-k-Nearest :",x[i],"didistance: ",dist[0][i])#返回S的最近邻和欧氏距离 #print(tree.query(x, k=2, return_distance=False) )
使用scikit-learn的KNN算法进行分类的一个实例
from sklearn import neighbors import numpy as np #数据集 group =np.array([[1.0,1.1],[2.0,2.1],[1.0,1.0],[0,0],[0,0.1],[0.5,0.9]]) labels = ['A','A','A','B','B','B'] knn = neighbors.KNeighborsClassifier() #训练数据集 knn.fit(group,labels) #预测 predict = knn.predict([[1,2],[3,3]]) print(predict)使用iris鸢尾花数据集 的一个实例
from sklearn.datasets import load_iris from sklearn import neighbors #查看iris数据集 iris = load_iris() print(iris) knn = neighbors.KNeighborsClassifier() #训练数据集 knn.fit(iris.data, iris.target) #预测 predict = knn.predict([[1,2,2,5]]) print (predict) print (iris.target_names[predict])
Python中常用包——sklearn主要模块和基本使用方法(Jorocco的博客)