在 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
测试。
我是 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
测试。