问题描述
我有一个 n*m 数组“a”,另一个一维数组“b”,如下所示:
a = array([[ 51,30,20,10],[ 10,32,65,77],[ 15,77,30]])
b = array([10,15,51,77])
我想将“a”中的所有元素替换为该元素所在的“b”的相应索引。在上述情况下,我希望输出为:
a = array([[ 5,3,2,0],[ 0,4,6,7],[ 1,7,3]])
请注意,在实际应用中,我的数组很大,超过 30k 个元素和数千个元素。我试过 for 循环,但这些需要很长时间来计算。我也尝试过类似的迭代方法,并使用 list.index() 来获取索引,但这也需要太多时间。
谁能帮我首先确定出现在“b”中的“a”元素的“b”索引,然后构造更新的“a”数组?
谢谢。
解决方法
如果 a,b
的最小/最大元素形成一个小范围(或至少小到足以放入 RAM),则可以使用查找表非常快速地完成此操作:
a = np.array([[51,30,20,10],[10,32,65,77],[15,77,30]])
b = np.array([10,15,51,77])
lo = min(a.min(),b.min())
hi = max(a.max(),b.max())
lut = np.zeros(hi - lo + 1,dtype=np.int64)
lut[b - lo] = np.arange(len(b))
那么:
>>> a_indices = lut[a - lo]
>>> a_indices
array([[5,3,2,0],[0,4,6,7],[1,7,3]])
,
这只是作为答案发布的,因为评论太长了。它支持上面发布的 orlp 的解决方案。 Numpy 的 vectorize 避免了显式循环,但这显然不是最好的方法。 请注意,Numpy 的 searchsorted 只能在 b 已排序时如图所示应用。
import timeit
import numpy as np
a = np.random.randint(1,100,(1000,1000))
b = np.arange(0,1000,1)
def o1():
lo = min(a.min(),b.min())
hi = max(a.max(),b.max())
lut = np.zeros(hi - lo + 1,dtype=np.int64)
lut[b - lo] = np.arange(len(b))
a2 = lut[a - lo]
return a2
def o2():
a2 = a.copy()
fu = np.vectorize(lambda i: np.place(a2,a2==b[i],i))
fu(np.arange(0,len(b),1))
print(timeit.timeit("np.searchsorted(b,a)",globals=globals(),number=2))
print(timeit.timeit("o1()",number=2))
print(timeit.timeit("o2()",number=2))
印刷品
0.061956800000189105
0.012765400000716909
2.220097600000372