KNN算法简单应用

99封情书 提交于 2020-03-28 15:00:36

这里是写给小白看的,大牛路过勿喷。

 

1 KNN算法简介

  KNN(K-Nearest Neighbor)工作原理:存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类对应的关系。输入没有标签的数据后,将新数据中的每个特征与样本集中数据对应的特征进行比较,提取出样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k近邻算法中k的出处,通常k是不大于20的整数。最后选择k个最相似数据中出现次数最多的分类作为新数据的分类

 

2 KNN算法优缺点

  优点:精度高,对异常值不敏感、无数据输入假定

  缺点:计算复杂度高、空间复杂度高

 

 

做一个简单的应用:

一种花叫做虹膜花:

 

收集一些实例
 
萼片长度,萼片宽度,花瓣长度,花瓣宽度
(sepal length, sepal width, petal length and petal width)
 
类别:
Iris setosa, Iris versicolor, Iris virginica.
 
学习目标是:根据四种属性判断类别
 
用python的sklearn库实现:
(sklearn中已经存在的数据集)
from sklearn import neighbors
from sklearn import datasets

knn = neighbors.KNeighborsClassifier()
iris = datasets.load_iris()

knn.fit(iris.data, iris.target)
# 当数据为0.1, 0.2, 0.3, 0.4时,预测它是什么花
predictedLabel = knn.predict([[0.1, 0.2, 0.3, 0.4]])
print(predictedLabel)

 

 
 不调用sklearn,自己实现:
 
 这是一个数据集文本
 截取数据集(irisdata.txt)的一段:
5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5.0,3.6,1.4,0.2,Iris-setosa
5.4,3.9,1.7,0.4,Iris-setosa
4.6,3.4,1.4,0.3,Iris-setosa
5.0,3.4,1.5,0.2,Iris-setosa

 

导入几个基本的库:

import csv
import random
import math
import operator

 

全局定义两个集合:训练集、测试集

# 训练集
trainingSet = []
# 测试集
testSet = []

 

 读取数据并做一些初步的处理:

 传入一个分割概率,随机划分训练集和测试集

def loadDataset(filename, split):
    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个数据:

计算训练集中每一项和该实例的欧氏距离,取最小的k个距离

def getNeighbors(k, testInstance):
    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

 

获取的这些k项未必是同一类,接下来统计类别个数,并返回出现次数最多的类作为最终的结果:

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(predictions):
    correct = 0
    for x in range(len(testSet)):
        if testSet[x][-1] == predictions[x]:
            correct += 1
    return (correct / float(len(testSet))) * 100.0

 

主函数:

 

if __name__ == '__main__':
    main()

 

def main():
    split = 0.70
    loadDataset(r'D:\ml\irisdata.txt', split)
    print('Train set: ' + repr(len(trainingSet)))
    print('Test set: ' + repr(len(testSet)))

 

读取后打印下个数:

Train set: 102
Test set: 48

 

接下来预测:

    predictions = []
    k = 3
    for x in range(len(testSet)):
        neighbors = getNeighbors(k, testSet[x])
        result = getResponse(neighbors)
        predictions.append(result)
        print('>predicted=' + repr(result) + ', actual=' + repr(testSet[x][-1]))

 

看一下预测的一部分结果:

 

 

发现基本预测准确,测试精确度:

    accuracy = getAccuracy(predictions)
    print('Accuracy: ' + repr(accuracy) + '%')

 

发现精确度很高:

 

由于处理数据时候采用随机划分的方式,可以反复运行测试,发现准确率基本在90%到96%,说明这个模型是合适的

 

小结:

  KNN是简单有效的分类数据算法,在使用时必须有训练样本数据,还要计算距离,如果数据量非常大会非常消耗空间和时间。它的另一个缺陷是无法给出任何数据的基础结构信息,因此我们无法平均实例样本和典型实例样本具体特征,

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!