相关单词的概率计数/频率?

时间:2012-10-01 07:08:34

标签: python string comparison counter frequency

我正在寻找一种方法来为具有共同根词/含义的单个单词生成数值概率值。

用户将使用“舞者”,“跳舞”,“跳舞”等词语生成内容。

如果“舞者”被提交30次,并且跳舞5次,我只需要一个值“舞蹈:35”来捕捉所有这些。

但是当用户同时提交“依据”这样的词语时,它不应该影响我的“舞蹈”计数,而是增加一个sperate计数以及“相应”和“相应”之类的词。

另外,我没有预先定义的根词列表需要注意。我需要根据用户生成的内容动态创建它。

所以我的问题是,什么可能是最好的解决方法?我相信没有完美的解决方案,但我认为这里的人可能会想出一个比我更好的方法。

到目前为止,我的想法是假设最有意义的单词至少有3或4个字母。因此,对于我遇到的长度大于4的每个单词,将其修剪为4(“舞者”变为“danc”),检查我的单词列表,看看我之前是否遇到过它,如果是这样的话 - 增加它的数量,如果没有 - 将其添加到该列表中,重复一遍。

我看到这里有一些类似的问题。但我没有找到任何考虑根的答案,我可以在python中实现。答案似乎是为了一个或另一个。

2 个答案:

答案 0 :(得分:3)

您正在寻找的内容也被称为词干(比语言“词根”更具技术性)。你认为没有完美的解决方案是正确的,所有的方法都会有不完美的分析或缺乏覆盖。 基本上最好的方法是使用包含词干的单词列表或词干算法。 检查这里的第一个答案以获得基于python的解决方案:

How do I do word Stemming or Lemmatization?

我在所有基于Java的项目中使用Snowball,它完全符合我的目的(它非常快,并且涵盖了多种语言)。它似乎也有一个Python包装器:

http://snowball.tartarus.org/download.php

答案 1 :(得分:3)

你不需要Java包的Python包装器,nltk得到了Snowball! :)

>>> from nltk.stem import SnowballStemmer as SS
>>> stemmer = SS('english')
>>> stemmer.stem('dance')
u'danc'
>>> stemmer.stem('danced')
u'danc'
>>> stemmer.stem('dancing')
u'danc'
>>> stemmer.stem('dancer')
u'dancer'
>>> stemmer.stem('accordance')
u'accord'

词干并不总能给你准确的根源,但它是一个很好的开始。

以下是使用词干的示例。我正在构建一个stem: (word, count)的字典,同时为每个词干选择最短的单词。 So ['dancing', 'danced', 'dances', 'dance', 'dancer'] converts to {'danc': ('dance', 4), 'dancer': ('dancer', 1)}

示例代码(取自http://en.wikipedia.org/wiki/Dance的文字)

import re
from nltk.stem import SnowballStemmer as SS

text = """Dancing has evolved many styles. African dance is interpretative.
Ballet, ballroom (such as the waltz), and tango are classical styles of dance
while square dancing and the electric slide are forms of step dances.
More recently evolved are breakdancing and other forms of street dance,
often associated with hip hop culture.
Every dance, no matter what style, has something in common.
It not only involves flexibility and body movement, but also physics.
If the proper physics are not taken into consideration, injuries may occur."""
#extract words
words = [word.lower() for word in re.findall(r'\w+',text)]

stemmer = SS('english')
counts = dict()

#count stems and extract shortest words possible
for word in words:
    stem = stemmer.stem(word)
    if stem in counts:
        shortest,count = counts[stem]
        if len(word) < len(shortest):
            shortest = word
        counts[stem] = (shortest,count+1)
    else:
        counts[stem]=(word,1)

#convert {key: (word, count)} to [(word, count, key)] for convenient sort and print
output = [wordcount + (root,) for root,wordcount in counts.items()]
#trick to sort output by count (descending) & word (alphabetically)
output.sort(key=lambda x: (-x[1],x[0]))
for item in output:
    print '%s:%d (Root: %s)' % item

<强>输出

dance:7 (Root: danc)
and:4 (Root: and)
are:4 (Root: are)
of:3 (Root: of)
style:3 (Root: style)
the:3 (Root: the)
evolved:2 (Root: evolv)
forms:2 (Root: form)
has:2 (Root: has)
not:2 (Root: not)
physics:2 (Root: physic)
african:1 (Root: african)
also:1 (Root: also)
as:1 (Root: as)
associated:1 (Root: associ)
ballet:1 (Root: ballet)
ballroom:1 (Root: ballroom)
body:1 (Root: bodi)
breakdancing:1 (Root: breakdanc)
---truncated---

我不建议根据您的特定需求进行词形还原:

>>> from nltk.stem.wordnet import WordNetLemmatizer
>>> lmtzr = WordNetLemmatizer()
>>> lmtzr.lemmatize('dance')
'dance'
>>> lmtzr.lemmatize('dancer')
'dancer'
>>> lmtzr.lemmatize('dancing')
'dancing'
>>> lmtzr.lemmatize('dances')
'dance'
>>> lmtzr.lemmatize('danced')
'danced'

子串不是一个好主意,因为它总会在某一点失败,并且很多次都会失败。

  • 固定长度:伪词'dancitization'和'dancendence'将分别匹配4个和5个字符的'dance'。
  • 比率:低比例将返回假货(如上)
  • 比率:高比率不够匹配(例如'跑')

但是通过遏制你得到:

>>> stemmer.stem('dancitization')
u'dancit'
>>> stemmer.stem('dancendence')
u'dancend'
>>> #since dancitization gives us dancit, let's try dancization to get danc
>>> stemmer.stem('dancization')
u'dancize'
>>> stemmer.stem('dancation')
u'dancat'

对于词干“danc”而言,这是令人印象深刻的不匹配结果。即使考虑到“舞者”并不是“danc”,整体的准确性也相当高。

我希望这可以帮助你开始。