我有一个一维单词数组。对于每个单词,我需要抓住它出现的每个句子,这些句子在单独的1D数组中定义。

带for循环的简单工作示例:

import numpy as np

sentences = np.array(['This is an apple tree', 'The cat is sleeping'])
words = np.array(['apple', 'dog', 'cat'])
matches = []

for word in words:
    for sentence in sentences:
        if word in sentence:
            matches.append([word, sentence])

print(matches)


如何将这个操作向量化?我尝试使用np.wherenp.select,但是似乎没有让我进行in比较的情况。

# select example
conditions = [words in sentences]
choices = [words]
print(np.select(conditions, choices))

# where example
print(np.where(words in sentences))


两者都产生:

ValueError: shape mismatch: objects cannot be broadcast to a single shape


也许我需要以某种方式雇用np.allnp.any

最佳答案

这个问题可以用两种不同的方式来解释,但解决方案略有不同。您要查找子字符串吗?还是要在字边界上找到匹配项?

查找子串

numpy.char提供了一些矢量化的字符串匹配功能:

>>> np.char.find(sentences[None,:], words[:,None])
array([[11, -1],
       [-1, -1],
       [-1,  4]])


类似于Python自己的find函数,当未找到子字符串时,此方法返回-1,否则返回子字符串的索引。 [None,:][:,None]选择器只是简单地调整了数组的形状以使其可广播。

这非常深入numpy esoterica,因此深入了解YMMV。文档报告有关numpy.char中功能的信息:


  它们全部基于Python标准库中的字符串方法。


如果这意味着它在内部调用Python函数,那么它不会很快,但是矢量化仍然可以提供一定的加速。

为了完全回答您的问题,您现在可以在输出上调用np.wherenp.c_,如下所示:

>>> r, c = np.where(np.char.find(sentences[None,:], words[:,None]) != -1)
>>> matches = np.c_[words[r], sentences[c]]
>>> matches
array([['apple', 'This is an apple tree'],
       ['cat', 'The cat is sleeping']],
      dtype='<U21')


(感谢Divakar提供最后的建议。)

查找精确的单词匹配

如果您的目标是匹配确切的单词而不是子字符串,那么最好将句子拆分为单词数组。在自然语言处理术语中,这称为标记化。然后的问题是句子的长度将不同,因此不会很好地适合固定大小的数组。这是解决该问题的一种方法。首先,生成一个单词(标记)数组和一个句子标签数组:

>>> s_words = np.array([w for s in sentences for w in s.split()])
>>> s_labels = np.array([i for i, s in enumerate(sentences) for w in s.split()])


然后以广播方式检查它们是否相等:

>>> r, c = (s_words[:,None] == words).nonzero()


并按照上述步骤进行操作,但是使用句子标签作为原始句子数组的索引:

>>> #               _________< -- another layer of indirection
>>> np.c_[words[c], sentences[s_labels[r]]]
array([['apple', 'This is an apple tree'],
       ['cat', 'The cat is sleeping']],
      dtype='<U21')


对于很长的单词列表和许多句子,这仍然很慢,尽管它比上面的find方法要快。有一些技巧可以使用searchsorted加快此类搜索的速度,但是它们需要一些其他逻辑来确保找到所有匹配项。答案here提供了一些指导。

最后,请注意,这只是使用Python split()方法来“标记”句子。如果要真正的标记化,可以使用nltkspacy之类的程序包中的标记化器。

关于python - 如何执行向量化检查数组中的每个单词是否出现在句子数组中?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43781911/

10-11 22:37
查看更多