快速/记忆保存方式,如果它们在欧几里德空间中太近,则从阵列中移除矢量

时间:2016-08-24 17:58:23

标签: python arrays algorithm matrix memory-management

为了使聚类成为一个更可行的任务,我想从数组中删除项目,如果它们有另一个项目在n维欧几里德空间的某个阈值内。该截断的输入数据是像素方式的特征向量的数组。我的第一个想法是计算所有项目之间的成对欧氏距离矩阵,然后对它们进行操作:

indices = list(range(len(X)))
dist_matrix = euclidean_distances(X,X)

index = 0
while True:
    deletion = np.where(dist_matrix[index]<=threshold)[0]
    indices = [i for i in indices if i==index or i not in deletion]
    try:
        index = indices[indices.index(index) + 1]
    except IndexError:
        break

dictionary = []
for index in indices:
    dictionary.append(X[index])

但是,当使用sklearn.metrics.pairwise.euclidean_distances创建距离矩阵时,这会导致我的大型数据集出现内存错误。执行此操作的有效,记忆保守的方式是什么?我已经意识到这个距离矩阵的计算是导致聚类算法出现问题的原因,所以我希望能够通过截断输入数组来避免计算这么大的距离矩阵。

3 个答案:

答案 0 :(得分:1)

根据尺寸数n,点数N,每个尺寸L中问题的大小以及可接受的间隔距离d,一个选项是将您的空间划分为尺寸d的框并保留最多每个网格框中的一个点。内存需求将从O(N ^ 2)变为O((L / d)^ n),运行时间将从O(N ^ 2)变为O(N +(L / d)^ n),因此如果L / d和n不是太大,它可能会更有效。

或者,使用以下算法

可能是切实可行的
 for each point p in points
   for each point q in points
     if p <> q and p.dist(q) < Dmin
       q.delete

这应该是O(N ^ 2)运行时间和O(0)额外内存。

答案 1 :(得分:0)

KD树应该比你的基本方法更快/更有效,而scipy对你的用例有一个很好的实现。运行时是O(nlog(n)),虽然我不确定内存使用,但我们假设它只存储你想要删除的对。

从运行时的角度来看,Pengiuno对网格采样方法的建议可能更快,但使用scipy需要更少的额外编码。

http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.KDTree.query_ball_tree.html#scipy.spatial.KDTree.query_ball_tree

答案 2 :(得分:0)

根据Penguino的建议,我把包含我的观点的超大角度网格化了。由于维度的数量是未定义的(我有多个向量长度,我在不同的点处理),我实际上不能在没有递归的情况下对空间进行分区(我对此有点懒惰) ,所以我基于将每个维度拆分为 d 块创建了一个变通方法。我根据该块的相对密度在每个块中选择多个点。这种操作稍微昂贵,但在内存保护方面是一个不错的解决方法。另一种解决方法是对向量​​列表进行分块并计算每个块的成对距离矩阵,并递归地构建简化向量列表。

def ndimcube_grid(X,ndim,d):
    dictionary = []
    for n in range(ndim):
        maximum = np.amax(X[:,n])
        minimum = np.amin(X[:,n])
        chunk = (maximum - minimum)/d
        iterate = minimum
        lengths = []
        while iterate < maximum:
            a = np.where(X[:,n] < (iterate + chunk))[0]
            b = np.where(X[:,n] >= iterate)[0]
            indices = list(set(a) & set(b))
            lengths.append(len(indices))
            iterate += chunk

        min_length = np.amin([length for length in lengths if not(length == 0)])
        iterate = minimum
        while iterate < maximum:
            a = np.where(X[:,n] < (iterate + chunk))[0]
            b = np.where(X[:,n] >= iterate)[0]
            indices = list(set(a) & set(b))
            size = int(np.round(len(indices)/min_length))
            MAX_DENSITY = 25
            size = np.minimum(size,MAX_DENSITY)
            if size > 0:
                selections = np.random.choice(indices,size=size)
                try:
                    for selection in selections:
                        if len(dictionary) > 0:
                            if np.amin(euclidean_distances(dictionary,X[selection]))>ndim:
                                dictionary.append(X[selection])
                        else:
                            dictionary.append(X[selection])
                except TypeError:
                    dictionary.append(selections)
            iterate += chunk

    return np.array(dictionary)