一种方法是使用
numpy.unique
提取值的计数。
然后将其转换为字典,并使用
numpy.vectorize
来利用这个字典映射。
import numpy as np
A = np.array([[2,2,3,3],
[2,3,3,3],
[3,3,4,4]])
d = dict(zip(*np.unique(A.ravel(), return_counts=True)))
res = np.vectorize(d.get)(A)
array([[3, 3, 7, 7],
[3, 7, 7, 7],
[7, 7, 2, 2]], dtype=int64)
性能
我发现上述方法对于一个2000x2000的数组需要大约2秒,而使用基于collections.Counter
字典的方法需要3秒。但是PaulPanzer和BradSolomon提出的纯numpy
解决方案仍然更快。
import numpy as np
from collections import Counter
A = np.random.randint(0, 10, (2000, 2000))
MAX_LOOKUP = 2**24
def map_count(A):
d = dict(zip(*np.unique(A.ravel(), return_counts=True)))
return np.vectorize(d.get)(A)
def map_count2(A):
d = Counter(A.ravel())
return np.vectorize(d.get)(A)
def bs(A):
_, inv, cts = np.unique(A, return_inverse=True, return_counts=True)
return cts[inv].reshape(A.shape)
def pp(a):
mn, mx = a.min(), a.max()
span = mx-mn+1
if span > MAX_LOOKUP:
raise RuntimeError('values spread to wide')
a = a - mn
return np.bincount(a.ravel(), None, span)[a]
%timeit map_count(A)
%timeit map_count2(A)
%timeit bs(A)
%timeit pp(A)