您的位置:首页 > 编程语言 > Java开发

JAVA拾遗 - 优先队列的探讨以及其在KNN算法中的应用

2016-08-28 11:40 337 查看
这几天导师安排写一个微博签到数据依据地理坐标的分类,所以有一段时间没有更新博客了,不过正好也在这次代码的写作中学习了一些新的姿势,写这篇博客跟大家分享下心得。


优先队列

定义

所谓的优先队列,就是在普通队列的基础上,对于每个点维护一个“优先”值,这个优先值决定了优先队列的出队顺序。优先队列内的元素不能够是空的

JAVA中的优先队列

在JAVA的优先队列(java.util.priorityQueue)内部维护了一个优先堆(priority heap),他的优先值比较是通过实现一个Comparator< T>接口进行实现的,这个接口决定了你打算怎么衡量优先度对出队的顺序,是打算先出大的,还是先出小的,或者先出优先值接近某个值的…Comparator< T>接口的实现代码如下:

static Comparator<priorityQueue> OrderIsdn =  new Comparator<priorityQueue>(){
public int compare(priorityQueue o1, priorityQueue o2) {
// TODO Auto-generated method stub
double numbera = o1.getPopulation()
c50a
;
double numberb = o2.getPopulation();
if(numberb > numbera)
{
return 1;  //优于比较值
}
else if(numberb<numbera)
{
return -1;  //劣于比较值
}
else
{
return 0;  //相等
}

}
};


关于这个comparator我们可以玩出花来,这里就先不探讨了。

优先队列的构造方法如下所示

PriorityQueue() //Creates a PriorityQueue with the default initial capacity (11) that orders its elements according to their natural ordering.

PriorityQueue(Collection<? extends E> c) //Creates a PriorityQueue containing the elements in the specified collection.

PriorityQueue(Comparator<? super E> comparator) //Creates a PriorityQueue with the default initial capacity and whose elements are ordered according to the specified comparator.

PriorityQueue(int initialCapacity) //Creates a PriorityQueue with the specified initial capacity that orders its elements according to their natural ordering.

PriorityQueue(int initialCapacity, Comparator<? super E> comparator) //Creates a PriorityQueue with the specified initial capacity that orders its elements according to the specified comparator.

PriorityQueue(PriorityQueue<? extends E> c) //Creates a PriorityQueue containing the elements in the specified priority queue.

PriorityQueue(SortedSet<? extends E> c) //Creates a PriorityQueue containing the elements in the specified sorted set.


优先队列通过两个方法进行取值,第一个是

peek();


也就是偷偷看一眼要出来的值,这个行为不会导致这个值从优先队列中删除

第二个是

poll();


这个行为会导致优先队列中的值被弹出

好了优先队列是一个很简单的概念,我们来看看应用:

poi点签到与优先队列

问题的提出

做微博签到点分类的重要思想就是根据该坐标点的位置讯息以及周围poi点的讯息进行一个微博签到数据的“打标签”。想到这里很容易就能够引入一个东西–也就是KNN算法。

KNN算法能够在给定的一个训练集中,每次输入一个测试集,返回在逻辑上距离这个输入的测试集最近的k个推荐点,如下所示:

//以k=4为例
(x1 ,x2) a
(x3 ,x4) b
(x5 ,x6) c
(x7 ,x8) a


然后,再依据这k个推荐点内的标签数量进行排序。过程是真的有点mapreduce的味道~

//以k=4为例
a 2
b 1
c 1


可是这样分类会有一个什么问题呢?

那就是分类的依据可以说单单依据坐标,如果想加入个“时间”维、“性别”维、“这个poi点签到数量”维的话会很困难,因为你很难去将坐标反应的距离与其他的维度进行一个归一化。

同时如果在KNN中引入这些维度的话,可能某地会有一个极端火热的poi点,这个点对男女、不同时间上都有大量的签到数量(比如说“武汉市”这个大的poi点),那么在KNN内进行这种权值计算的话,就会导致不论输入的点的请况,都会被分到这个极端点。

那应该怎么解决呢

解决思路

我们先依据距离先对预选点进行限制(这也是poi对微博进行分类的前提思想)

首先还是之前的流程,我们通过向KNN算法内输入一个坐标,先得到距离这个坐标最近的k个点

然后我们对这k个点入优先队列,并在队列内依据距离、签到数量、性别、时间等维度计算每个点的权值,以这个权值为优先队列的优先值。

这样的思路就能够解决“点王”出现的可能。

总结

之前使用纯距离分类,准确率能达到89%左右,但是这个结论在理论上是很难站住脚的,因为参数太少了,而且我们一开始只设置了11个标签进行poi点分类,这11个标签里面有个“51”类占全部标签的70%,几乎所有的分类结果都成了“51”标签,所以才能达到这个准确度。

之后我们在实验中引入了更多的变量,并对这些更多的变量进行KNN,发现实验效果更差了,退到了20%~30%,甚至后面坐的哥们搞出了个9%。

所以这次我改进了下代码,使用更多的标签(几十到几百个小标签),并且使用了前面说到的思想对KNN算法进行改进。

结果嘛~嘿嘿…91.45%(对签到数据取一万次随机样本,取四次实验平均值,k值取10)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: