【问题标题】:Calculating total and relative frequency of values in a dict representing a Markov-chain rule计算表示马尔可夫链规则的字典中值的总频率和相对频率
【发布时间】:2019-04-15 16:37:18
【问题描述】:

我创建了一个函数make_rule(text, scope=1),它简单地遍历一个字符串并生成一个字典,用作马尔可夫文本生成器的规则(其中范围是链接字符的数量,而不是单词)。

>>> rule = make_rule("abbcad", 1)
>>> rule
{'a': ['b', 'd'], 'b': ['b', 'c'], 'c': ['a']}

我的任务是计算这个系统的熵。为了做到这一点,我想我需要知道:

  1. 一个值在字典中出现的总频率,即它的总频率。
  2. 给定字典中某个键的值出现的频率,即它的相对频率。

有没有一种快速的方法可以为字典中的每个值获取这两个数字?

对于上面的例子,我需要这个输出:

'a' total: 1, 'a'|'a': 0, 'a'|'b': 0, 'a'|'c': 1
'b' total: 2, 'b'|'a': 1, 'b'|'b': 1, 'b'|'c': 0
'c' total: 1, 'c'|'a': 0, 'c'|'b': 1, 'c'|'c': 0
'd' total: 1, 'd'|'a': 1, 'a'|'b': 1, 'a'|'c': 1

我猜'a' 的总数很容易推断出来,所以也许只为字典中出现的每个唯一项目输出一个三元组列表:

[[('a', 'a', 0), ('a', 'b', 0), ('a', 'c', 1)], [('b', 'a', 1), ('b', 'b', 1), ('b', 'c', 0)], ...]

【问题讨论】:

  • 上述字典对每个值的预期结果是什么?
  • 哦,对不起,我好像删掉了预期的输出。我现在已经添加了。输出的格式不是很重要,重要的是我如何有效地得到这些数字。

标签: python python-3.x dictionary frequency markov-chains


【解决方案1】:

我将只处理“给定字典中某个键的值出现的频率”,因为您说过“一个值在字典中出现的总频率”很容易推断出来。

如果您只想查找给定键的值的相对频率,使用 dictCounter 对象很容易获得:

from collections import Counter

rule = {'a': ['b', 'd'], 'b': ['b', 'c'], 'c': ['a']}

freq = {k: Counter(v) for k, v in rule.items()}

...它会给你一个freq 像这样:

{
    'a': Counter({'b': 1, 'd': 1}),
    'b': Counter({'b': 1, 'c': 1}),
    'c': Counter({'a': 1})
}

... 这样你就可以得到'a' 的相对频率给定键'c' 像这样:

>>> freq['c']['a']
1

因为Counter 对象为不存在的键返回 0,所以您也会得到零频率:

>>> freq['a']['c']
0

如果您需要问题中指定的三元组列表,您可以通过一些额外的工作来获得它。这是一个函数:

def triples(rule):               
    freq = {k: Counter(v) for k, v in rule.items()}
    all_values = sorted(set().union(*rule.values()))      
    sorted_keys = sorted(rule)
    return [(v, k, freq[k][v]) for v in all_values for k in sorted_keys] 

我认为这里唯一可能无法自我解释的是all_values = ... 行,它:

  1. 创建一个空的set()
  2. 使用rule.values() 中列表的所有单个元素生成该集合的union()(注意使用argument-unpacking * 运算符)
  3. 将结果转换为sorted() 列表。

如果您仍然有原始文本,您可以通过使用例如避免所有这些工作。 all_values = sorted(set(original_text)) 代替。

它在行动:

>>> triples({'a': ['b', 'd'], 'b': ['b', 'c'], 'c': ['a']})
[
    ('a', 'a', 0), ('a', 'b', 0), ('a', 'c', 1),
    ('b', 'a', 1), ('b', 'b', 1), ('b', 'c', 0),
    ('c', 'a', 0), ('c', 'b', 1), ('c', 'c', 0),
    ('d', 'a', 1), ('d', 'b', 0), ('d', 'c', 0)
]

【讨论】:

  • Counter的使用大大简化了任务,谢谢你的好建议!我认为这应该是公认的答案,因为它深入且内容丰富。
【解决方案2】:

除了遍历单词的字符,计算字典每个列表中出现的次数并在最后求和之外,我想不出一个快速的方法:

alphabet = sorted(set("abbcad"))
rule = {'a': ['b', 'd'], 'b': ['b', 'c'], 'c': ['a']}

totalMatrix = []
for elem in alphabet:
    total = 0
    occurences = []
    for key in rule.keys():
        currentCount = rule[key].count(elem)
        total += currentCount
        occurences.append((elem,key,currentCount))
    totalMatrix.append([elem, total] + occurences)

for elem in totalMatrix:
    print(elem)

totalMatrix的内容为:

['a', 1, ('a', 'a', 0), ('a', 'b', 0), ('a', 'c', 1)]
['b', 2, ('b', 'a', 1), ('b', 'b', 1), ('b', 'c', 0)]
['c', 1, ('c', 'a', 0), ('c', 'b', 1), ('c', 'c', 0)]
['d', 1, ('d', 'a', 1), ('d', 'b', 0), ('d', 'c', 0)]

【讨论】:

  • 你的建议很清楚很简单,谢谢!
猜你喜欢
  • 2014-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
相关资源
最近更新 更多