k近邻是一种常用的分类与回归算法,简单直观。
原理:
k近邻模型
模型有3个要素——距离度量方法、k值的选择和分类决策规则。
模型
当3要素确定的时候,对任何实例(训练或输入),它所属的类都是确定的,相当于将特征空间分为一些子空间。
距离度量
对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的博客)