KD树和LSH局部敏感哈希

    xiaoxiao2021-03-25  220

    文档结构 文档表示距离度量 KD树 原理 构建查询 复杂度KD树的KNNKD树的逼近KNN不适用高维数据 LSH LSH潜在的问题LSH算法复杂度概率逼近多表

    文档结构

    文档表示

    词袋模型:有一些词,比如“的”,“吧”出现的频率很高,但是这些词意义不大。tf-idf:在该文档局部出现的频率高,在全部文档全局出现的频率低。

    距离度量

    常见的距离度量有:

    欧氏距离: d=Kk=1(x1kx2k)2 曼哈顿距离: d=Kk=1|x1kx2k| 切比雪夫距离: d=maxk|x1kx2k| 汉明距离:两个等长的字符串将一个变成另外一个所需的最小替换数余弦相似性: d=1x1x2|x1||x2| 内积: d=x1x2 核函数: d=K(x1,x2) 相关系数: d=Cov(x1,x2)σx1σx2

    不同的特征分布范围不同,对于变化范围很大的特征计算距离的时候要乘以相对较小的系数,对于变化范围小的特征计算距离的时候要乘以相对较大的系数。否则距离就会被变化范围较大的特征统治。另一种做法是先对源数据做归一化。

    一般的欧式距离如下:

    d(x,y)=||(xy)T(xy)||

    考虑权重后的欧式距离如下, A 是对角阵,对角线上的元素代表该特征上的距离乘数:

    d(x,y)=||(xy)TA(xy)||

    对于余弦相似性,需要注意几点:

    不是合适的距离度量,不符合三角不等式(两边之和大于第三边)计算稀疏向量的内积很有效率

    对于是否需要scale向量,需要考虑下面几点:

    如果不scale的话,那么对同样的两篇文章,重复其内容会导致相似性变大,这与常理不符合。scale的话,会忽视文章的长度,比如一篇科技论文的相似性和一篇微博的相似性会很高,但是建议阅读科技论文的读者去阅读微博是不大符合常理的。通常的做法是,cap maximum word counts,也就是设置最大的单词数以文档为例,对于文档的内容可以scale以忽略文档长度的影响,对于文档的读者数不可以scale因为它是具有切实意义的特征。

    KD树

    brute-force搜索的KNN复杂度太高,单次1NN的复杂度是 O(N) ,单次KNN的复杂度是 O(NlogK) 。如果N很大,查询次数很多的话,那么效率很低。

    原理

    KD树通过不断划分样本到不同的子空间,构建二叉树的结构,通过剪枝实现了效率更高的查询,在低维空间表现较好。

    构建

    确定split特征(更宽更广的特征;alternating)确定split的特征值(median;center point of box)split数据到两部分对分支的数据递归构建KD树直到到达停止条件(min leaf nodes; min box width)

    每个node上需要记录以下信息:

    split的特征split的特征值该node以下包含的节点区域

    查询

    由根节点从上到下找到对应包含查询点的叶节点计算该区域内的点到查询点的最小距离回溯(backtrack)其他分支,如果该分支区域与到查询点最小距离构成的圆相交,那么进一步深入该区域查询;如果不相交,那么对该分支剪枝继续回溯,直到到达根节点。

    复杂度

    构建的复杂度: O(NlogN) 单次查询的复杂度: O(logN)O(N) ,复杂度与维度是指数关系。

    KD树的KNN

    保留距离的时候,只需要把1NN中的离查询点最小的距离改成离查询点最小的第K个距离即可。

    KD树的逼近KNN

    实际计算的时候,假设已获得的离查询点最近的距离是 r ,那么剪枝的标准由d>r变成 d>r/αα>1 ,相当于更容易剪枝。

    这样做,虽然可能找不到最近的NN,但是可以保证一旦我们找到的NN距离是 r ,那么没有其他点的距离小于r/α。实际中,我们定义的向量表示、距离度量都不一定是百分百地反映其本质的,所以逼近KNN通常可以取得很好的结果,关键更容易剪枝,实现了更高的查询效率。

    不适用高维数据

    查询的复杂度随维度上升指数增长,通常要求 N>>2d 。距离对不相关的特征很敏感,高维空间中每个点都分离很远,最短距离构成的圆和很多点都相交。需要特征选择,判断哪个特征更优。

    LSH

    KD树实现检索有以下缺点:

    实现起来没那么有效复杂度随特征维度指数增加,不适合高维情况高维情况下,一旦发现了最近的点,那么以到最近的点距离为半径的超球体几乎与大多超多面体相交,导致剪枝效率不高。

    LSH通过建立hash表,将数据分散到不同的部分,检索的时候只需要检索hash到的那部分的点即可。该方法提供了大概率上发现NN的方法。进一步提高NN概率的方向有两个:在当前hash表内,不仅检索当前的部分还检索周围的部分;建立多个hash表。

    如下图所示,根据点在直线上下进行hash,将数据分为两部分,检索的时候只需要检索对应hash后的那部分的数据即可。

    LSH潜在的问题

    LSH潜在的问题如下:

    怎么找到好的直线(好的hash函数)最坏的情况怎么样hash后的部分可能包含很多点,这样进一步检索的复杂度仍然很大

    针对第一个问题,随机划分即可。在随机划分下,针对第二个问题,用一条直线划分,最坏情况的概率是 θπ θ 代表NN点距离样本点的夹角。

    针对第三个问题,那我多用几条直线划分,每个bin中的点就小了。

    如果想进一步提高精度的话,在计算能力范围内在bin的周围多检索几个bin就可以了。

    LSH算法

    复杂度

    LSH构建hash表的复杂度为:hash表的个数*超平面的个数*数据的维度*训练数据

    LSH构建hash表后检索的复杂度为:hash表的个数*表中检索bin的个数*每个bin的数据

    概率逼近

    多表

    如果检测三个bin,有两种方法:

    建立一个表,找到检索点对应的bin后,在其周围找到两个bin。建立三个表, 每个表各找一个bin。

    一般来说,当hash表中的直线(位数)越多时,第二种方法概率保证上效果更好,缺点是需要计算多个表,计算复杂度比较高。

    实际中,我们一般固定bits的位数(一个hash表中划分超平面的个数,然后增大hash表的个数。

    转载请注明原文地址: https://ju.6miu.com/read-276.html

    最新回复(0)