Python 如何统计包含特定单词的文档?

Python 如何统计包含特定单词的文档?,python,dictionary,counter,frequency,tf-idf,Python,Dictionary,Counter,Frequency,Tf Idf,假设我有一个这样的口述: docDict = {"alpha": ["a", "b", "c", "a", "b"], "bravo": ["b", "c", "d", "c", "d"]} 我想做的是计算“文档频率”:假设每个字典项都是一个文档,我有一个特定的单词,那么有多少文档包含这个单词 我看到很多帖子告诉我如何计算频率,但是这里如果“a”在文档“alpha”中出现两次,我只需要计数为1。所以“a”的“频率”应该是1,“c”应该是2 我知道我可以迭代整个文档字典,并在文档中查找单词时添加

假设我有一个这样的口述:

docDict = {"alpha": ["a", "b", "c", "a", "b"], "bravo": ["b", "c", "d", "c", "d"]}
我想做的是计算“文档频率”:假设每个字典项都是一个文档,我有一个特定的单词,那么有多少文档包含这个单词

我看到很多帖子告诉我如何计算频率,但是这里如果
“a”
在文档
“alpha”
中出现两次,我只需要计数为1。所以
“a”
的“频率”应该是1,
“c”
应该是2

我知道我可以迭代整个文档字典,并在文档中查找单词时添加计数器。或者我可以先使每个文档中的单词唯一,然后合并所有文档并计算单词

但我认为有更好的方法,更有效的方法。有什么想法吗

顺便问一句,有没有什么方法可以让我保留这篇文章的结构?在本例中,我希望得到
{“alpha”的结果:{c':2,'b':2,'a':1},“bravo”:{c':2,'b':2,'d':1}

更新

如果这里我只有一个列表(类似于
[[a”,“b”,“c”,“a”,“b”,“b”,“b”,“b”,“c”,“d”,“c”,“d”]]
),我如何才能得到像
[[1,2,2,0],[0,2,2,1]
这样的结果列表


我不知道。重点是要扩展每个列表,并确保术语的顺序。想法?

我会使用和的第二种方法

更新1:

>>> c = sum((Counter(set(x)) for x in docDict.itervalues()), Counter())
>>> {k: {k1:c[k1] for k1 in set(v)} for k, v in docDict.iteritems()}
{'alpha': {'a': 1, 'c': 2, 'b': 2}, 'bravo': {'c': 2, 'b': 2, 'd': 1}}
更新2:

如果性能是一个问题,那么不要将
计数器
求和
一起使用,这里是另一种方法。请注意,与@user2931409 answer不同,我不会在内存中保留一组单词,只是为了获得它们的长度,因此这比内存效率要高得多,但比它们的答案稍微慢一点

result = Counter()
for v in docDict.itervalues():
    result.update(set(v))
return result
定时比较:

def func1():
    #http://stackoverflow.com/a/22787509/846892
    result = defaultdict(set)
    for k, vlist in docDict.items():
        for v in vlist:
            result[v].add(k)
    return dict(zip(result.keys(), map(lambda x:len(x), result.values())))

def func2():

    result = Counter()
    for v in docDict.itervalues():
        result.update(set(v))
    return result

In [94]: docDict = {''.join(random.choice(lis) for _ in xrange(8)): random.sample(lis, 25)
    ...:   for _ in xrange(70000)}

In [95]: %timeit func1(docDict)
1 loops, best of 3: 380 ms per loop

In [96]: %timeit func2(docDict)
1 loops, best of 3: 591 ms per loop

In [97]: docDict = {''.join(random.choice(lis) for _ in xrange(8)): random.sample(lis, 25)
    ...:   for _ in xrange(10**5)}

In [98]: %timeit func1(docDict)
1 loops, best of 3: 529 ms per loop

In [99]: %timeit func2(docDict)
1 loops, best of 3: 848 ms per loop

In [101]: func1(docDict) == func2(docDict)
Out[101]: True
给出:


您可以使用set统一单个文档中的字符。然后只需
Counter()

from collections import Counter

docDict = {"alpha": ["a", "b", "c", "a", "b"], "bravo": ["b", "c", "d", "c", "d"]}

result = reduce(lambda x, y: x + Counter(set(y)), docDict.itervalues(), Counter([]))

这不是特别的一种,很普通的方式

from collections import defaultdict

docDict = {"alpha": ["a", "b", "c", "a", "b"], "bravo": ["b", "c", "d", "c", "d"]}
result = defaultdict(set)

for k, vlist in docDict.items():
    for v in vlist:
        result[v].add(k)

#Now the result looks like this.
#{'a': set(['alpha']), 'c': set(['alpha', 'bravo']), 'b': set(['alpha', 'bravo']), 'd': set(['bravo'])})

print dict(zip(result.keys(), map(lambda x:len(x), result.values())))
#{'a': 1, 'c': 2, 'b': 2, 'd': 1}
更新

另一种方法…只是计数。并改为使用迭代器。所以它比上面的代码更快

from collections import defaultdict
def func3(docDict):
    result = defaultdict(int)
    for vlist in docDict.itervalues():
        for i in set(vlist):
            result[i] += 1
    return dict(result)

我不明白你的目标。你想计算一个字符/单词在文档中的次数?但你不想计算实际次数?为什么
“a”
的计数为
1
“c”
有一个计数为
2
?这对我来说没有意义。@Cyber我想计算有多少文档包含这个词。在我的示例中,只有
“alpha”
包含
“a”
,所以它应该是1(虽然在
“alpha”
中有两次),而
“c”
同时在
“alpha”
“bravo”
中,所以它是2(虽然总共有3个c)。谢谢!我从来没有想到它会如此紧凑和优雅!但是…有什么方法可以保持字典的结构吗?比如…
{“alpha”:{c':2,'b':2,'a':1},好极了:{c':2,'b':2,'d':1}
@Melkor检查更新后的答案,你需要一个额外的循环。嗨,我已经测试过了,但是它运行得很慢。当我处理了7万多个单词时,我花了将近300秒。但是@user2931409说的方式真的很快。@Melkor我有另一个答案。我不得不说它真的很神奇。处理大约只花了2秒超过7000个单词,超过3000行!至于保持dict的结构,我只是创建了一个新的dict,并对原始dict进行迭代,以映射这个计数器的结果。仍然非常快。@Melkor:我不知道
set
函数和
for loop
的速度有这么快。谢谢你告诉我。不管怎样,我上传了more.更快的一个。:)
from collections import Counter

docDict = {"alpha": ["a", "b", "c", "a", "b"], "bravo": ["b", "c", "d", "c", "d"]}

result = reduce(lambda x, y: x + Counter(set(y)), docDict.itervalues(), Counter([]))
from collections import defaultdict

docDict = {"alpha": ["a", "b", "c", "a", "b"], "bravo": ["b", "c", "d", "c", "d"]}
result = defaultdict(set)

for k, vlist in docDict.items():
    for v in vlist:
        result[v].add(k)

#Now the result looks like this.
#{'a': set(['alpha']), 'c': set(['alpha', 'bravo']), 'b': set(['alpha', 'bravo']), 'd': set(['bravo'])})

print dict(zip(result.keys(), map(lambda x:len(x), result.values())))
#{'a': 1, 'c': 2, 'b': 2, 'd': 1}
from collections import defaultdict
def func3(docDict):
    result = defaultdict(int)
    for vlist in docDict.itervalues():
        for i in set(vlist):
            result[i] += 1
    return dict(result)