字母频率:从大多数到最少使用的顺序获得打印频率

时间:2012-04-14 03:16:06

标签: python

我想编写一个程序,从文本文件中读取字母,忽略符号和空格,并按照从最常见到最不常见的顺序打印每个字母的计数。

另外,我正在为第一个编程课程工作,所以我不允许使用计数器。

到目前为止,我有这个:

name= raw_input("Enter file name:")
fl= open(name, 'r+').read()
lw= fl.lower()
ws= lw.replace(' ','')
sm= ws.translate(None, ",-!.;?:")
occ= {}
alpha= list ('abcdefghijklmnopqrstuvwxyz')
for x in alpha:
    occ[x]= sm.count(x)
for x in occ:
    print x, occ[x]

假装文本文件是这样的:“我对此感到非常困惑?”

然后程序将通过它的编程并执行此操作:“iamhighlyconfusedbythis”

但是现在它只显示这样的东西:

1   a
1   b
1   c
1   d
1   e
1   f
1   g
3   h
3   i
0   j
0   k
1   l
1   m
1   n
1   o
0   p
0   q
0   r
2   s
1   t
1   u
0   v
0   w
0   x
2   y
0   z

但我希望结果如下:

3   h
3   i
2   s
2   y
1   e
1   f
1   g
1   a
1   b
1   l
1   m
1   n
1   o
1   c
1   t
1   u
1   d
0   j
0   k
0   p
0   q
0   r
0   v
0   w
0   x
0   z

我使用了以下的想法:

spyshyguy

Determining Letter Frequency Of Cipher Text

SimplyZ

Letter frequency in python

5 个答案:

答案 0 :(得分:4)

更新问题的解决方案

>>> from collections import defaultdict
>>> import string
>>> text = 'I am highly confused by this?'.lower().translate(None,string.punctuation+' ')
>>> c = defaultdict(int)
>>> c.update({letter:0 for letter in string.lowercase[:26]}) #Initialize each letter of alphabet to 0
>>> for letter in text:
        c[letter] += 1


>>> for letter,freq in sorted(c.iteritems(),key=lambda (l,f): (-f,l)): #Sort by frequency in descending order by making frequency negative then by letter in ascending order
        print freq, letter


3 h
3 i
2 s
2 y
1 a
1 b
1 c
1 d
1 e
1 f
1 g
1 l
1 m
1 n
1 o
1 t
1 u
0 j
0 k
0 p
0 q
0 r
0 v
0 w
0 x
0 z

解决原始问题: 您可以使用collections.Counter

>>> from collections import Counter
>>> import string
>>> text = 'I am highly confused by this?'.translate(None,string.punctuation+' ')
>>> print ' '.join('%d %s'%(freq,letter) for letter,freq in Counter(x).most_common())
3 h 2 i 2 s 2 y 1 a 1 c 1 b 1 e 1 d 1 g 1 f 1 I 1 m 1 l 1 o 1 n 1 u 1 t

答案 1 :(得分:3)

你可以这样做,

from operator import itemgetter
for k,v in sorted(occ.items(), key=itemgetter(1), reverse=True):
    print k, v

但是有更好的方法来计算字母,例如collections.Counter

答案 2 :(得分:1)

由于你不能使用Counter,我会做这样的事情:

from string import ascii_lowercase

with open(name, 'r') as f:
    raw_text = f.read().lower()

letterCounts = [raw_text.count(letter) for letter in ascii_lowercase]

frequencies = reversed(sorted(zip(ascii_lowercase, letterCounts), lambda x: x[1]))

for i in frequencies:
    print "%s: %d" % i

答案 3 :(得分:0)

这是一个使用defaultdict()的简单Python版本。既然你说这是一个类,这不是你要求的最终解决方案。

from collections import defaultdict
from operator import itemgetter

d = defaultdict(int)

name = raw_input("Enter file name: ")

with open(name, "r") as f:
    for line in f:
        for ch in line:
            if ch.isalpha():
                d[ch] += 1

lst = d.items()

# sort twice: once for alphabetical order, then for frequency (descending).
# Because the Python sort is "stable", we will end up with descending
# frequency, but alphabetical order for any frequency values that are equal.
lst.sort(key=itemgetter(0))
lst.sort(key=itemgetter(1), reverse=True)

for key, value in lst:
    print value, key,

当您在打开的文件上执行for循环时,例如此处的for line in f,Python将从输入文件中一次抓取一行。然后我们在输入行上一次循环一个字符。然后我们检查它是否是一个字母,如果是,我们增加字母的频率计数。

此代码中存在错误。你希望它计算所有字母的频率,好像它们都是小写字母一样,但是这个代码将保留一个大写的计数和另一个小写的计数。我相信你可以弄清楚如何修改它,以便计数只适用于小写。

完成计数后,我们使用.items()方法函数获取(key, value)元组的列表。例如:('h', 3)是一个元组,其中包含字典键字符h及其值,即计数3。

现在我们要排序。我向你展示了Python可以做的一个很好的技巧:因为排序是一种“稳定”排序,如果我们做多种排序,Python不会干扰早期排序的结果,除非它必须。这意味着如果我们首先按字母顺序排序,然后然后按频率计数排序,那么对于频率计数相等的所有情况,我们将在该频率内获得字母顺序。因此,由于abc都是相同的频率(它们各自出现一次),您可能希望输出的一部分为:1 a 1 b 1 c

现在,我有点棘手,但这很好学。 sort函数可以使用一个名为key的参数来控制排序。 key应该是一个返回要用于排序的值的函数。由于我们有一个元组列表,我们需要一个关键函数,它可以获取元组的一部分并返回它。我们可以编写两个函数:

def get_key(kv_tuple):
    return kv_tuple[0]
def get_value(kv_tuple):
    return kv_tuple[1]

但Python有一个函数operator.itemgetter(),我们可以使用它。如果我们只是告诉它我们想要得到的元组中的哪个位置,它将为我们提供一个关键功能,它将为我们提供元组的一部分。

由于我们希望首先按最大值对频率进行排序,因此我们还在reverse=True方法的参数中设置.sort()

最后,我们遍历键,值元组和打印列表。

此代码中还有另一个问题。您的示例输出显示您希望每个字母都在列表中,如果字母不在输入中,则计数为0。这只计算那里的东西。

所以,我建议你重新编写这段代码。不要使用defaultdict,而是尝试使用普通dict,但要设置一个循环,将每个字母a设置为zdict数为0.

我还建议,在您的普通dict包含您要计算的字母后,您可以更改决定是否计算的代码。目前,它使用.isalpha()方法函数来决定是否计算一个字符;相反,您可以检查该字符是否为in字典。然后,您可以使用此代码来计算标点符号或数字或任何类型的字符。

答案 4 :(得分:0)

我认为更简单的方法是使用本机计数功能:

此代码只打印每个字母的计数。你需要把它放在一个集合中,并为你排序,以便先获得最常用的字母。

text = 'Your original text.'
alpha = list ('abcdefghijklmnopqrstuvwxyz')
for letter in alpha:
    print letter + ': ' + str(text.count(letter))