求3000个细胞在PC空间的20个最近邻,最快的实现方法是 annoy,Seurat 4也采用了该方法。具体细节见:
Annoy 牺牲了精确度,提升了运算速度。通过多次构建,求共同最近的方法,能大致正确的求出高维空间中最近的k个邻居。
1. Annoy 实现 KNN的原理
Annoy(Approximate Nearest Neighbors Oh Yeah) 是一个用于高效的最近邻搜索的库,特别适用于处理高维数据。它的基本原理如下:
- 树结构:
- Annoy 使用一种树状结构(如随机投影树)。在构建树时,数据点被随机划分,类似于 KD 树,但采用随机选择的方式。
- 每个节点使用一个随机超平面将数据点划分为两个子集。这个过程递归进行,直到达到设定的深度或数据点数量。
- 多棵树:
- Annoy 允许用户构建多棵树(例如,用户可以设置树的数量)。每棵树通过不同的随机超平面划分数据,从而增加了搜索的鲁棒性和准确性。
- 多棵树的构建增加了内存占用,但可以显著提高查询的准确性和速度。
- 查询过程:
- 在查询时,Annoy 会在所有树中并行搜索,找到与给定点最接近的点。
- 通过每棵树的搜索结果,Annoy 聚合这些结果,返回最接近的 K 个点。
2. Annoy 计算复杂度
-
构建时间复杂度:
- 构建 Annoy 索引的时间复杂度为 O(n log n),其中 n 是数据点的数量。这是因为需要构建多棵树,每棵树的构建涉及对数据的多次划分。
-
查询时间复杂度:
- 查询的时间复杂度为 O(k log n),其中 k 是要返回的最近邻的数量。通常情况下,k 是一个小值,因此查询效率较高。
-
空间复杂度:
- Annoy 的空间复杂度通常为 O(n d),其中 d 是数据的维度。每个数据点需要存储其特征向量。
Annoy 通过构建多棵随机投影树来实现高效的 K 最近邻搜索,适合高维数据。构建和查询的时间复杂度分别为 O(n log n) 和 O(k log n),使其在处理大规模数据时表现出色。
Ref
- https://sds-aau.github.io/M3Port19/portfolio/ann/