KNN算法,是比较常见而且也易于实现的机械学习分类算法。其从字面上简单的可以理解为,周围离预测点最近的K各点中大多数点的属性就为预测点的属性。此处,可以看出这样三个关键点。第一,少数服从多数;第二,知道周围点的属性,因此需要储存属性,这点便导致了KNN算法需要比较大的空间复杂度;第三,最近的K各点。如何判断最近?便以此,引入距离的概念。距离在解析几何中定义(空间两点或者两向量之间的距离) , 线性代数中的矩阵的距离; 其次还有曼哈顿距离(棋盘距离)d(i,j)=|X1-X2|+|Y1-Y2|等等。
那么问题来了,KNN算法中距离的定义是否会对计算结果有影响了?
自然是有影响的,一般地连续性数据的时候采用欧式距离;非连续性的时候采用曼哈顿或者汉明距离。所以有时候需要对距离度量进行优化从而提高预测的精度,如大边缘最近邻法或者近邻成分分析法。但是本人认为距离的选取,对KNN算法的精度影响不太大,而更为重要的是K值的选取。显然K值的选择并不是一拍脑门就直接想出的。K值的选择过程中需要采用交叉验证来降低误差。
另外,由于采用的是少数服从多数的方法,显然样本的不均衡性会对预测结果产生一定的影响。此处,我们便引入权重的概念,权重的概念体现在两个方面,第一,数据量(如A类本身数据量极大,因此可以考虑按照比例降低);第二,距离。(显然距离预测点越近的点,其在预测中权重就应该越大,选1/dis)。
接下来,我们用一个示例代码来说明。
调用sklearn来实现
from sklearn import neighbors
from sklearn import datasets
knn = neighbors.KNeighborsClassifier()
iris = datasets.load_iris()
print (iris)
knn.fit(iris.data, iris.target)
predictedLabel = knn.predict([[0.1,0.2, 0.3, 0.4]])
print(predictedLabel)
基本编程来实现
import csv
##自行下载iris.data.txt 或者csv 二者可以直接转化
import random
import math
import operator #操作文件
#首先载入数据
def loadDataset(filename, split, trainingSet = [], testSet = []):
with open(filename, 'r')as csvfile:
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[x])
#计算距离
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):
distance = []
length = len(testInstance) -1
for x in range(len(trainingSet)):
dist = euclideanDistance(testInstance, trainingSet[x], length)##计算每个训练集到实数集的距离
distance.append((trainingSet[x], dist))
distance.sort(key = operator.itemgetter(1))
neighbors = []
for x in range(k):
neighbors.append(distance[x][0])
return neighbors
#投票排序
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
def main():
trainingSet = []
testSet = []
split = 0.67
loadDataset(r'D:\knn\iris.data.csv', 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('prediction = ' + repr(result) + ', actual=' + repr(testSet[x][-1]))
accuracy = getAccuracy(testSet, predictions)
print('accuracy:' + repr(accuracy) + '%')
if __name__ == '__main__':
main()
还有三个问题需要测试;一个是K值的选取,一个是距离的定义问题,另外一个是分割值split.