k-最近邻分类器
“让我看看你的朋友是谁,我就告诉你你是谁?”
k-最近邻分类器的概念再简单不过了。这是一句古老的谚语,可以在多种语言和多种文化中找到。圣经中也有这样的说法:“与智慧人同行的,必得智慧;与愚昧人同行的,必受害”(箴言13:20)
这意味着 k-最近邻分类器的概念是我们日常生活和判断的一部分:想象一下,你遇到了一群人,他们都很年轻、时尚且喜欢运动。他们谈论着不在他们身边的朋友本。那么,你对本的想象是什么?是的,你把他想象成年轻、时尚和爱运动的人。
如果你知道 Ben 住在一个人们投票保守并且平均年收入超过 200000 美元的社区?他的两个邻居每年的收入甚至超过30万美元?你觉得本怎么样?最有可能的是,你不认为他是一个失败者,你可能也怀疑他是一个保守派?
最近邻分类背后的原理在于找到一个预定义的数字,即距离必须分类的新样本最近的训练样本的“k”。新样本的标签将从这些邻居中定义。k-最近邻分类器有一个固定的用户定义常数,用于必须确定的邻居数量。还有基于半径的邻居学习算法,它根据点的局部密度有不同数量的邻居,所有样本都在固定半径内。通常,距离可以是任何度量标准:标准欧几里得距离是最常见的选择。基于邻居的方法被称为非泛化机器学习方法,因为它们只是“记住”其所有训练数据。
k-NN 算法是所有机器学习算法中最简单的算法之一,尽管它很简单,但它在大量分类和回归问题中取得了相当大的成功,例如字符识别或图像分析。
现在让我们更数学一点:
正如数据准备一章所解释的,我们需要标记的学习和测试数据。然而与其他分类器相比,纯最近邻分类器不做任何学习,而是所谓的学习集升秒是分类器的基本组成部分。与其他分类方法相比,k-Nearest-Neighbor Classifier (kNN) 直接作用于学习到的样本,而不是创建规则。
最近邻算法:
给定一组类别 C={C1,C2,...C米},也称为类,例如 {"male", "female"}。还有一个学习集升秒 由标记的实例组成:
升秒={(○1,C○1),(○2,C○2),⋯(○n,C○n)}
由于标签项目少于类别是没有意义的,我们可以假设
n>米 在大多数情况下甚至 n⋙米 (n 远大于 m。)
分类的任务在于分配一个类别或类 C 到任意实例 ○.
为此,我们必须区分两种情况:
- 案例 1:
实例○ 是一个元素 升秒, 即有一个 tupel (○,C)∈升秒
在这种情况下,我们将使用类 C 作为分类结果。 - 案例 2:
我们现在假设○ 不在 升秒,或者准确地说:
∀C∈C,(○,C)∉升秒
○ 与所有的实例进行比较 升秒. 距离度量d用于比较。
我们确定克 最接近的邻居 ○,即距离最小的项目。
克是一个用户定义的常数和一个通常很小的正整数。
号码克 通常选择为的平方根 升秒,训练数据集中的总点数。
为了确定 克 最近的邻居我们重新排序 升秒 通过以下方式:
(○一世1,C○一世1),(○一世2,C○一世2),⋯(○一世n,C○一世n)
以便 d(○一世j,○)≤d(○一世j+1,○) 对所有人都是如此 1≤j≤n-1
k-最近邻集 N克 由第一个 克 此排序的元素,即
N克={(○一世1,C○一世1),(○一世2,C○一世2),⋯(○一世克,C○一世克)}
这组最近邻中最常见的类 N克 将被分配给实例 ○. 如果没有唯一的最常见的类,我们可以任意选择一个。
没有通用的方法来定义 'k' 的最佳值。该值取决于数据。作为一般规则,我们可以说增加“k”会减少噪音,但另一方面会使边界变得不那么明显。
k-最近邻分类器的算法是所有机器学习算法中最简单的算法之一。k-NN 是一种基于实例的学习或惰性学习。在机器学习中,惰性学习被理解为一种学习方法,其中训练数据的泛化延迟到对系统进行查询。另一方面,我们有急切学习,系统通常在接收查询之前概括训练数据。换句话说:该函数仅在局部逼近,并且在执行实际分类时执行所有计算。
下图以简单的方式展示了最近邻分类器的工作原理。拼图未知。为了找出它可能是哪种动物,我们必须找到邻居。如果k=1
,唯一的邻居是一只猫,我们假设在这种情况下拼图也应该是一只猫。如果k=4
,最近的邻居有一只鸡和三只猫。同样在这种情况下,假设我们讨论的对象应该是一只猫,这将是有利的。
从零开始的 k-最近邻
准备数据集
在我们真正开始编写最近邻分类器之前,我们需要考虑数据,即学习集和测试集。我们将使用 sklearn 模块的数据集提供的“iris”数据集。
数据集包含来自三种鸢尾属植物中每一种的 50 个样本
- 鸢尾,
- 弗吉尼亚鸢尾和
- 鸢尾花。
从每个样本测量四个特征:萼片和花瓣的长度和宽度,以厘米为单位。
从sklearn导入数据集导入numpy 作为 np
虹膜 = 数据集。load_iris ()
数据 = 虹膜。数据
标签 = 虹膜。目标
for i in [ 0 , 79 , 99 , 121 ]:
print ( f "index: { i : 3 } , features: { data [ i ] } , label: { labels [ i ] } " )
输出:
索引:0,特征:[5.1 3.5 1.4 0.2],标签:0
索引:79,特征:[5.7 2.6 3.5 1.],标签:1
指数:99,特征:[5.7 2.8 4.1 1.3],标签:1
索引:121,特征:[5.6 2.8 4.9 2.],标签:2
我们从上面的集合中创建了一个学习集。我们使用permutation
fromnp.random
来随机分割数据。
# 仅网站需要播种
#so 值始终相等:
np 。随机的。种子( 42 )
指数 = np 。随机的。排列(len (数据))
n_training_samples = 12
learn_data = 数据[索引[: - n_training_samples ]]
学习 标签= 标签[索引[: - n_training_samples ]]
test_data = 数据[索引[ - n_training_samples :]]
test_labels = 标签[索引[ - n_training_samples :]]
print ( "我们学习集的第一个样本:" )
print ( f " { 'index' : 7s }{ 'data' : 20s }{ 'label' : 3s } " )
for i in range ( 5 ):
print ( f " { i : 4d } { learn_data [ i ] } { learn_labels [ i ] : 3 } " )
print ( "我们测试集的第一个样本:" )
print ( f " { 'index' : 7s }{ 'data' : 20s }{ 'label' : 3s } " )
for i in range ( 5 ):
print ( f " { i : 4d } { learn_data [ i ] } { learn_labels [ i ] : 3 } " )
输出:
我们学习集的第一个样本:
索引数据标签
0 [6.1 2.8 4.7 1.2] 1
1 [5.7 3.8 1.7 0.3] 0
2 [7.7 2.6 6.9 2.3] 2
3 [6. 2.9 4.5 1.5] 1
4 [6.8 2.8 4.8 1.4] 1
我们测试集的第一个样本:
索引数据标签
0 [6.1 2.8 4.7 1.2] 1
1 [5.7 3.8 1.7 0.3] 0
2 [7.7