一、关于knn算法
1、对于knn的理解:
- KNN 的全称是 K Nearest Neighbors,意思是 K 个最近的邻居。KNN 的原理就是:当预测一个新样本的类别时,根据它距离最近的k个样本点是什么类别来判断该新样本属于哪个类别。它的工作原理是利用训练数据对特征向量空间进行划分,并将划分结果作为最终算法模型。存在一个样本数据集合,也称作训练样本集,并且样本集中的每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的数据后,将这个没有标签的数据的每个特征与样本集中的数据对应的特征进行比较,然后提取样本中特征最相近的数据的分类标签。
- 在编写程序的过程中,对不同的k值的选择也会对最终结果有所影响,所以还是得选择比较合适的k值来进行实验。本次实验中我采取的k值是3。
- knn算法的优缺点:
优点:
1、KNN可以处理分类问题,同时天然可以处理多分类问题。
2、简单,易懂,同时也很强大。
3、KNN还可以处理回归问题,也就是预测。
缺点:
1、效率低,因为每一次分类或者回归,都要把训练数据和测试数据都算一遍,如果数据量很大的话,需要的算力会很惊人,但是在机器学习中,大数据处理又是很常见的一件事。
2、对训练数据依赖度特别大,虽然所有机器学习的算法对数据的依赖度很高,但是KNN尤其严重,因为如果我们的训练数据集中,有一两个数据是错误的,刚刚好又在我们需要分类的数值的旁边,这样就会直接导致预测的数据的不准确,对训练数据的容错性太差。
2、实验问题引入:
- 基于对knn算法的学习,此次实验我从网络上查找了一些数据集,最终选定了比较经典的鸢尾花数据集。这个数据集中一共有150条数据样例,共4个属性(萼片长度, 萼片宽度,花瓣长度, 花瓣宽度)。
- 此次实验的目标是将数据集随机划分为训练集(70%)和测试集(30%)以此来测试训练的分类器准确率是多少。
- 采用欧氏距离来计算不同数据样本之间的距离:。
- 我的数据集。
二、代码实现
knn算法的实现:
- 导入一些需要用到的库
import csv #用于进行数据交换
import random #用于生成随机数
import math #计算
import operator #高效率函数
- 导入数据,划分数据集
def loadDataset(filename, split, trainingSet=[], testSet=[]):
with open(filename, 'rt', encoding="utf-8") 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):
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)) # sort函数默认为升序
neighbors = []
for x in range(k):
neighbors.append(distances[x][0]) # 得到k个近邻
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/len(testSet) * 100.0
- 主函数,使代码更加简洁
def main():
trainingSet = []
testSet = []
split = 0.67 # 设置训练集:测试集为2:1
loadDataset('iris.txt', split, trainingSet, testSet) # 导入数据
print("Train set:", len(trainingSet))
print("Test set:", len(testSet))
predictions = []
k = 3 # 计算最近的3个近邻
for x in range(len(testSet)):
neighbors = getNeighbors(trainingSet, testSet[x], k)
result = getResponse(neighbors)
predictions.append(result)
print('>predicted = ', result, ', actual = ', testSet[x][-1])
accuracy = getAccuracy(testSet, predictions)
print("Accuracy: ", accuracy, '%')
三、结果截图
四、实验总结
- 实验结果分析:实验结果输出的是测试集测试的准确率,但是实际上每次输出的结果都有所不同,因为训练集和测试集是随机划分的。
- 实验时遇到的问题:
- k值应该如何选取。——k=1的K近邻算法被称为最近邻算法,此时将训练集中与测试样本点最接近的点的类别作为测试样本的分类标签。
优点:只有与输入实例较近的的训练实例才会对预测起作用。
缺点:因为参考的点很少,所以其“学习”的估计误差会增大,预测结果对近邻的点非常敏感。如果近邻的实例点刚好事噪声, 那么预测可能出错的概率变大。
k比较大时:
优点:有效的减少“学习“的估计误差。
缺点:“学习”的近似误差会增加,此时离实例较远的点也会对预测起作用,使得出现预测错误的概率加大。其实K值加大意味着模型变得简单,如果K=样本点数,那么所有的测试点的类标签都是训练集中出现最多的那一类标签。 - 如何将数据导入并合理的地设置数据所在区域——通过设置一个字典用于数据的记录,以及不同属性之间的分类运用。
参考:
1、https://elevenzou.github.io/