我有一个单词列表,让我们说:[“foo”,“bar”,“baz”]以及可能出现这些单词的大字符串。
我现在使用列表中的每个单词“string”.count(“word”)方法。这工作正常,但似乎效率很低。对于添加到列表中的每个额外单词,必须在额外的时间内迭代整个字符串。
他们有更好的方法吗,或者我应该实现一次迭代大字符串的自定义方法,检查每个字符是否已达到列表中的一个字词?
要明确:
答案 0 :(得分:8)
为您的单词制作一个dict
类型的频率表,然后迭代字符串中的单词。
vocab = ["foo", "bar", "baz"]
s = "foo bar baz bar quux foo bla bla"
wordcount = dict((x,0) for x in vocab)
for w in re.findall(r"\w+", s):
if w in wordcount:
wordcount[w] += 1
修改:如果列表中的“字词”包含空格,您可以改为从中构建RE:
from collections import Counter
vocab = ["foo bar", "baz"]
r = re.compile("|".join(r"\b%s\b" % w for w in vocab))
wordcount = Counter(re.findall(r, s))
说明:这将从词汇表中构建RE r'\bfoo bar\b|\bbaz\b'
。 findall
然后找到列表['baz', 'foo bar']
,Counter
(Python 2.7+)计算其中每个不同元素的出现次数。 注意您的单词列表不应包含RE特有的字符,例如()[]\
。
答案 1 :(得分:3)
假定单词需要单独找到(也就是说,你想要计算由str.split()
生成的单词):
编辑:根据评论中的建议,计数器是一个不错的选择:
from collections import Counter
def count_many(needles, haystack):
count = Counter(haystack.split())
return {key: count[key] for key in count if key in needles}
运行如下:
count_many(["foo", "bar", "baz"], "testing somefoothing foo bar baz bax foo foo foo bar bar test bar test")
{'baz': 1, 'foo': 4, 'bar': 4}
请注意,在Python< = 2.6(?)中,由于缺乏字典理解,您需要使用return dict((key, count[key]) for key in count if key in needles)
。
当然,另一种选择是简单地返回整个Counter
对象,并且只在需要时获取所需的值,因为根据具体情况获得额外值可能不是问题。
旧答案:
from collections import defaultdict
def count_many(needles, haystack):
count = defaultdict(int)
for word in haystack.split():
if word in needles:
count[word] += 1
return count
结果是:
count_many(["foo", "bar", "baz"], "testing somefoothing foo bar baz bax foo foo foo bar bar test bar test")
defaultdict(<class 'int'>, {'baz': 1, 'foo': 4, 'bar': 4})
如果您极力反对获取defaultdict(您不应该这样做,因为它的功能与访问时的dict完全相同),那么您可以执行return dict(count)
来获取普通字典。
答案 2 :(得分:1)
你的字符串有多长时间我理解它不会随着你的字符串列表而不断变化?
一个好主意是迭代字符串中的单词并为单词添加字典并增加每个单词的计数。有了这个。然后,您可以在字典的列表中查找单词,并输出它的值,即出现次数。
答案 3 :(得分:0)
Counter
方法不适用于大词汇量。在下面的示例中,CountVectorizer
的速度提高了很多倍:
import time
import random
longstring = ["foo", "bar", "baz", "qux", "thud"] * 100000
random.shuffle(longstring)
longstring = " ".join(longstring)
vocab = ["foo bar", "baz"] + ["nothing"+str(i) for i in range(100000)]
import re
from collections import Counter
tic = time.time()
r = re.compile("|".join(r"\b%s\b" % w for w in vocab))
wordcount = Counter(re.findall(r, longstring))
print(time.time() - tic)
from sklearn.feature_extraction.text import CountVectorizer
from scipy import array
tic = time.time()
vectorized = CountVectorizer(vocabulary=vocab, ngram_range=(1, 2)).fit([longstring]) # list strings contains 1 to 2 words
counts = vectorized.transform([longstring])
counts = array(counts.sum(axis=0))[0]
wordcount = {vocab[i]: counts[i] for i in range(len(vocab))}
print(time.time() - tic)