- k-Nearest Neighbors算法(简称KNN算法,k近邻算法),是一个逻辑很简单的分类算法,其核心原理是找到与被测数据距离最近的k个数据,这k个数据中最多的类别就是预测数据的类别,而这个距离用的是欧式距离。
- knn算法几乎没有训练过程,实现简单,但是计算复杂性高;空间复杂性高;一般数值很大的时候不用这个,计算量太大。但是单个样本又不能太少,否则容易发生误分,最大的缺点是无法给出数据的内在含义
knn算法python实现
1. 直接使用python sklearn库
十来行代码就能搞定,高效快捷
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
#加载数据
iris = datasets.load_iris()
iris_x = iris.data
iris_y = iris.target
#分割数据,30%用做测试集
x_train, x_test, y_train, y_test = train_test_split(iris_x, iris_y, test_size=0.3)
#训练模型,预测数据
knn = KNeighborsClassifier()
knn.fit(x_train, y_train)
print(knn.predict(x_test))
print(y_test)
其中iris数据是分类鸢尾花数据,sklearn内置的,当然也可以下载原数据,链接:https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data
2. 不使用库,徒手写knn实现
KNN算法分为如下几步:
-
数据处理:打开CSV文件获取数据,将原始数据分为测试集/训练集。
-
相似性度量:计算每两个数据实例之间的距离。
-
近邻查找:找到k个与当前数据最近的邻居。
-
结果反馈:从近邻实例反馈结果。
-
精度评估:统计预测精度。
-
主函数:将上述过程串起来。
2.1 数据处理
首先加载文件中的数据。示例中使用的是csv module中的reader函数去读取文件。其实可以直接按行读取处理成想要的数据类型,不需要引入csv模块,因人而异。
接下来,将数据拆分为kNN用于做预测的训练集(training dataset)和用来评估模型精度的测试集(test dataset)。。通常训练集/测试集的划分比例标准为67/33。
将上述步骤合在一起,我们可以定义一个叫loadDataset的函数,该函数可以加载指定的CSV文件,并按照指定的比例随机分为训练集与测试集。
def loadDataset(filename, split, trainingSet=[] , testSet=[]):
with open(filename, 'rb') 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])
#测试函数
trainingSet=[]
testSet=[]
loadDataset('iris.data', 0.66, trainingSet, testSet)
print 'Train: ' , len(trainingSet)
print 'Test: ', len(testSet)
2.2 相似度度量(计算距离)
为了进行预测我们需要计算任意两个数据实例的相似性。对于给定的每一个测试集中的数据实例,我们都可以在训练集中找出k个相似性最高的数据实例,这样就可以依次进行预测。
假定鸢尾花的4个测量数据都为数值形式且单位相同,我们可以直接采用欧氏距离(Euclidean distance)进行相似性度量。欧式距离定义为:两组向量对应元素之差的平方和再做平方根运算。
将上述步骤合在一起,我们可以将euclideanDistance函数定义为:
import math
def euclideanDistance(instance1, instance2, length):
distance = 0
for x in range(length):
distance += pow((instance1[x] - instance2[x]), 2)
return math.sqrt(distance)
#测试函数
data1 = [2, 2, 2, 'a']
data2 = [4, 4, 4, 'b']
distance = euclideanDistance(data1, data2, 3)
print 'Distance: ' , distance
2.3 近邻查找
采用相似性度量的方法寻找未知数据实例的k个相似性最高的实例。
处理过程直接计算所有样本点到给定点的欧式距离,进而筛选距离最近的样本点子集。
下面是getNeighbors函数,该函数遍历训练集并返回与测试实例距离最近的k个近邻样本点(采用已经定义好的euclideanDistance函数)。
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 = []
for x in range(k):
neighbors.append(distances[x][0])
return neighbors
#测试函数
trainSet = [[2, 2, 2, 'a'], [4, 4, 4, 'b']]
testInstance = [5, 5, 5]
k = 1
neighbors = getNeighbors(trainSet, testInstance, 1)
print(neighbors)
2.4 结果预测
我们已经找到了测试实例的最近的邻居,下一步就是基于这些近邻做出预测结果。
我们可以让每个邻居对测试实例的类别属性进行投票,最终以票数多者做为预测结果。
下面的函数提供了从近邻投票中反馈多数投票结果的机制。该函数假定每个邻居的最后一列为类别属性。
import operator
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.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedVotes[0][0]
#测试函数
neighbors = [[1,1,1,'a'], [2,2,2,'a'], [3,3,3,'b']]
response = getResponse(neighbors)
print(response)
该方法在平局的情况下依然会有一个返回结果,但是我们可以对其特殊处理,例如返回空值或者选择一个无偏随机结果
2.5 精度评估
评估模型精度最简单的方法就是计算正确预测结果数量占全部预测结果数量的比例,称为分类精度。下面是getAccuracy函数,该函数统计所有的正确预测并返回正确分类的百分比精度。
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
#测试函数
testSet = [[1,1,1,'a'], [2,2,2,'a'], [3,3,3,'b']]
predictions = ['a', 'a', 'a']
accuracy = getAccuracy(testSet, predictions)
print(accuracy)
2.6 主函数(串联步骤2.1~2.5)
目前为止,我们已经具备了所有的算法组成元素,下面我们将这些元素串起来,组成主函数。
下面是从零开始实现的kNN算法完整Python代码。
# Example of kNN implemented from Scratch in Python
import csv
import random
import math
import operator
def loadDataset(filename, split, trainingSet=[] , testSet=[]):
with open(filename, 'rb') 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)
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 = []
for x in range(k):
neighbors.append(distances[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.iteritems(), 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():
# prepare data
trainingSet=[]
testSet=[]
split = 0.67
loadDataset('iris.data', split, trainingSet, testSet)
print 'Train set: ' + repr(len(trainingSet))
print 'Test set: ' + repr(len(testSet))
# generate predictions
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()
参考
http://python.jobbole.com/87407/
https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data
https://blog.csdn.net/Gamer_gyt/article/details/51232210
网友评论