O(n) 字符串中单词列表的出现次数
number of occurrences of list of words in a string with O(n)
我已经看过类似问题的答案:
其中 ahocorasick 算法用于显示列表中的每个单词是否存在于字符串中,复杂度为 O(n)。但是我想获取字符串中列表中每个单词的频率。
例如如果
my_string = "some text yes text text some"
my_list = ["some", "text", "yes", "not"]
我想要结果:
[2, 3, 1, 0]
我在 documentation 中没有找到这方面的确切示例,知道如何实现吗?
除了使用 ahocorasick 之外的其他 O(n) 解决方案也将不胜感激。
您可以使用列表理解来计算特定列表在 my_string 中出现的次数:
[my_string.split().count(i) for i in my_list]
[2, 3, 1, 0]
你可以用字典来统计你关心的词出现的次数:
counts = dict.fromkeys(my_list, 0) # initialize the counting dict with all counts at zero
for word in my_string.split():
if word in counts: # this test filters out any unwanted words
counts[word] += 1 # increment the count
counts
字典将保存每个单词的计数。如果你确实需要一个与原始关键字列表顺序相同的计数列表(而 dict 不会这样做),你可以在循环完成后添加最后一步:
results = [counts[word] for word in my_list]
实施:
这是一个 Aho-Corasick 频率计数器:
import ahocorasick
def ac_frequency(needles, haystack):
frequencies = [0] * len(needles)
# Make a searcher
searcher = ahocorasick.Automaton()
for i, needle in enumerate(needles):
searcher.add_word(needle, i)
searcher.make_automaton()
# Add up all frequencies
for _, i in searcher.iter(haystack):
frequencies[i] += 1
return frequencies
(对于您的示例,您将调用 ac_frequency(my_list, my_string)
来获取计数列表)
对于大中型输入,这将比其他方法快得多。
备注:
对于真实数据,此方法可能会产生与发布的其他解决方案不同的结果,因为 Aho-Corasick 会查找 所有 次目标词,包括子字符串。
如果只想查找完整单词,可以使用 space/punctuation-padded 版本的原始字符串调用 searcher.add_word
:
...
padding_start = [" ", "\n", "\t"]
padding_end = [" ", ".", ";", ",", "-", "–", "—", "?", "!", "\n"]
for i, needle in enumerate(needles):
for s, e in [(s,e) for s in padding_start for e in padding_end]:
searcher.add_word(s + needle + e, i)
searcher.make_automaton()
# Add up all frequencies
for _, i in searcher.iter(" " + haystack + " "):
...
collections
模块中的Counter
可能对你有用:
from collections import Counter
my_string = "some text yes text text some"
my_list = ["some", "text", "yes", "not"]
counter = Counter(my_string.split(' '))
[counter.get(item, 0) for item in my_list]
# out: [2, 3, 1, 0]
我已经看过类似问题的答案:
其中 ahocorasick 算法用于显示列表中的每个单词是否存在于字符串中,复杂度为 O(n)。但是我想获取字符串中列表中每个单词的频率。
例如如果
my_string = "some text yes text text some"
my_list = ["some", "text", "yes", "not"]
我想要结果:
[2, 3, 1, 0]
我在 documentation 中没有找到这方面的确切示例,知道如何实现吗?
除了使用 ahocorasick 之外的其他 O(n) 解决方案也将不胜感激。
您可以使用列表理解来计算特定列表在 my_string 中出现的次数:
[my_string.split().count(i) for i in my_list]
[2, 3, 1, 0]
你可以用字典来统计你关心的词出现的次数:
counts = dict.fromkeys(my_list, 0) # initialize the counting dict with all counts at zero
for word in my_string.split():
if word in counts: # this test filters out any unwanted words
counts[word] += 1 # increment the count
counts
字典将保存每个单词的计数。如果你确实需要一个与原始关键字列表顺序相同的计数列表(而 dict 不会这样做),你可以在循环完成后添加最后一步:
results = [counts[word] for word in my_list]
实施:
这是一个 Aho-Corasick 频率计数器:
import ahocorasick
def ac_frequency(needles, haystack):
frequencies = [0] * len(needles)
# Make a searcher
searcher = ahocorasick.Automaton()
for i, needle in enumerate(needles):
searcher.add_word(needle, i)
searcher.make_automaton()
# Add up all frequencies
for _, i in searcher.iter(haystack):
frequencies[i] += 1
return frequencies
(对于您的示例,您将调用 ac_frequency(my_list, my_string)
来获取计数列表)
对于大中型输入,这将比其他方法快得多。
备注:
对于真实数据,此方法可能会产生与发布的其他解决方案不同的结果,因为 Aho-Corasick 会查找 所有 次目标词,包括子字符串。
如果只想查找完整单词,可以使用 space/punctuation-padded 版本的原始字符串调用 searcher.add_word
:
...
padding_start = [" ", "\n", "\t"]
padding_end = [" ", ".", ";", ",", "-", "–", "—", "?", "!", "\n"]
for i, needle in enumerate(needles):
for s, e in [(s,e) for s in padding_start for e in padding_end]:
searcher.add_word(s + needle + e, i)
searcher.make_automaton()
# Add up all frequencies
for _, i in searcher.iter(" " + haystack + " "):
...
collections
模块中的Counter
可能对你有用:
from collections import Counter
my_string = "some text yes text text some"
my_list = ["some", "text", "yes", "not"]
counter = Counter(my_string.split(' '))
[counter.get(item, 0) for item in my_list]
# out: [2, 3, 1, 0]