[Python]基于K-Nearest Neighbors[K-NN]算法的鸢尾花分类问题解决方案
看了原理,总觉得需要用具体问题实现一下机器学习算法的模型,才算学习深刻。而写此博文的目的是,网上关于K-NN解决此问题的博文很多,但大都是调用Python高级库实现,尤其不利于初级学习者本人对模型的理解和工程实践能力的提升,也不利于Python初学者实现该模型。
本博文的特点:
一 全面性地总结K-NN模型的特征、用途
二 基于Python的内置模块,不调用任何第三方库实现
博文主要分为四部分:
基本模型(便于理清概念、回顾模型)
对待解决问题的重述
模型(算法)和评价(一来,以便了解模型特点,为以后举一反三地应用作铺垫;二来,有利于以后快速复习)、
编程实现(Code)。
特别声明:
1.劳动成果开源,未经同意博主(千千寰宇:http://cnblogs.com/johnnyzen),不得以任何形式转载、复制。
2.如有纰漏或者其他看法,欢迎共同探讨~
零 基本模型
(本部分内容,均来源于引用[1],其原理讲解十分通俗易懂)
①K-近邻算法,即K-Nearest Neighbor algorithm,简称K-NN算法。单从名字来猜想,可以简单粗暴的认为是:K个最近的邻居,当K=1时,算法便成了最近邻算法,即寻找最近的那个邻居。
②所谓K-NN算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例(也就是K个邻居), 这K个实例的多数属于某个类,就把该输入实例分类到这个类中。
③实例
猜猜看:有一个未知形状(绿色圆点),如何判断其是什么形状?
问题:给这个绿色的圆分类?
对噪声数据过于敏感。为了解决这个问题,我们可以把位置样本周边的多个最近样本计算在内,扩大参与决策的样本量,以避免个别数据直接决定决策结果。
有两类不同的样本数据,分别用蓝色的小正方形和红色的小三角形表示,而图正中间的那个绿色的圆所标示的数据则是待分类的数据。
如果K=3,判定绿色的这个待分类点属于红色的三角形一类。
如果K=5,判定绿色的这个待分类点属于蓝色的正方形一类。
一 问题
题目:ML之k-NN:k-NN实现对150朵共三种花的实例的萼片长度、宽,花瓣长、宽数据统计,根据一朵新花的四个特征来预测其种类
数据源:https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data
数据源说明:https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.names
二 解决过程及模型评价

(见第三部分示范代码)

由于前面第二部分已经详细叙述,且代码中注释已经十分详细,便不在对代码进行解释,阅读注释便容易懂。
__init__.py
import random;
import math;
import Iris; # 自定义
import file_handle; # 自定义 #if __name__ == '__main__': #__name__ == '__main__'是Python的main函数入口
def main(print_test=False,print_samples=False):
follows = []; # 样本集空间(前sampleAmount项)+测试集空间(后 sampleAll-sampleAmount项)
data = ""; # 样本数据(前sampleAmount项)+测试集空间(后 sampleAll-sampleAmount项)
sampleAll = 150;
sampleAmount = 100; # 标记样本集数目(剩余的便作为测试集)
k = 5;
test_print = print_test; ########## 一 读取数据集,装载样本集
##### 1.1 加载数据集数据
data = file_handle.read("./dataset/data.txt",1,'r');#1:忽略第一行
# print(data);
list = data.split('\n');
i = 0;
for line in list: # 如:line = "5.1,3.5,1.4,0.2,Iris-setosa"
item = line.split(',');# 如:item = [5.1,3.5,1.4,0.2,Iris-setosa]
label_species = item.pop();#移除最后一项:标记种类
#print("[test] item:", item,"\tlabel_species:", label_species); # test
follows.append(Iris.Iris(item,label_species));
#print("[ ",i," ] ",follows[i].toString());
i += 1;
pass;
random.shuffle(follows); # 【千万注意!!!】由于原数据集是有序的,如果不做乱序处理,预测结果会及其不理想(准确率,趋近于0),当然,这也是这一模型的缺陷之一
##### 1.2 选择前100项 作为已标记样本集
#i = 0;
#for i in range(sampleAmount):
# follows[i].setPredictSpecies(follows[i].label_species);
# pass; ########## 二 训练测试样本
##### 2.1 对101 - 150 项的测试集进行训练/预测
## 算法描述:
## 遍历测试样本
## 计算测试样本与已标记的样本的欧式距离
## 对各欧式距离升序排序
## 选择前K项的已样本作为一子集( 即 选择最近的K项邻居作为参照标准)
## 遍历统计,已标记子集的花朵种类何种花朵数目种类最多
## 设置当前测试样本的预测花朵种类为该种
## 结束。
## 注释:花的种类分别为:Iris-setosa、Iris-versicolor、Iris-virginica;共计3种。
offset = 0; # 测试空间偏移量:目的是为了将通过偏移量,增大原已标记样本空间的样本数量 即 使已预测的测试样本加入参照样本空间。
for x in range(sampleAmount,sampleAll):# x:测试样本下标
weights = [];# 对各欧式距离(权值)的升序排序列表
for y in range(0,sampleAmount+offset):
result = (math.sqrt( + \
math.pow(follows[y].features[0] - follows[x].features[0],2) + \
math.pow(follows[y].features[1] - follows[x].features[1],2) + \
math.pow(follows[y].features[2] - follows[x].features[2],2) + \
math.pow(follows[y].features[3] - follows[x].features[3],2)), y);# 存储x,方便排序后定位花朵
#print("[test] weights[x]:", result);
weights.append(result);
pass;
weights.sort(key = lambda item:item[0]); # 以各元组内第一首项[欧氏距离]为键,默认升序排序
if test_print:
for m in range(len(weights)): # 输出预测权重
print("[test] weights[",m,"]:",weights[m],"\tweights[",m,"][1] > ",weights[m][1],":",follows[weights[m][1]].toString());
kinds_count = {"Iris-setosa":0,"Iris-versicolor":0,"Iris-virginica":0}; # 对已标记样本空间中各种花的数目统计作初始化
for z in range(0,k): # 选择前K项的已样本作为一子集( 即 选择最近的K项邻居作为参照标准)
if test_print:
print("[test] 排名前",z+1,"项 follows[",z,"]:",follows[weights[z][1]].toString());
label_species = follows[weights[z][1]].label_species;
if(label_species == 'Iris-setosa'):
kinds_count["Iris-setosa"] += 1;
elif label_species == 'Iris-versicolor':
kinds_count["Iris-versicolor"] += 1;
elif label_species == 'Iris-virginica':
kinds_count['Iris-virginica'] += 1;
else:
print("[ERROR:Unknown Species] follows[",weight[z][1],"]:",follows[weight[z][1]]);
pass;
result = max(kinds_count.items(), key = lambda item:item[1]); # 取统计花类数字典中最大值对应的序列
follows[x].predict_species = result[0]; # 标记预测种类
if test_print:
print("[test] 预测结果",result, " [follows[",x,"].predict_species]:", follows[x].predict_species); # test
offset += 1;
#for test in range(len(weights)): # 测试-输出距离权值结果
# print("[",test,"] weights:",weights[test][0],"\t",follows[weights[test][1]].toString());
# pass;
pass; ########## 三 计算预测准确率
rate = 0.0;
i = 0;
for i in range(sampleAmount,len(follows)):
if(follows[i].label_species == follows[i].predict_species):
rate += 1;
else:
print("[预测错误样本] follow[",i,"]:",follows[i].toString());
pass;
pass;
rate = rate / (sampleAll - sampleAmount);
print("预测准确率:",rate); if print_samples:
for i in range(0,len(follows)):
print(follows[i].toString());
pass;
pass; main(False,True);
Iris.py
'Iris module [class] ' __author__ = 'Johnny Zen' class Iris:
"""
Iris花(类) [Demo]
iris = Iris([5.1,3.5,1.4,0.2],"Iris-setosa");
print(iris.toString());
iris.setPredictSpecies('Iris-setosa');
print(iris.toString());
print(iris.label_species);
=======================
[features][5.1, 3.5, 1.4, 0.2] [label-species]Iris-setosa [predict-species]None
[features][5.1, 3.5, 1.4, 0.2] [label-species]Iris-setosa [predict-species]Iris-setosa
Iris-setosa
"""
features = [];
label_species = None; # 标记种类
predict_species = None; # 预测种类
def __init__(self,features,label_species=None):
if type(features).__name__ == 'list':
self.features = features;
else:
self.features = list(features); # 此list方法对list对象执行将产生错误
pass;
for x in range(len(self.features)): # 列表内元素字符串转实数
self.features[x] = float(self.features[x]);
self.label_species = label_species;
pass;
def setPredictSpecies(self,predict_species=None):#设置预测种类
self.predict_species = predict_species;
pass;
def toString(self):#与一般函数定义不同,类方法必须包含参数 self[第一个参数]
return "[features]" + str(self.features) + "\t[label]" + str(self.label_species + "\t[predict]" + str(self.predict_species));
pass;
pass;
file_handle.py
"file_handle module [function]:read(filepath,ignore=0,mode='r')" def read(filepath,ignore=0,mode='r'):
try:
file = open(filepath,mode);
## file_content = file.read();
file_content = '';
i = 0;
for i in range(0,ignore):
file.readline();
##print(i);
##print(file.readline());
for line in file.readlines():
file_content += line;
finally:
if file:
file.close();
#print(file_content);
return file_content;
pass;
四 参考文献
[1] K-NN和K-Means算法
[Python]基于K-Nearest Neighbors[K-NN]算法的鸢尾花分类问题解决方案的更多相关文章
- [机器学习系列] k-近邻算法(K–nearest neighbors)
C++ with Machine Learning -K–nearest neighbors 我本想写C++与人工智能,但是转念一想,人工智能范围太大了,我根本介绍不完也没能力介绍完,所以还是取了他的 ...
- 04-04 AdaBoost算法代码(鸢尾花分类)
目录 AdaBoost算法代码(鸢尾花分类) 一.导入模块 二.导入数据 三.构造决策边界 四.训练模型 4.1 训练模型(n_e=10, l_r=0.8) 4.2 可视化 4.3 训练模型(n_es ...
- K Nearest Neighbor 算法
文章出处:http://coolshell.cn/articles/8052.html K Nearest Neighbor算法又叫KNN算法,这个算法是机器学习里面一个比较经典的算法, 总体来说KN ...
- K NEAREST NEIGHBOR 算法(knn)
K Nearest Neighbor算法又叫KNN算法,这个算法是机器学习里面一个比较经典的算法, 总体来说KNN算法是相对比较容易理解的算法.其中的K表示最接近自己的K个数据样本.KNN算法和K-M ...
- 机器学习--K近邻 (KNN)算法的原理及优缺点
一.KNN算法原理 K近邻法(k-nearst neighbors,KNN)是一种很基本的机器学习方法. 它的基本思想是: 在训练集中数据和标签已知的情况下,输入测试数据,将测试数据的特征与训练集中对 ...
- Python交互K线工具 K线核心功能+指标切换
Python交互K线工具 K线核心功能+指标切换 aiqtt团队量化研究,用vn.py回测和研究策略.基于vnpy开源代码,刚开始接触pyqt,开发界面还是很痛苦,找了很多案例参考,但并不能完全满足我 ...
- 02-19 k近邻算法(鸢尾花分类)
[TOC] 更新.更全的<机器学习>的更新网站,更有python.go.数据结构与算法.爬虫.人工智能教学等着你:https://www.cnblogs.com/nickchen121/ ...
- 统计学习方法与Python实现(二)——k近邻法
统计学习方法与Python实现(二)——k近邻法 iwehdio的博客园:https://www.cnblogs.com/iwehdio/ 1.定义 k近邻法假设给定一个训练数据集,其中的实例类别已定 ...
- 聚类之K均值聚类和EM算法
这篇博客整理K均值聚类的内容,包括: 1.K均值聚类的原理: 2.初始类中心的选择和类别数K的确定: 3.K均值聚类和EM算法.高斯混合模型的关系. 一.K均值聚类的原理 K均值聚类(K-means) ...
随机推荐
- 【SFA官方翻译】使用 Kubernetes、Spring Boot 2.0 和 Docker 的微服务快速指南
[SFA官方翻译]使用 Kubernetes.Spring Boot 2.0 和 Docker 的微服务快速指南 原创: Darren Luo SpringForAll社区 今天 原文链接:https ...
- 最全面的 Spring 学习笔记
http://www.codeceo.com/article/learn-spring.html 来源:泊浮目 分享到:更多36 Spring致力于提供一种方法管理你的业务对象.在大量Java EE的 ...
- Vim保存时权限不足
保存时权限不足,由于打开时忘记在命令前添加sudo.我们并不需要放弃修改,从新以root权限打开 解决方案 命令模式使用:w !sudo tee %提权,保存
- A1111. Online Map
Input our current position and a destination, an online map can recommend several paths. Now your jo ...
- 【洛谷P1052】过河 离散化+dp
题目大意:给定一个长度为 N 的序列,有 M 个点对答案的贡献为 1,其余为 0,现从起点出发,每次只能走 [s,t] 个单位,求从起点走到终点时答案贡献最小是多少. 题解:由于 N 很大,无法直接记 ...
- Linux基本命令总结(三)
接上篇: 11,more命令,功能类似 cat ,cat命令是整个文件的内容从上到下显示在屏幕上. more会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空白键(space)就往下一页显示 ...
- Django 创建超级用户
Django自带的后台管理是Django明显特色之一,可以让我们快速便捷管理数据.后台管理可以在各个app的admin.py文件中进行控制 #创建超级用户 python manage.py creat ...
- linux free命令
Linux上的free命令详解 free命令的所有输出值都是从/proc/meminfo中读出的 total used free shared buffers cached Mem: -/+ buff ...
- redis五种数据类型的使用场景
string 1.String 常用命令: 除了get.set.incr.decr mget等操作外,Redis还提供了下面一些操作: 获取字符串长度 往字符串append内容 设置和获取字符串的某一 ...
- 第二十八篇-Fragment静态用法
效果图: 首先,先大致布局成这个形状 看动画中,横看分为两个区域,所以整体是一个水平排列 设置外层LinearLayout的参数 android:orientation="horizonta ...