为了使聚类成为一个更可行的任务,我想从数组中删除项目,如果它们有另一个项目在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创建距离矩阵时,这会导致我的大型数据集出现内存错误。执行此操作的有效,记忆保守的方式是什么?我已经意识到这个距离矩阵的计算是导致聚类算法出现问题的原因,所以我希望能够通过截断输入数组来避免计算这么大的距离矩阵。
答案 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需要更少的额外编码。
答案 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)