python 计算非唯一数组元素的顺序

thigvfpy  于 2023-11-15  发布在  Python
关注(0)|答案(1)|浏览(94)

我正在寻找一种有效的方法来计算numpy数组中每个元素的“order”,其中“order”定义为等于该元素的前面元素的数量。示例:

order([4, 2, 3, 2, 6, 4, 4, 6, 2, 4])
[0 0 0 1 0 1 2 1 2 3]

字符串
目前的解决方案在纯Python中循环,速度不够快:

def order(A):
    cnt = defaultdict(int)
    O = np.zeros_like(A)
    for i, r in enumerate(A):
        O[i] = cnt[r]
        cnt[r] += 1
    return O


我使用order来实现scatter

def scatter(A, c):
    R = A % c
    I = c * order(R) + R
    B = np.full(np.max(I) + 1, -1)
    B[I] = A
    return B


这对多线程很有用。例如,如果分散的数组包含要写入的地址,那么并行处理数组的两个线程将不会看到相同的地址。
问题是,是否有我遗漏的numpy内置函数可以用来使order更快,并删除显式循环?

2w2cym1i

2w2cym1i1#

由于你所做的本质上是一个Pandas cumcount,而Pandas在内部使用NumPy,一个想法是看看他们是如何实现cumcount的,并做同样的事情。
如果你读了Pandas的cumcount代码,它在内部是这样实现的:

  • 对数组进行排序,跟踪每个元素的来源。
  • 将已排序数组的每个元素与下一个元素进行比较。如果不同,则开始新的运行。(run
  • 求出每组的长度。(rep
  • 进行累计求和,对于不属于新运行的每个元素递增1。(out
  • 跟踪每个组受其之前的组影响的程度,这不应该计数。(out[run]
  • 重复该值减去rep
  • 撤消初始排序以将元素放回其原始位置。

下面是如何在不依赖任何Pandas的情况下做同样的事情。

def order(array):
    # https://github.com/pandas-dev/pandas/blob/v1.3.5/pandas/core/groupby/groupby.py#L1493
    if len(array) == 0:
        return np.array([])
    count = len(array)
    # Can remove 'stable' here to increase speed if you
    # don't care what order the order is assigned in
    ind = np.argsort(array, kind='stable')
    array = array[ind]
    run = np.r_[True, array[:-1] != array[1:]]
    rep = np.diff(np.r_[np.nonzero(run)[0], count])
    out = (~run).cumsum()
    out -= np.repeat(out[run], rep)
    rev = np.empty(count, dtype=np.intp)
    rev[ind] = np.arange(count, dtype=np.intp)
    out = out[rev]
    return out

字符串
我发现这对于1000个元素和更大的数组来说快了大约10倍。

相关问题