表2 - 2 已知电影与未知电影的距离
________________
电影名称______________
___________________与 未 知 电 影的 距 离 ______________________California Man m 5
He 's Not Really into Dudes 18.7
Beautiful Woman 19.2
Kevin Longblade 115.3
Robo Slayer 3000 117.4
Amped II
_________________
m 3____________________
现在我们得到了样本集中所有电影与未知电影的距离,按照距离递增排序,可以找到乂个距 离最近的电影。假定
^=3
,贝丨』三个最靠近的电影依次是故》#0;
办(7//
少如0/3»
如 、Beautiful Woman和。_ _ 从 氣 4-
近邻算法按照距离最近的三部电影的类型,决定未知电影的类型,而这三部 电影全是爱情片,因此我们判定未知电影是爱情片。本章主要讲解如何在实际环境中应用々-近邻算法,同时涉及如何使用
?7
出(^工具和相关的机 器学习术语。按 照1.5
节开发机器学习应用的通用步骤,我们使用?
乂出如语言开发&-近邻算法的简 单 应 用 ,以检验算法使用的正确性。k
-近邻算法的一般流程 ■ A .廣 ,^a.. :¾f , -(1)
收集数据:可以使用任何方法。(2)
准备数据:距离计算所需要的数值,最好是结构化的数据格式。(3)
分析数据 :可以使用任何方法。(4)
训练算 法 :此步驟不适用于1
近邻算法。(5)
测试算 法:计算错误率。(6)
使 用 算 法 :首先需要输入样本数据和结构化的输出结果,然后运行女-近邻算法判定输 入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。2 . 1 . 1
准 备 : 使 用P y th o n
导 入 数 据首 先 ,创 建 名 为 麵 孙 的
?
沖0
濃 块 ,本章使用的所有代码都在这个文件中。读者可以按照自 己的习惯学习代码,既可以按照本书学习的进度,在自己创建的?7^«^
文件中编写代码,也可以直 接从本书的源代码中复制_
仍 文 件 。我推荐读者从头开始创建模块,按照学习的进度编写代码。无论大家采用何种方法,我们现在已经有了
kNN.py
文件 。在构造完整的丨-
近邻算法之前,我 们还需要编写一些基本的通用函数,在kNN.py
文件中增加下面的代码:f r o m n u m p y i m p o r t ★ i m p o r t o p e r a t o r d e f c r e a t e D a t a S e t { ) :
g r o u p = a r r a y ( [ [ 1 . 0 , 1 .1] • [1.0,1. 0], [0,0], [0,0.1]]) l a b e l s = [ ' A ' , ' A ' , ' B ' , ' B 1]
r e t u r n group, l a b e l s
在上面的代码中,我们导人了两个模块;第一个是科学计算包
> ^ ! ^ ^
第二个是运算符模块,
18
第2
章it
-近邻算法女
-
近邻算法执行排序操作时将使用这个模块提供的函数,后面我们将进一步介绍。为了方便使用。
3^
社60
社 沾61^)
函数 ,它创建数据集和标签,如图2-1
所 示 。然后依次执行 以下步骤:保存_ $ 7
文 件 ,改变当前路径到存储— .?7
文 件 的 位 置 ,打开?
外1«^
开 发环境。Xifc^Linux、Mac O S
还是Windows
都需要在打开终端,在命令提亦符下完成上述操作。只要我 们按照默认配置安装? 3 ^ ( ® ,
在01»«
几^ 0 8
终端内都可以直接输人9 7
比0 1 ^
而 在 斯1«10
评8
命令 提水符下需要输人。:\Python2 . 6\python _ e x e ,
进人?7
也00
交互式开发环境。进人
?
丫出(^
开发环境之后,输人下列命令导人上面编辑的程序模块:
> >> i m p o r t k N N
上 述 命 令 导 人 臟 模 块 。为了确保输人相同的数据集,麵 模 块 中 定 义 了 函 数^ 的七扣壯沾社,在 卩
”
乜0
«命令提本符下输入下属 命 令:>>> g r o u p , l a b e l s = k N N . c r e a t e D a t a S e t ()
上述命令创建了变量
910
叩 和1
沾013
,在?7
出^
命 令提示 符下,输人变量的名字以检验是否正确 地 定 义变 量:>>> g r o u p
a r r a y ([[ 1 1 . 1]
•
0.1]])
l a b e l s
[ ' A f, ' A ' , 'B,, 'B']
这里有
4
组 数 据 ,每组数据有两个我们已知的属性或者特征值。上面的9!^
卩?矩阵每行包含一个 不同的数据,我们可以把它想象为某个日志文件中不同的测量点或者入口。由于人类大脑的限制,我们通常只能可视化处理三维以下的事务。因此为了简单地实现数据可视化,对于每个数据点我 们通常只使用两个特征。
向量
1
必61
包含了每个数据点的标签信息,1
处61
包含的元素个数等于取。叩 矩 阵 行 数 。这 里我们将数据点(1
,1.1)
定义为类八,数据点(0, 0.1)
定义为类8
。为了说明方便,例子中的数值是 任 意选择的,并没有给出轴标签,图2-2
是带有类标签信息的四个数据点。~ ° -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2
•图2-2 &近邻算法:带有4个数据点的简单例子
2.1 A
-近邻算 法概述19
现在我们巳经知道?7««^
如何解析数据,如何加载数据,以及_
算法的工作原理,接下来 我们将使用这些方法完成分类任务。2 . 1 . 2 从文本文件中解析数据
本节使用程序清单
2-1
的函数运行_
算 法 ,为每组数据分类。这里首先给出卜近邻算法的伪 代码和实际的?
乂出011
代 码 ,然后详细地解释每行代码的含义。该函数的功能是使用&-近邻算法将 每组数据划分到某个类中,其伪代码如下:对未知类别属性的数据集中的每个点依次执行以下操作:
(1)
计算已知类别数据集中的点与当前点之间的距离;(2)
按照距离递增次序排序;(3)
选取与当前点距离最小的走个点;(4)
确定前灸个点所在类别的出现频率;(5)
返回前女个点出现频率最高的类别作为当前点的预测分类。?
丫0 « ^
函数<=13331&0 ()
如程序清单2_1
所 示。程序清单
2 - 1
各近邻算法d e f c l a s s i f y O ( i n X , dataSet, labels, k ) : d a t a S e t S i z e = d a C a S e t .s h a p e fO]
d i f f M a t = t i l e ( i n X , ( d a t a S e t S i z e , 1)) - d a t a S e t s q D i f f M a t = d i f f M a t * * 2
s q D i s t a n c e s = s q D i f f M a t .s u m (axis=l) d i s t a n c e s = s q D i s t a n c e s * * O .5
s o r t e d D i s t I n d i c i e s - d i s t a n c e s.argaort ()
距 离 计 算
c l a s s C o u n t = { } 选 择 距 离 最 小 资
f o r 1 in r a n g e ( k ) . 的斤个占 ^ \
v o t e I l a b e l = l a b e l s [ s o r t e d D i s t I n d i c i e s [i]]
c l a s s C o u n t [ v o t e l l a b e l ] = c l a s s C o u n t . g e t { v o t e I l a b e l ,0) + 1 s o r t e d C l a s s C o u n t = s o r t e d ( c l a s s C o u n t .i t e r i t e m s (),
k e y = o p e r a t o r . i t e m g e t t e r { l ) , r e v e r s e = T r u e ) < ~ ^
r e t u r n s o r t e d C l a s s C o u n t [ 0 ] [0] 办 排 序
classifyO ()
函数有4
个输人参数:
用于分类的输人向量是丨必,输人的训练样本集为(1313861,
标签向量为131^13
,最后的参数义表示用于选择最近邻居的数目,其中标签向量的元素数目和矩 阵 如1
沾&
的行数相同。程序清单2-1
使用欧氏距离公式,计算两个向量点“
和成之间的距离0 :
d = 」(xA0 - xB0 )2 + (xA{ - xBt )2
例 如 ,点(0
,0)
与(1, 2)
之间的距离计算为:V(l-0)2+(2-0)2
如果数据集存在
4
个 特 征 值 ,则点(1
,0, 0
,1)
与(7, 6, 9
,4)
之间的距离计算为:20
第2
章1
-近邻算法V(7 - 1)2 + (6 - 0)2 + (9
一
0)2 + (4一
1)2计算完所有点之间的距离后,可以对数据按照从小到大的次序排序。然 后 ,确定前
k
个距离 最小元素所在的主要分类© ,
输人々总是正整数;最 后 ,将< ^
尤0
恤 字 典 分 解 为 元 组 列 表 ,然后 使用程序第二行导入运算符模块的让挪9
过 t e r ^ m ,按照第二个元素的次序对元组进行排序©。此处的
3#
序 为 逆 序 ,即按照从最大到最小次序排序,最后返回发生频率最高的元素标签。为了预测数据所在分类,在卩沖如提示符中输入下列命令
:
>>> k N N . c l a s s i f y 0 ( [ 0 , 0 ] , gr oup, labels, 3)
输 出 结 果 应 该 是 艮 大 家 也 可 以 改 变 输 人
[0,0]
为其他 值 ,测试程序的运行结果。到现在为止,我们已经构造了第一个分类器,使用这个分类器可以完成很多分类任务。从这 个 实例出发,构造使用分类算法将会更加容易。
2 . 1 . 3 如何测试分类器
上文我们已经使用女
-
近邻算法构造了第一个分类器,也可以检验分类器给出的答案是否符合 我们的预期。读者可能会问:“
分类器何种情况下会出错?”
或 者“
答案是否总是正确的?” 答 案 是否定的,
分类器并不会得到百分百正确的结果,
我们可以使用多种方法检测分类器的正确率。此外分类器的性能也会受到多种因素的影响,如分类器设置和数据集等。不同的算法在不同数据 集上的表现可能完全不同,这也是本部分的
6
章都在讨论分类算法的原因所在。为了测试分类器的效果,我们可以使用已知答案的数据,当然答案不能告诉分类器,检验分 类器给出的结果是否符合预期结果。通过大量的测试数据,我们可以得到分类器的错误率—— 分 类器给出错误结果的次数除以测试执行的总数。错误率是常用的评估方法,主要用于评估分类器 在某个数据集上的执行效果。完美分类器的错误率为
0 ,
最差分类器的错误率是1.0
,在 这 种 情 况 下 ,分类器根本就无法找到一个正确答案。读者可以在后面章节看到实际的数据例子。上一节介绍的例子已经可以正常运转了,但是并没有太大的实际用处,本章的后两节将在现 实世界中使用
/
卜近邻算法。首 先 ,我们将使用&-
近邻算法改进约会网站的效果,然后使用々-近邻 算法改进手写识别系统。本书将使用手写识别系统的测试程序检测々-
近邻算法的效果。2 . 2 示例:使用々-近邻算法改进约会网站的配对效果
我的朋友海伦一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的 人 选 ,但她没有从中找到喜欢的人。经过一番总结,她发现曾交往过三种类型的人:
□ 不喜欢的人
□ 魅力一般的人
□ 极具魅力的人
尽管发现了上述规律,但海伦依然无法将约会网站推荐的匹配对象归人恰当的分类。她觉得 可以在周一到周五约会那些魅力一般的人,而周末则更喜欢与那些极具魅力的人为伴。海伦希望
2 . 2
示 例 :使 用1
近邻 算法改 进约会网站的配对效果21
我们的分类软件可以更好地帮助她将匹配对象划分到确切的分类中。此外海伦还收集了一些约会 网站未曾记录的数据信息,她认为这些数据更有助于匹配对象的归类。|
示例:在约会网站上使用&近邻算法' ' ;; • f ^ , : , i (1)
收集数据:提供文本文件。(2)_
准备数据:
使用?沖00
解析文本文件。( 3 )分 析 数 据 :使用河3中10«化画二维扩散图。
(4)
训练算 法:此步驟不适用于卜近邻算法。(5)
测试算法:使用海伦提供的部分数据作为测试样本。测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类 与实际类别不同,则标记为一个错误。
(6)
使 用 算 法 :产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否 为自己喜欢的类型。2 . 2 . 1 准 备 数 据 :从文本文件中解析数据
海伦收集约会数据巳经有了一段时间,她把这些数据存放在文本文件
(1
如1^
及 抓 比 加 中 ,每 个样本数据占据一行,总共有1000
行 。海伦的样本主要包含以下3
种 特 征 :□ 每年获得的飞行常客里程数
□ 玩视频游戏所耗时间百分比
□ 每周消费的冰淇淋公升数
在将上述特征数据输人到分类器之前,必须将待处理数据的格式改变为分类器可以接受的格 式 。在
kNN.py
中创建名为file2matrix
的 函数,以此来处理输人格式问题。该函数的输人为文 件 名 字符 串,输出为训练样本矩阵和类标签向量。将下面的代码增加到
_ . ?7
中。程序清单
2 - 2
将文本记录到转换NumPy
的解析程序程序清单