【问题标题】:Python - Number of word occurrencesPython - 单词出现次数
【发布时间】:2012-02-03 06:59:01
【问题描述】:

我正在尝试做一个函数,允许在文本中查找(整个)单词(不区分大小写)的出现次数。

例子:

>>> text = """Antoine is my name and I like python.
Oh ! your name is antoine? And you like Python!
Yes is is true, I like PYTHON
and his name__ is John O'connor"""

assert( 2 == Occs("Antoine", text) )
assert( 2 == Occs("ANTOINE", text) )
assert( 0 == Occs("antoin", text) )
assert( 1 == Occs("true", text) )    
assert( 0 == Occs("connor", text) )
assert( 1 == Occs("you like Python", text) )
assert( 1 == Occs("Name", text) )

这是一个基本的尝试:

def Occs(word,text):
    return text.lower().count(word.lower())

这个行不通,因为它不是基于文字的。
这个功能一定要快,文字可以很大。

我应该把它拆分成一个数组吗?
有没有简单的方法来完成这个功能?

编辑 (python 2.3.4)

【问题讨论】:

  • 您有多少查询?如果你有很多,我建议你将小写文本拆分成单词 (O(n)),对它们进行排序并在结果列表中搜索(二分搜索 + 对相邻项目的迭代)
  • 你为什么要绑定到 Python 2.3?
  • @Nikolay 实际上我无法拆分,因为可以搜索的不仅仅是单词(参见第二次编辑):)
  • @jsbueno 我使用 python 2.7 但这是我必须做的练习(我没有选择)。

标签: python python-2.3


【解决方案1】:
from collections import Counter
import re

Counter(re.findall(r"\w+", text))

或者,对于不区分大小写的版本

Counter(w.lower() for w in re.findall(r"\w+", text))

在 Python defaultdict 代替 Counter

freq = defaultdict(int)
for w in re.findall(r"\w+", text):
    freq[w.lower()] += 1

【讨论】:

  • 对于不区分大小写的版本,为什么不直接使用re.IGNORECASE 标志? docs.python.org/library/re.html#re.IGNORECASE
  • @DaveWebb:IGNORECASE在匹配时会忽略大小写,但不会将findall的结果小写。
  • 问题是要求计算特定单词而不是所有单词;我想在这种情况下IGNORECASE 更有意义。
  • @DaveWebb:因为计算所有单词可以在 O(n) 时间内在一行代码中完成,所以几乎没有必要。
  • 这是最好的答案,但我不能只使用 "\w+" 因为我应该也可以匹配多个单词(参见第二次编辑)。另外 lower() 会减慢我认为的功能
【解决方案2】:

this question

一个认识是,如果您的文件是面向行的,那么逐行读取它并在每行上使用纯 split() 不会很昂贵。这当然假设单词不跨越换行符,不知何故(没有连字符)。

【讨论】:

  • 谢谢,但它不完全是面向行的
【解决方案3】:

这是一种非 Python 的方式 - 我假设这是一个家庭作业问题......

def count(word, text):
    result = 0
    text = text.lower()
    word = word.lower()
    index = text.find(word, 0)
    while index >= 0:
        result += 1
        index = text.find(word, index)
    return result

当然,对于非常大的文件,这会很慢,主要是由于text.lower() 调用。但是你总是可以想出一个不区分大小写的find 并修复它!

我为什么要这样做?因为我认为它捕捉到了你最想做的事情:遍历text,计算你在其中找到word 的次数。

此外,这种方法还解决了标点符号的一些棘手问题:split 会将它们留在其中,然后您将无法匹配,对吗?

【讨论】:

  • 这个可以匹配NumberOfOccurencesOfWordInText("antoin",text) 吗?它不应该。无论如何 +1 对于 lower() 性能问题。
  • @Glide 对,我的错。然而,该技术将起作用,您只需要检查匹配(开始和结束)的单词边界。没有简单的方法可以做到这一点。你只需要扫描文本。考虑在运行时构建一个专门的扫描器来压缩你的文本检查单词。类似grep
【解决方案4】:

感谢您的帮助。
这是我的解决方案:

import re

starte = "(?<![a-z])((?<!')|(?<=''))"
ende = "(?![a-z])((?!')|(?=''))"

def NumberOfOccurencesOfWordInText(word, text):
    """Returns the nb. of occurences of whole word(s) (case insensitive) in a text"""
    pattern = (re.match('[a-z]', word, re.I) != None) * starte\
              + word\
              + (re.match('[a-z]', word[-1], re.I) != None) * ende
    return  len(re.findall(pattern, text, re.IGNORECASE))

【讨论】:

  • 为我工作,让'word'有引号和空格。你有没有找到其他解决方案?那个正则表达式是不是太昂贵了?
【解决方案5】:

我被要求解决完全相同的问题,因此浏览了很多关于该问题的信息。这就是为什么想在这里分享我的解决方案。虽然我的解决方案需要一段时间才能执行,但它的内部处理时间比我猜的 findall 好一点。我可能错了。无论如何,这里有解决方案:

def CountOccurencesInText(word,text):
    """Number of occurences of word (case insensitive) in text"""

    acceptedChar = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 
                'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '-', ' ')

    for x in ",!?;_\n«»():\".":
        if x == "\n" or x == "«" or x == "»" or x == "(" or x == ")" or x == "\"" or x == ":" or x == ".":
            text = text.replace(x," ")
        else:
            text = text.replace(x,"")

    """this specifically handles the imput I am attaching my c.v. to this e-mail."""
    if len(word) == 32:
        for x in ".":
            word = word.replace(x," ")

    punc_Removed_Text = ""
    text = text.lower()

    for i in range(len(text)):
        if text[i] in acceptedChar:
        punc_Removed_Text = punc_Removed_Text + text[i]

        """"this specifically handles the imput: Do I have to take that as a 'yes'"""
        elif text[i] == '\'' and text[i-1] == 's':
            punc_Removed_Text = punc_Removed_Text + text[i]

        elif text[i] == '\'' and text[i-1] in acceptedChar and text[i+1] in acceptedChar:
            punc_Removed_Text = punc_Removed_Text + text[i]

        elif text[i] == '\'' and text[i-1] == " " and text[i+1] in acceptedChar:
            punc_Removed_Text = punc_Removed_Text + text[i]

        elif text[i] == '\'' and text[i-1] in acceptedChar and text[i+1] == " " :
            punc_Removed_Text = punc_Removed_Text + text[i]

    frequency = 0
    splitedText = punc_Removed_Text.split(word.lower())

    for y in range(0,len(splitedText)-1,1):
        element = splitedText[y]

        if len(element) == 0:
            if(splitedText[y+1][0] == " "):
                frequency += 1

        elif len(element) == 0:
            if(len(splitedText[y+1][0])==0):  
                frequency += 1

        elif len(splitedText[y+1]) == 0:
            if(element[len(element)-1] == " "):  
                frequency += 1

        elif (element[len(element)-1] == " " and splitedText[y+1][0] == " "):
            frequency += 1
    return frequency

这是个人资料:

128006 function calls in 7.831 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    7.831    7.831 :0(exec)
    32800    0.062    0.000    0.062    0.000 :0(len)
    11200    0.047    0.000    0.047    0.000 :0(lower)
        1    0.000    0.000    0.000    0.000 :0(print)
    72800    0.359    0.000    0.359    0.000 :0(replace)
        1    0.000    0.000    0.000    0.000 :0(setprofile)
     5600    0.078    0.000    0.078    0.000 :0(split)
        1    0.000    0.000    7.831    7.831 <string>:1(<module>)
        1    0.000    0.000    7.831    7.831 ideone-gg.py:225(doit)
     5600    7.285    0.001    7.831    0.001 ideone-gg.py:3(CountOccurencesInText)
        1    0.000    0.000    7.831    7.831 profile:0(doit())
        0    0.000             0.000          profile:0(profiler)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-25
    • 2012-08-09
    相关资源
    最近更新 更多