在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
本节书摘来自华章计算机《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一书中的第1章,第1.5节,作者:[美] 德博拉·诺兰(Deborah Nolan) 邓肯·坦普·朗(Duncan Temple Lang) 更多章节内容可以访问云栖社区“华章计算机”公众号查看。 1.5 预测位置的最近邻方法通过探测设备和若干个接入点之间的信号强度,我们可以使用很多种不同的统计技术来估计设备所处的位置。这里,我们使用一种相对简单、直观的方法,称为k-最近邻方法,或者简称为k-NN。最近邻方法(k=1)背后的思想为:我们已经拥有从遍布在大楼的已知位置上的多个接入点测量到的训练数据,这样,当我们拿到一个新的观测记录时,即一个未知位置上的一组信号强度值,我们从训练数据中找出与这个新观测记录最接近的观测记录。所谓“最接近”的意思是,在接入点与这个以前未观测的新位置之间记录到的信号强度,接近于在该接入点与训练数据中已观测到的位置之间的信号强度。然后,我们可简单地预测出,新观测点的位置就是与它最接近的训练观测点的位置。对k大于1的k-最近邻,我们找出k个最近的训练点(在信号强度范围内),通过聚合k个训练点的位置估算出新的观测点的位置。 其中,Si是在手持设备与第i个接入点之间检测到的信号,属于在一些特定位置上观测到的训练数据;Si*是在新观测点与同一个接入点之间检测到的信号,该观测点的位置(x,y)正是我们所要预测的。 有了这些测量记录所在的位置,就可以评估我们所做预测的精度。如同对待离线数据,我们也为在线数据创建唯一的位置标识符,执行如下: 使用这个新变量,可以确定出我们有60个唯一的测试位置,即 我们还要计算出在每个位置上所记录的信号强度的个数,执行: 这个输出结果说明,对于每个位置,只在一个方向上记录到了信号强度。 在数据框中,我们只保留了用于预测和评估的那些变量。这个新数据框应该有60行和11个变量,包括对应于MAC地址的6个平均信号强度。我们确认如下: 1.5.2 方向的选择 注意,我们分别处理m为奇数和偶数的情况。我们也必须将角度映射为refs中的值,例如,-45映射为335,405映射为45,这样我们调整angles如下: 当我们有了所需要角度的数据子集之后,就可从offlineSummary中选择观测记录进行分析: 然后,我们从这些角度数据中聚集信号强度,创建一个类似于onlineSummary的数据结构。为了避免重复代码,我们将这些计算转化成一个辅助函数,称为reshapeSS(): 我们对offlineSubset 进行汇总,并调整结构: 用于选择角度和调用reshapeSS()的代码可包装到一个函数里,这留作练习题。该函数有3个参数:angleNewObs为新观测点的角度,signals为训练数据(遵照offlineSummary格式的数据),m为signals中所要包含的角度个数。该函数返回一个与上面trainSS相匹配的数据框。 为了提高可读性,我们对执行结果的格式稍微进行了调整: selectTrain()函数对各个角度取信号强度的平均值,为训练数据中的166个位置中的每一个位置产生一组信号强度,即 当然,我们也可以不对m个角度做信号强度的压缩处理,而是为每个接入点返回一组m×166的信号。我们把这个替代方案留作练习题。 这个函数的参数是由6个新的信号强度组成的一个数值型向量,以及来自selectTrain()函数的返回结果值。我们的函数将按照与新观测点信号强度接近程度的大小次序,返回训练观测点的位置。 当然,我们不必只做简单的平均。例如,我们可在平均值计算中使用权重,权重的大小反比于该位置与测试观测点之间的距离(按照信号强度)。在这种情况下,我们需要使用从findNN()函数返回的距离值。这个替代方案允许我们包含k个相近的点,但按照它们与新观测信号的实际接近程度,对它们加以区分。对于观测信号的第i个最近邻,其权重可按如下公式计算: 其中,di是从新观测点到最近参照点(在信号强度空间内)的距离。也可考虑使用不同的度量方法。我们已经用过欧氏距离,但也可以尝试曼哈顿距离。在将邻居组合在一起预测(x,y)时,如果用于求平均的值的分布是非常倾斜的,也可以倾向于使用中位数,而不是平均值。这个替代方案留作练习题。 我们用3个最近邻和3个方向对该函数进行测试: 为了评估该模型的拟合度,我们绘制一张包含实际位置和预测位置的地图。图1-12给出关于该模型和1-NN模型的地图。注意,一般来说,3-NN的误差较小。在3-NN模型中,即使存在大的误差看起来也没有什么问题,因为它们通常发生在走廊里。 我们将这个函数应用到上述两个误差集合上,可以发现: 这个结果证实我们在图中所看到的,3近邻确实比1近邻能够更好地预测位置。但还保留一个疑问:是否还存在有其他的k值,可用于建立更好的预测器。 图1-12 显示出预测位置和实际位置的楼层平面图。楼层平面图中的线段将测试位置(黑点)连接到它们的预测位置(星花)上。上方的图给出k=1最近邻的预测结果,下方的图给出k=3最近邻的预测结果。在该模型中,我们使用的训练数据是平均信号强度,这些信号强度来自166个离线位置(灰点)中的每一个位置,每个位置接收到6个接入点(黑方块)的信号,每个接入点上取出3个与测试数据的角度最接近的角度上的信号强度 我们在调用matrix()时接收到一个警告信息,它指出v不能整除166,所以permuteLocs不能包含全部的166个位置。我们将包含15个位置的每个子集用作“在线”数据或测试数据。例如,第一重在线数据是: 我们需要对这些数据进行汇总,使得该数据结构与onlineSummary相匹配。这包括随机地选择一个方向,因为每个测试观测点只有一个方向(虽然我们也可从8个方向中找出最近邻的一个,但我们这里采用较简单的方式)。 我们将这段代码合并进reshapeSS()函数中,并扩充该函数的定义,使其包含缺省值为FALSE的sampleAngle变量。之后,我们就可以对offline进行汇总和格式化如下: 现在,第一重数据是: 这个数据结构使得我们可以很容易地使用前面的代码来发现最近邻。第一重训练数据为: 这个数据子集也符合我们在前面应用最近邻方法所需要的正确格式。即对于这些在线数据和离线数据的交叉验证版本,我们可以使用predXY()函数: 然后,可以得出所做估计的误差: 对于每一重数据,我们想要对k=1, 2, …, K(K为适当大的值),找出k-NN估计。我们也要汇总所有v重子集中的误差。先简单地把前文中的代码包装进上面关于重数和邻居数的嵌套循环中。令K=20,执行如下: 图1-13给出了作为k的函数的误差平方和。我们看到该误差在开始时大幅度地减小,例如k = 1,2,3时。然后,误差在k = 5,6,7附近时呈平缓状态,之后,误差还是缓慢地增加,这是因为邻居在地理位置上太分散。 图1-13 利用交叉验证选择k。该曲线图显示出,误差平方和是用于预测新观测点位置的邻居个数的函数,它是通过对离线数据的交叉验证而得到的 然后,我们计算预测中的误差如下: 早先,当k=1和k=3时的误差分别是659和307。选择k=5也许不能最小化在线数据上的误差,因为该值的选择并没有参考在线数据。这就是我们使用交叉验证的原因,即我们在选择k和评估预测时,均不使用在线数据。 我们记得,findNN()返回训练数据中的所有位置,并按照它们与新观测点信号强度的距离进行排序。我们可以使用开始的k个位置,但是,由于我们拥有所有的位置,因此可以计算出感兴趣的所有k值的估计值。cumsum()函数在这里非常有帮助,即cumsum(x[1:K])/(1:K)提供K均值。如果我们修改predXY(),使其返回所有的K估计值,则可以删除k上的内部循环。这将极大地加速代码。我们把对这个问题的探讨留作练习题。 |
请发表评论