I.距离度量
首先,数据集中的要素(列)数量不是选择用于kNN的距离度量的因素。有很多针对这一问题的已发表研究,比较的通常依据是:
如果您不了解数据采样的分布,请至少进行一项(有据可查且详尽的)研究得出结论,欧几里德距离是最佳选择。
YEuclidean度量标准用于大规模Web推荐引擎以及当前的学术研究中。欧几里得距离计算的距离具有直观的含义和计算范围,即,无论两点是二维空间还是22维空间,欧几里德距离的计算方式都是相同的。
它对我来说只有几次失败,在每种情况下,欧几里得距离都失败了,因为基础(笛卡尔)坐标系是一个糟糕的选择。而且您通常会认识到这一点,因为例如路径长度(距离)不再是累加的,例如,当公制空间是国际象棋棋盘时,曼哈顿距离要比欧几里得更好,同样,当公制空间是地球并且您的距离是反距离时-洲际飞行,适合于极坐标系的距离度量是一个好主意(例如,伦敦到维也纳为2.5小时,维也纳到圣彼得堡为3小时,或多或少在同一方向,而伦敦到圣地圣彼得堡不是5.5小时,而是3小时多一点。)
但是,除了数据属于非笛卡尔坐标系的情况以外,距离度量的选择通常并不重要。(请参阅来自CS学生的博客文章,通过检查距离度量标准对kNN分类器的影响来比较多个距离度量标准-卡方得出最佳结果,但差异并不大;学术论文中有更全面的研究,比较研究最近邻的距离函数-马哈拉诺比斯(本质上是欧几里得,用尺寸协方差归一化)是本研究中最好的。
一个重要的条件:要使距离度量计算有意义,您必须 重新缩放您的数据-很少有可能建立kNN模型来生成准确的预测,而无需这样做。例如,如果您正在建立一个kNN模型来预测运动表现,并且您的期望变量是身高(cm),体重(kg),体脂(%)和静息脉动(每分钟心跳数),那么典型数据点可能看起来像这样:[180.4,66.1,11.3,71]。显然,距离计算将以身高为主导,而体脂百分比的贡献几乎可以忽略不计。换句话说,如果报告的数据不同,那么体重以克而不是千克为单位,那么原始值86.1将为86,100,这将对您的结果产生重大影响,而这正是您要做的不想。
X_new = (X_old - mu) / sigma
二。数据结构
如果您担心kd-tree结构的性能,Voronoi Tessellation是概念上简单的容器,但它将大大提高性能,并且比kd-Trees更好地扩展。
这不是持久保留kNN训练数据的最常见方法,尽管对此已充分记录了VT的应用以及由此带来的性能优势(例如,参见此Microsoft Research报告)。这样做的实际意义是,假设您使用的是“主流”语言(例如,在TIOBE Index中),那么您应该找到一个执行VT的库。我知道在Python和R中,每种语言都有多个选项(例如,在CRAN上提供R 的voronoi软件包)
将VT用于kNN的工作方式如下:
从您的数据中随机选择w点-这是您的Voronoi中心。Voronoi单元封装了距离每个中心最近的所有相邻点。想象一下,如果您为每个Voronoi中心指定了不同的颜色,那么分配给给定中心的每个点都将涂上该颜色。只要您有足够的密度,这样做就能很好地显示每个Voronoi中心的边界(作为分隔两种颜色的边界)。
如何选择沃罗诺伊中心?我使用两个正交准则。随机选择w点后,为您的训练数据计算VT。接下来,检查分配给每个Voronoi中心的数据点数-这些值应大致相同(在整个数据空间中均采用统一的点密度)。在二维中,这将导致VT具有相同大小的图块,这是第一条规则,这是第二条规则。通过迭代选择w-使用w作为变量参数运行kNN算法,然后测量性能(通过查询VT返回预测所需的时间)。
因此,假设您有一百万个数据点.....如果这些点被保存在普通的2D数据结构或kd树中,则平均需要进行数百万次的距离计算 每个点您希望预测其响应变量的新数据点。当然,这些计算是在单个数据集上执行的。借助V / T,分两步对两个不同的数据群进行最近邻居搜索-首先对Voronoi中心进行搜索,然后在找到最近的中心后,单元内的点对应于搜索该中心以找到实际的最接近的邻居(通过连续的距离计算)。结合起来,这两个查找要比单个暴力查找快得多。这很容易看到:对于1M个数据点,假设您选择250个Voronoi中心来整理数据空间。平均每个Voronoi单元将拥有4,000个数据点。因此,您不必执行平均500,000次距离计算(强力),而是执行更少的操作,平均只需125 + 2,000。
三,计算结果(预测的响应变量)
根据一组kNN训练数据计算预测值有两个步骤。第一个是标识n或用于此计算的最近邻居的数量。第二个是如何加权他们对预测值的贡献。
W / r / t是第一个组件,您可以通过解决优化问题(与最小二乘法最相似)来确定n的最佳值。那是理论;实际上,大多数人只使用n = 3。无论如何,很容易在一组测试实例(用于计算n = 1,n = 2,n = 3等)上运行kNN算法(以计算预测值),并将误差绘制为n的函数。如果您只是想让n成为一个合理的值,请再次使用n = 3。
第二部分是如何加权每个邻居的贡献(假设n> 1)。
最简单的加权技术是将每个邻居乘以一个加权系数,加权系数仅为1 /(dist * K),即从该邻居到测试实例的距离的倒数,通常乘以一些经验得出的常数K。不喜欢这种技术,因为它常常使最近的邻居过重(并同时使距离较远的邻居过轻);这样做的意义在于,给定的预测几乎可以完全取决于单个邻居,从而提高了算法对噪声的敏感度。
必须更好地加权的函数,实质上避免了这种限制的是高斯函数,在python中看起来像这样:
def weight_gauss(dist, sig=2.0) :
return math.e**(-dist**2/(2*sig**2))
要使用kNN代码计算预测值,您需要确定要预测其响应变量的数据点的n个最近邻居(“测试实例”),然后为n个邻居中的每个邻居调用一次weight_gauss函数,该函数将返回每个邻居的权重,然后将其用作加权平均计算中该邻居的系数。