Python 加速二维阵列上的NumPy循环-删除相似的行
我试图显著加快以下代码的速度,但没有效果。该代码接收二维数组并删除与数组中其他行相比过于相似的数组行。请参阅下面的代码和注释Python 加速二维阵列上的NumPy循环-删除相似的行,python,performance,numpy,vectorization,Python,Performance,Numpy,Vectorization,我试图显著加快以下代码的速度,但没有效果。该代码接收二维数组并删除与数组中其他行相比过于相似的数组行。请参阅下面的代码和注释 as0 = a.shape[0] for i in range(as0): a2s0 = a.shape[0] # shape may change after each iteration if i > (a2s0 - 1): break # takes the difference between all rows in
as0 = a.shape[0]
for i in range(as0):
a2s0 = a.shape[0] # shape may change after each iteration
if i > (a2s0 - 1):
break
# takes the difference between all rows in array by iterating over each
# row. Then sums the absolutes. The condition finally gives a boolean
# array output - similarity condition of 0.01
t = np.sum(np.absolute(a[i,:] - a), axis=1)<0.01
# Retains the indices that are too similar and then deletes the
# necessary row
inddel = np.where(t)[0]
inddel = [k for k in inddel if k != i]
a = np.delete(a, inddel, 0)
第一行:
t = np.sum(np.absolute(a[i,:] - a), axis=1)<0.01
t=np.sum(np.absolute(a[i,:]-a,axis=1)
这里有一种矢量化方法,它利用了将a
扩展到3D
然后以矢量化的方式在所有迭代中执行这些计算-
mask = (np.absolute(a[:,None] - a)).sum(2) < 0.01
a_out = a[~np.triu(mask,1).any(0)]
标杆管理
接近-
# Approach#2 from this post
def remove_similar_rows(a, thresh=0.01):
n = a.shape[0]
dists = pdist(a, 'cityblock')
idx = np.flatnonzero(dists < thresh)
sep_idx = np.arange(n-1,0,-1).cumsum()
rm_idx = np.unique(np.searchsorted(sep_idx,idx,'right'))
return np.delete(a,rm_idx,axis=0)
# @John Zwinck's soln
def pairwise_manhattan_distances(a, thresh=0.01):
d = manhattan_distances(a)
return a[~np.any(np.tril(d < thresh), axis=0)]
让我们创建一些假数据:
np.random.seed(0)
a = np.random.random((4,3))
现在我们有:
array([[ 0.5488135 , 0.71518937, 0.60276338],
[ 0.54488318, 0.4236548 , 0.64589411],
[ 0.43758721, 0.891773 , 0.96366276],
[ 0.38344152, 0.79172504, 0.52889492]])
接下来,我们需要所有行对的元素差异之和。我们可以使用:
其中:
array([[ 0. , 0.33859562, 0.64870931, 0.31577611],
[ 0.33859562, 0. , 0.89318282, 0.6465111 ],
[ 0.64870931, 0.89318282, 0. , 0.5889615 ],
[ 0.31577611, 0.6465111 , 0.5889615 , 0. ]])
现在可以应用阈值,只保留一个三角形:
m = np.tril(d < 0.4, -1) # large threshold just for this example
这表明第0行与第1行和第3行“太相似”。现在,您可以从原始矩阵中删除掩码的任何元素为真的行:
a[~np.any(m, axis=0)] # axis can be either 0 or 1 - design choice
这给了你:
array([[ 0.54488318, 0.4236548 , 0.64589411],
[ 0.43758721, 0.891773 , 0.96366276],
[ 0.38344152, 0.79172504, 0.52889492]])
总而言之:
d = sklearn.metrics.pairwise.manhattan_distances(a)
a = a[~np.any(np.tril(d < 0.4, -1), axis=0)]
d=sklearn.metrics.pairwise.manhattan\u距离(a)
a=a[~np.any(np.tril(d<0.4,-1),轴=0)]
谢谢你,史蒂夫。到目前为止,我已经添加了一个edit,它删除了delete,现在我已经包含了只对未看到的行进行计算的代码。再次感谢您的(np.absolute(a[:,None]-a))。sum(2)
在数学上是优雅的,但是如果输入的数据足够大,它就会爆炸。我试着输入一个(4000,30)的形状,花了很多秒,很多内存,然后我把它杀死了。我的答案中的曼哈顿距离(a)
在150毫秒内做同样的事情。如果输入很小,你的速度会更快。@JohnZwinck你能在你的帖子中分享你的基准测试设置吗?很简单:a=np.random.random((4000,30))
然后%timeit(np.absolute(a[,None]-a)).sum(2)
在IPython中。@JohnZwinck添加了另一种有效的方法,以及计时测试。@Jean-michelaurencenairac:只需在几个块中重复运行它。例如,在前10k行上运行该算法,然后在接下来的10k行上运行该算法,同时删除。希望您删除很多行,最后您可以将剩余的行组装成最后一行。假设我们有行号:6,10,12
“相似”。那么,是否可以删除前两行并保留最后一行,即12
?是的。删除哪些索引并不重要。只要唯一的行仍然存在。要复制您的行,我必须做一个小的更改:m=np.tril(d<0.4,k=-1)
@Jean-michelaurencenairac:你说得对,我在发布的代码中忽略了设置k=-1
。现在修好了。
m = np.tril(d < 0.4, -1) # large threshold just for this example
array([[False, False, False, False],
[ True, False, False, False],
[False, False, False, False],
[ True, False, False, False]], dtype=bool)
a[~np.any(m, axis=0)] # axis can be either 0 or 1 - design choice
array([[ 0.54488318, 0.4236548 , 0.64589411],
[ 0.43758721, 0.891773 , 0.96366276],
[ 0.38344152, 0.79172504, 0.52889492]])
d = sklearn.metrics.pairwise.manhattan_distances(a)
a = a[~np.any(np.tril(d < 0.4, -1), axis=0)]