使用字典在Python中有效计算词频

时间:2018-12-19 08:09:21

标签: python python-2.7 dictionary data-structures

我的任务是找到列表中每个单词的出现频率。有两种方法。

方法1

def f(words):
    wdict = {}
    for word in words:
        if word not in wdict:
            wdict[word] = 0
        wdict[word] += 1
    return wdict

方法2

def g(words):
    wdict = {}
    for word in words:
        try:
            wdict[word] += 1
        except KeyError:
            wdict[word] = 1

为什么方法2高效?并非在这两种情况下,哈希函数调用的数量都与此http://blackecho.github.io/blog/programming/2016/03/23/python-underlying-data-structures.html相矛盾?

4 个答案:

答案 0 :(得分:1)

让我们模拟几种情况。

例如:“一只鸟在飞”

words = ["A", "bird", "is", flying"]

您的第一种方法: 对于每个单词,它将在字典中搜索3次,因此将访问总计3 * {len(words)或3 * 4 = 12

第二种方法 如果找不到,它将仅搜索2次;否则1次:所以2 * 4 = 8

从理论上讲,两者的时间复杂度相同。

更新

感谢Thierry Lathuille指出。实际上,方法1应该比方法2更有效。Python字典使用哈希图,因此访问键的复杂度为O(n),但通常情况下为O(1)。而且cpython的实现非常有效。另一方面,try / catch异常处理很慢。

您可以在方法1中使用defaultdict以获得更简洁的代码。

答案 1 :(得分:1)

这取决于输入。如果平均而言,大多数单词已经在字典中,那么您将不会有很多例外。如果大多数单词都是唯一的,则异常的开销会使第二种方法变慢。

答案 2 :(得分:0)

有几种方法可以解决此问题。您可以使用循环并仍然获得预期的答案。我专注于两种方法:

列表理解

wordstring = 'it was the best of times it was the worst of times '
wordstring += 'it was the age of wisdom it was the age of foolishness'
wordlist = wordstring.split()
# Count each word
wordfreq = [wordlist.count(w) for w in wordlist] # a list comprehension
# Convert to set to remove repetitions
frequencies=set(zip(wordlist, wordfreq))
print(frequencies)

输出:

{('of', 4), ('best', 1), ('the', 4), ('worst', 1), ('age', 2), ('wisdom', 1), ('it', 4), ('was', 4), ('times', 2), ('foolishness', 1)}

方法二:标准库

import collections
wordstring = 'it was the best of times it was the worst of times '
wordstring += 'it was the age of wisdom it was the age of foolishness'
wordlist = wordstring.split()
# Count frequency
freq=collections.Counter(wordlist)
print(freq)

输出:

Counter({'it': 4, 'was': 4, 'the': 4, 'of': 4, 'times': 2, 'age': 2, 'best': 1, 'worst': 1, 'wisdom': 1, 'foolishness': 1})

选择的方法取决于您正在处理的文本的大小。上面的方法适用于较小的文本。

答案 3 :(得分:0)

有两个主要区别:

  • 方法1将对每个单词执行in操作,而方法2将在可能的情况下直接更新。
  • 每当Method1插入一个新单词时,该计数就会在以后更新。方法2从1开始计数。

这最终取决于输入,但是如果重复次数足够多,则操作会更少。

示例:
让我们只看一下这里的代码,以获取一般想法(而不是实际操作)。

['a', 'a']

Method1
1-wdict中没有'a'-True
2-分配“ a”
3-更新'a'
4-'a'not dict-假
5-更新'a'

Method2
1-访问'a'
2-错误
3-将“ a”直接分配给1
4-更新“ a”(第二个“ a”)

尽管这些步骤并不完全是执行时要执行的操作数量,但它们表示Method2更精简并且执行的“步骤”更少。