【问题标题】:unique word frequency in multiple files多个文件中的唯一词频
【发布时间】:2013-06-04 12:45:49
【问题描述】:

我是 python 新手。我得到一个包含大约 2000 个文本文件的文件夹。我应该输出每个单词及其出现的次数(在文件中不重复)。例如,句子:“i am what i am”必须在文件中仅包含一次“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)

【问题讨论】:

  • 从你的例子看来,输出总是1?此外,在我看来,您的代码不会输出 2 而不是 1 作为您的示例。
  • 在脚本中为 count "cnt = Counter()" 创建一个全局变量,并在各自的函数中更新它。
  • 使用words = set(words) 删除重复项。

标签: python data-mining


【解决方案1】:

查看os.listdir(),它会给你一个目录中所有条目的列表。

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

【讨论】:

    【解决方案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】:

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

      #!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)
      

      您可以选择许多其他方式来处理您的参数、硬编码默认参数等。我将让您想象如何将“top”从硬编码值更改为命令行参数。为了获得额外的功劳,请使用选项/参数解析模块(argparseoptparse)将其设置为具有默认值的命令行开关。

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

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

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

      【讨论】:

      • from __future__ importif 内。哇!
      • 嗯,是的!关于那个。我已经把它移到了它应该在的地方。
      【解决方案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))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-08-11
        • 2020-07-10
        • 1970-01-01
        • 1970-01-01
        • 2018-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多