多个文件中的唯一字频率

时间:2013-06-08 07:25:33

标签: python data-mining

我是python的新手。我得到一个包含大约2000个文本文件的文件夹。我应该输出每个单词及其出现次数(不重复文件)。例如,句子:“我就是我”必须在文件中只包含一次“i”。

我能够为单个文件执行此操作,但如何为多个文件执行此操作?

from collections import Counter
import re

def openfile(filename):
    fh = open(filename, "r+")
    str = fh.read()
    fh.close()
    return str

def removegarbage(str):
    # Replace one or more non-word (non-alphanumeric) chars with a space
    str = re.sub(r'\W+', ' ', str)
    str = str.lower()
    return str

def getwordbins(words):
    cnt = Counter()
    for word in words:
        cnt[word] += 1
    return cnt

def main(filename, topwords):
    txt = openfile(filename)
    txt = removegarbage(txt)
    words = txt.split(' ')
    bins = getwordbins(words)
    for key, value in bins.most_common(topwords):
        print key,value

main('speech.txt', 500)

4 个答案:

答案 0 :(得分:4)

您可以使用glob模块中的glob()iglob()功能获取文件列表。我注意到您没有有效地使用Counter对象。最好只调用它的update()方法并将其传递给单词列表。这是一个简化的代码版本,用于处理指定文件夹中找到的所有*.txt文件:

from collections import Counter
from glob import iglob
import re
import os

def remove_garbage(text):
    """Replace non-word (non-alphanumeric) chars in text with spaces,
       then convert and return a lowercase version of the result.
    """
    text = re.sub(r'\W+', ' ', text)
    text = text.lower()
    return text

topwords = 100
folderpath = 'path/to/directory'
counter = Counter()
for filepath in iglob(os.path.join(folderpath, '*.txt')):
    with open(filepath) as file:
        counter.update(remove_garbage(file.read()).split())

for word, count in counter.most_common(topwords):
    print('{}: {}'.format(count, word))

答案 1 :(得分:2)

请参阅os.listdir(),它将为您提供目录中所有条目的列表。

http://docs.python.org/2/library/os.html#os.listdir

答案 2 :(得分:2)

如果我的解释正确,您希望为每个单词计算包含该单词的文件数。这是你能做的。

对于每个文件,在此文件中获取一组单词(即单词应该是唯一的)。然后,对于每个单词计数,可以找到它的集合数。

以下是我的建议:

  1. 遍历目标目录中的所有文件。您可以使用os.listdir来实现此目的。
  2. 在此文件中找到一组单词:

    with open(filepath, 'r') as f:
        txt = removegarbage(f.read())
        words = set(txt.split())
    
  3. 现在,当每个文件中都有一组单词时,您最终可以使用Counter这些集合。最好使用其update方法。这是一个小小的演示:

    >>> a = set("hello Python world hello".split())
    >>> a
    {'Python', 'world', 'hello'}
    >>> b = set("foobar hello world".split())
    >>> b
    {'foobar', 'hello', 'world'}
    >>> c = Counter()
    >>> c.update(a)
    >>> c.update(b)
    >>> c
    Counter({'world': 2, 'hello': 2, 'Python': 1, 'foobar': 1})
    

答案 3 :(得分:0)

所以你可能会做一些类似的事情:

#!python
from __future__ import print_function
# Your code here
# ...
#

if __name__ == '__main__':
    import sys

    top=500

    if len(sys.argv) < 2:
        print ("Must supply a list of files to operate on", file=sys.stderr)
        ## For Python versions older than 2.7 use print >> sys.stderr, "..."
        sys.exit(1)

    for each in sys.argv[1:]:
        main(each, top)

请注意,我正在展示一种简单的方法来包装现有函数,以便您可以使用任意数量的文件名参数调用程序。如果你想要,你也可以只用一个参数来指向你想要处理所有文件的目录:

#!python
from __future__ import print_function
# Your code here
# ...
# 
if __name__ == '__main__':
    import sys

    top = 500

    if len(sys.argv) != 2:
        ## Require exactly one argument: sys.argv[0] is our own executable filename
        ## (Similarly to how class methods are called with "self" as their first
        ## argument, but on the OS layer)
        print ("Must supply directory name full of files to be processed", file=sys.stderr)
        sys.exit(1)
    for each in os.listdir(sys.argv[1]):
        main(each, top)

还有很多其他方法可以选择处理你的参数,硬代码默认参数等等。我会让你想象一下如何将“顶层”从硬编码值改为命令行参数。对于额外的功劳,使用选项/ arg解析模块(argparseoptparse)使其成为带默认值的命令行开关。

请注意,此if __name__ == ....商家是一种Python惯例,它通过鼓励您将功能与操作分开来促进良好的编程实践。因此,您可以在if __name__ == '__main__':行之上定义所有功能,并且可以在其后调用脚本执行的所有操作(使用该功能)。这允许您的文件被其他程序用作模块,同时仍然允许它自己拥有自己的实用程序作为程序。 (这是一个几乎与Python无关的功能,尽管Ruby实现了一组类似的语义,但语法略有不同)。

__future__内容允许您使用Python 2.7编写程序,该程序使用与Python 3.x兼容的print语义。这对于最终转换到Python 3以及讨论语言非常有用,因此我们可以逐步淘汰旧的“print”作为语句并推广使用“print()”函数。如果您不关心细节,请不要担心。只是意识到差异是普遍存在的,必须是微不足道的。您将看到的绝大多数示例使用旧的打印语义,并且您将希望使用更新的,略微不兼容的语义。

(注意:在我最初的帖子中,我在from __future__ import部分中有__main__。特别是那些不起作用(通常Python __future__导入应该在任何其他之前发生代码)。[我基本上试图理解这个想法,并且不想陷入Python2.x和Python3打印语义之间的差异。