在 numpy 中向量化简单的 for 循环

Vectorize simple for loop in numpy

我是 numpy 的新手,出于性能原因,我正在尝试 向量化一个简单的 for 循环 ,但我可以'似乎想出了一个解决办法。我有一个带有唯一单词的 numpy 数组,对于这些单词中的每一个,我需要它们在另一个名为 array_to_compare 的 numpy 数组中出现的次数。该数字被传递给第三个 numpy 数组,该数组与唯一单词数组具有相同的形状。 这是包含 for 循环的代码:

import numpy as np

unique_words = np.array(['a', 'b', 'c', 'd'])
array_to_compare = np.array(['a', 'b', 'a', 'd'])
vector_array = np.zeros(len(unique_words))

for word in np.nditer(unique_words):
    counter = np.count_nonzero(array_to_compare == word)
    vector_array[np.where(unique_words == word)] = counter

vector_array = [2. 1. 0. 1.]    #the desired output

我用 np.where 和 np.isin 试过了,但没有得到想要的结果。感谢您的帮助!

我可能会使用 Counter 和列表理解来解决这个问题:

In [1]: import numpy as np
   ...:
   ...: unique_words = np.array(['a', 'b', 'c', 'd'])
   ...: array_to_compare = np.array(['a', 'b', 'a', 'd'])

In [2]: from collections import Counter

In [3]: counter = Counter(array_to_compare)

In [4]: counter
Out[4]: Counter({'a': 2, 'b': 1, 'd': 1})

In [5]: vector_array = np.array([counter[key] for key in unique_words])

In [6]: vector_array
Out[6]: array([2, 1, 0, 1])

组装 Counter 是在线性时间内完成的,迭代 unique_words 也是线性的。

类似于@DanielLenz 的回答,但使用 np.unique 创建一个 dict:

import numpy as np
unique_words = np.array(['a', 'b', 'c', 'd'])
array_to_compare = np.array(['a', 'b', 'a', 'd'])
counts = dict(zip(*np.unique(array_to_compare, return_counts=True)))
result = np.array([counts[word] if word in counts else 0 for word in unique_words])
[2 1 0 1]

使用broadcasting:

对数组值进行numpy比较
In [76]: unique_words[:,None]==array_to_compare
Out[76]: 
array([[ True, False,  True, False],
       [False,  True, False, False],
       [False, False, False, False],
       [False, False, False,  True]])
In [77]: (unique_words[:,None]==array_to_compare).sum(1)
Out[77]: array([2, 1, 0, 1])

In [78]: timeit (unique_words[:,None]==array_to_compare).sum(1)
9.5 µs ± 2.79 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

不过Counter也是不错的选择:

In [72]: %%timeit
    ...: c=Counter(array_to_compare)
    ...: [c[key] for key in unique_words]
12.7 µs ± 30.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

可以改善您对 count_nonzero 的使用
In [73]: %%timeit
    ...: words=unique_words.tolist()
    ...: vector_array = np.zeros(len(words))
    ...: for i,word in enumerate(words):
    ...:     counter = np.count_nonzero(array_to_compare == word)
    ...:     vector_array[i] = counter
    ...: 
23.4 µs ± 505 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

列表迭代比数组迭代快(nditer增加不多)。 enumerate 让我们跳过 where 测试。