一、knn分类器简介
在模式识别领域中,最近邻居法(KNNK-近邻算法)是将在特征空间中最接近的训练样本进行分类的方法。【维基百科】
算法步骤:
1.第一步:求待测点到已知类别的数据集的距离
2.第二步:对距离进行排序(从小到大)
3.第三步:选择前面k个距离对应的点
4.第四步:统计各个类别的频数(频率)
5.第五步:将出现频率(频率)最大的类别作为测试点的类别。
需要注意的是:K的选择很关键
二、算法实现
python版本1(有详细的中文注释)
#coding:utf-8
import kNN1
from numpy import *
#dataSet, labels = kNN1.createDataSet()
#创建一个矩阵,每一行代表一个样本,这里有4个样本
dataSet = array([[1.0, 0.9], [1.0, 1.0], [0.1, 0.2], [0.0, 0.1]])
#创建类别标签,有2类,4个样本
labels = ['1', '1', '0', '0']
testX = array([1.2, 1.0])
newInput = testX
k = 3
print 'labels:',labels #1xM: 1x4
print 'dataSet:',dataSet #MxN: 4x2
print 'newInput',newInput #1xN: 1x2
print "###############"
##step 1 计算待测试的样本到所有已标记的样本的欧式距离
#样本个数
numSamples = dataSet.shape[0]
print 'numSamples:',numSamples
#将newInput向量构造出(重复numSamples次),然后和已标记样本作差
diff = tile(newInput, (numSamples, 1)) - dataSet #diff: 4x1
print 'diff:',diff
#对每个元素进行平方操作
squaredDiff = diff ** 2
print 'squaredDiff:',squaredDiff
#对每行进行求和操作
squaredDist = sum(squaredDiff, axis = 1)
print 'squaredDist:',squaredDist
#得到待测样本到所有已标记的样本的距离,构成了一个数组
distance = squaredDist ** 0.5
print 'distance:',distance
##step 2 对距离进行从小到大排序得到他们的索引序列
sortedDistIndices = argsort(distance)
print 'sortedDistIndices:',sortedDistIndices
##step 3,step 4 选出距离待测点最近的k个点,并统计每类别出现的次数
#定义了一个字典类型
classCount = {}
for i in xrange(k):
#step 3 选择距离待测点最近的k个点
voteLabel = labels[sortedDistIndices[i]]
print 'voteLabel',voteLabel
#统计每类别出现的次数,这里是存放到了字典中
classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
print classCount
##step 5 找出类别中统计数最大的那个类别,为待测样本的类别
maxCount = 0
for key, value in classCount.items():
if value > maxCount:
maxCount = value
maxIndex = key
#得到待测样本的类别
predictLable = maxIndex
print 'predictLable:',predictLable
#outputLabel = kNN1.kNNClassify(testX, dataSet, labels, k)
#print outputLabel
结果
>>>
labels: ['1', '1', '0', '0']
dataSet: [[ 1. 0.9]
[ 1. 1. ]
[ 0.1 0.2]
[ 0. 0.1]]
newInput [ 1.2 1. ]
###############
numSamples: 4
diff: [[ 0.2 0.1]
[ 0.2 0. ]
[ 1.1 0.8]
[ 1.2 0.9]]
squaredDiff: [[ 0.04 0.01]
[ 0.04 0. ]
[ 1.21 0.64]
[ 1.44 0.81]]
squaredDist: [ 0.05 0.04 1.85 2.25]
distance: [ 0.2236068 0.2 1.36014705 1.5 ]
sortedDistIndices: [1 0 2 3]
voteLabel 1
{'1': 1}
voteLabel 1
{'1': 2}
voteLabel 0
{'1': 2, '0': 1}
predictLable: 1
>>>
python版本2[3]
kNN.py
#coding:utf-8
from numpy import *
import operator
# 创建一个包含4个样本,2类的数据集
def createDataSet():
#创建一个矩阵:每一行作为一个样本,这里有4个样本,每个样本2个属性
group = array([[1.0, 0.9], [1.0, 1.0], [0.1, 0.2], [0.0, 0.1]])
#标签:4个样本和2类
labels = ['1', '1', '0', '0']
return group, labels
# 定义一个KNN分类器函数
def kNNClassify(newInput, dataSet, labels, k):
#样本的个数
numSamples = dataSet.shape[0] #numSamples = 4
###step 1 求待测样本到已知类别所有样本的距离
#tile(A, reps): 表示通过复制A,reps次,来创建一个数组,这里是4x1
#然后将其与已经类别的样本数据集做差
diff = tile(newInput, (numSamples, 1)) - dataSet #newInput:1xN,dataSet:NxM
#对矩阵中的每个元素平方
squaredDiff = diff ** 2
#将矩阵的每一行加起来
squaredDist = sum(squaredDiff, axis = 1)
#得到待测样本到已知类别的所有样本的距离,这里是一个向量,1x4
distance = squaredDist ** 0.5
###step 2 对所得到的距离向量进行从小到大排序,得到对应元素的索引
sortedDistIndices = argsort(distance)
#定义一个字典类型
classCount = {}
###step 3,4 选出距离待测点最近的k个点,并统计每个类别的出现次数
for i in xrange(k):
##step 3 选出距离待测点最近的k个点
voteLabel = labels[sortedDistIndices[i]]
##step 4 统计每个类别出现的次数
classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
### step 5 将出现次数最大的类别作为待测样本的类别,这里是选出最大的那个值,并记录它的类别
maxCount = 0
for key, value in classCount.items():
if value > maxCount:
maxCount = value
maxIndex = key
#返回待测样本的预测值(类别)
return maxIndex
结果
>>>
Your input is: [ 1.2 1. ] and classified to class: 1
Your input is: [ 0.1 0.3] and classified to class: 0
>>>
参考