根据原始的paper,我编写了自己的共享最近邻(SNN)聚类算法。本质上,我得到每个数据点的最近邻居,用Jaccard距离预先计算距离矩阵,然后将距离矩阵传递给DBSCAN。
为加速算法,我仅计算两个数据点之间的Jaccard距离(如果它们是彼此最近的邻居,并且具有一定数量的共享邻居)。我还利用了距离矩阵的对称性,因为我只计算矩阵的一半。
但是,我的算法较慢,并且比K-Means或DBSCAN等常见聚类算法花费的时间更长。有人可以看一下我的代码并提出建议,以改善我的代码并使算法更快吗?
def jaccard(a,b):
"""
Computes the Jaccard distance between two arrays.
Parameters
----------
a: an array.
b: an array.
"""
A = np.array(a, dtype='int')
B = np.array(b, dtype='int')
A = A[np.where(A > -1)[0]]
B = B[np.where(B > -1)[0]]
union = np.union1d(A,B)
intersection = np.intersect1d(A,B)
return 1.0 - len(intersection)*1.0 / len(union)
def iterator_dist(indices, k_min=5):
"""
An iterator that computes the Jaccard distance for any pair of stars.
Parameters:
indices: the indices of nearest neighbors in the chemistry-velocity
space.
"""
for n in range(len(indices)):
for m in indices[n][indices[n] > n]:
if len(np.intersect1d(indices[n], indices[m])) > k_min:
dist = jaccard(indices[n], indices[m])
yield (n, m, dist)
# load data here
data =
# hyperparameters
n_neighbors =
eps =
min_samples =
k_min =
# K Nearest Neighbors
nbrs = NearestNeighbors(n_neighbors=n_neighbors).fit(data)
distances, indices = nbrs.kneighbors()
# distance matrix
S = lil_matrix((len(distances), len(distances)))
for (n, m, dist) in iterator_dist(indices, k_min):
S[n,m] = dist
S[m,n] = dist
db = DBSCAN(eps=eps, min_samples=min_samples, metric='precomputed',
n_jobs=-1).fit(S)
labels = db.labels_
答案 0 :(得分:0)
编写快速的python代码是 hard 。关键是尽可能避免使用python,而是通过numpy使用BLAS例程,或者例如使用未经解释的编译代码的cython。因此,在某些时候,您至少需要从“真实” python切换到键入的cython代码。除非您找到一个已经对您足够低级别实施这些操作的库。
但是显而易见的第一步是运行 profiler 来识别缓慢的操作!
第二,考虑避免距离矩阵。除非非常小心,否则涉及距离矩阵的任何事物都倾向于按O(n²)缩放。当然,这要比k均值和欧几里得DBSCAN慢得多。