计算表示马尔可夫链规则的字典中值的总频率和相对频率
Calculating total and relative frequency of values in a dict representing a Markov-chain rule
我创建了一个函数 make_rule(text, scope=1)
,它简单地遍历一个字符串并生成一个字典,用作马尔可夫文本生成器的规则(其中范围是链接字符的数量,而不是单词的数量) .
>>> rule = make_rule("abbcad", 1)
>>> rule
{'a': ['b', 'd'], 'b': ['b', 'c'], 'c': ['a']}
我的任务是计算这个系统的熵。为此,我想我需要知道:
- 一个值在字典中出现的总频率,即它的总频率。
- 给定字典中某个键值出现的频率,即它的相对频率。
有没有一种快速的方法来获取字典中每个值的这两个数字?
对于上面的例子,我需要这样的输出:
'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)], ...]
除了遍历单词的字符,计算字典中每个列表中的出现次数并最后求和外,我想不出一个快速的方法:
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)]
我只处理 "How often a value appears given a key in the dictionary",因为你说 "How often a value appears in the dictionary in total" 很容易推断出来。
如果您只想查找给定键的值的相对频率,使用 dict
个 Counter
个对象很容易获得:
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
objects return 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 = ...
行,其中:
- 创建一个空的
set()
- 生成
union()
of that set with all the individual elements of the lists in rule.values()
(note the use of the argument-unpacking *
运算符)
- 将结果转换为
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)
]
我创建了一个函数 make_rule(text, scope=1)
,它简单地遍历一个字符串并生成一个字典,用作马尔可夫文本生成器的规则(其中范围是链接字符的数量,而不是单词的数量) .
>>> rule = make_rule("abbcad", 1)
>>> rule
{'a': ['b', 'd'], 'b': ['b', 'c'], 'c': ['a']}
我的任务是计算这个系统的熵。为此,我想我需要知道:
- 一个值在字典中出现的总频率,即它的总频率。
- 给定字典中某个键值出现的频率,即它的相对频率。
有没有一种快速的方法来获取字典中每个值的这两个数字?
对于上面的例子,我需要这样的输出:
'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)], ...]
除了遍历单词的字符,计算字典中每个列表中的出现次数并最后求和外,我想不出一个快速的方法:
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)]
我只处理 "How often a value appears given a key in the dictionary",因为你说 "How often a value appears in the dictionary in total" 很容易推断出来。
如果您只想查找给定键的值的相对频率,使用 dict
个 Counter
个对象很容易获得:
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
objects return 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 = ...
行,其中:
- 创建一个空的
set()
- 生成
union()
of that set with all the individual elements of the lists inrule.values()
(note the use of the argument-unpacking*
运算符) - 将结果转换为
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)
]