欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

KNN算法简单应用

程序员文章站 2022-03-30 16:41:56
这里是写给小白看的,大牛路过勿喷。 1 KNN算法简介 KNN(K-Nearest Neighbor)工作原理:存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类对应的关系。输入没有标签的数据后,将新数据中的每个特征与样本集中数据对应的特征进 ......

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

 

1 KNN算法简介

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

 

2 KNN算法优缺点

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

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

 

 

做一个简单的应用:

一种花叫做虹膜花:

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]))

 

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

KNN算法简单应用

 

 

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

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

 

发现精确度很高:

KNN算法简单应用

 

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

 

小结:

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