2013-10-30 48 views
13

我已经从文档中提取了句子的列表。我正在预处理这个句子列表以使它更明智。我面临着以下问题使用字典查找python中的空格固定单词?

我有句如"more recen t ly the develop ment, wh ich is a po ten t "

我想使用查找字典来纠正这样的句子?去除不需要的空间。

最终的输出应"more recently the development, which is a potent "

我会认为这是在预处理文本直接的任务吗?我需要一些指引来寻求这种方法。谢谢。

回答

5

看看单词或文字segmentation。问题是要找到一个字符串最可能的拆分成一组字。例如:

thequickbrownfoxjumpsoverthelazydog 

最可能的分割应当然:

the quick brown fox jumps over the lazy dog 

下面是使用Google Ngram语料库包括用于所述问题原型源代码的制品:

关键是这个工作的算法是获取关于世界的知识,在这种情况下是某种语言的词频。我实现了一个版本,这里的文章中所描述的算法:

用法示例:

$ python segmentation.py t hequi ckbrownfoxjum ped 
thequickbrownfoxjumped 
['the', 'quick', 'brown', 'fox', 'jumped'] 

使用的数据,即使这样可以重新排序:

$ python segmentation.py lmaoro fll olwt f pwned 
lmaorofllolwtfpwned 
['lmao', 'rofl', 'lol', 'wtf', 'pwned'] 

请注意,该算法是相当慢 - 它是prototypica湖

使用NLTK另一种方法:

至于你的问题,你可以只串连,你必须得到一个字符串并在其上运行分割算法的所有字符串部分。

+3

但是,当句子可以按多个顺序排列时,它是如何工作的? “笔更适合当时的人” – DhruvPathak

+1

优雅的方法,但放弃所有空间将其变成一个更难的问题。 OPS描述(“删除不需要的空间”)表明空间永远不会丢失;如果这是正确的,你应该永远不要在分词中寻找片段。 – alexis

+1

@alexis,你说得对,我猜测性能可以提高至少一个数量级,只需计算各种连接的概率,而不是所有的分割。我稍后可能会回来重新阐述我的答案。 – miku

2

这里的东西很基本的:

chunks = [] 
for chunk in my_str.split(): 
    chunks.append(chunk) 
    joined = ''.join(chunks) 
    if is_word(joined): 
     print joined, 
     del chunks[:] 

# deal with left overs 
if chunks: 
    print ''.join(chunks) 

我假定你有一组有效的地方的话,可以被用来实现is_word。你还必须确保它处理标点符号。下面是其中一个办法是:

def is_word(wd): 
    if not wd: 
     return False 
    # Strip of trailing punctuation. There might be stuff in front 
    # that you want to strip too, such as open parentheses; this is 
    # just to give the idea, not a complete solution. 
    if wd[-1] in ',.!?;:': 
     wd = wd[:-1] 
    return wd in valid_words 
3

- 解决方案1:

让这些大块的认为你的句子作为算盘的珠子,每个珠子组成部分字符串,珠可以向左或向右移动以产生排列。每个片段的位置固定在两个相邻片段之间。 在目前的情况下,珠会:

(more)(recen)(t)(ly)(the)(develop)(ment,)(wh)(ich)(is)(a)(po)(ten)(t) 

这解决了2子问题:

一)珠是一个单位,所以我们不关心的“更多”珠即排列中排列是不可能的。

b)珠子的顺序是恒定的,只有它们之间的间距发生变化。即“更多”将总是在“重新”之前等等。

现在,产生的这些珠子,这将给像输出所有排列:

morerecentlythedevelopment,which is a potent 
morerecentlythedevelopment,which is a poten t 
morerecentlythedevelop ment, wh ich is a po tent 
morerecentlythedevelop ment, wh ich is a po ten t 
morerecentlythe development,whichisapotent 

则得分这些排列基础上,他们是如何从相关的字典很多字包含最正确的结果可以很容易地过滤出。 more recently the development, which is a potent将比分这确实珠的排列部分高于morerecentlythedevelop ment, wh ich is a po ten t

代码:

import re 

def gen_abacus_perms(frags): 
    if len(frags) == 0: 
     return [] 
    if len(frags) == 1: 
     return [frags[0]] 

    prefix_1 = "{0}{1}".format(frags[0],frags[1]) 
    prefix_2 = "{0} {1}".format(frags[0],frags[1]) 
    if len(frags) == 2: 
     nres = [prefix_1,prefix_2] 
     return nres 

    rem_perms = gen_abacus_perms(frags[2:]) 
    res = ["{0}{1}".format(prefix_1, x) for x in rem_perms] + ["{0} {1}".format(prefix_1, x) for x in rem_perms] + \ 
["{0}{1}".format(prefix_2, x) for x in rem_perms] + ["{0} {1}".format(prefix_2 , x) for x in rem_perms] 
    return res 



broken = "more recen t ly the develop ment, wh ich is a po ten t" 
frags = re.split("\s+",broken) 
perms = gen_abacus_perms(frags) 
print("\n".join(perms)) 

演示http://ideone.com/pt4PSt


- 解决方案#2 :

我会建议一种替代方法,它利用了人们已经开发的文本分析智能,这些智能人员正在研究类似的问题,并研究了依赖字典和语法的大数据语料库。搜索引擎。

我不太了解这样的公共/付费apis,所以我的例子是基于谷歌的结果。

让我们尝试使用谷歌:

  1. 你可以保持把你的无效条款,谷歌,多传球,并保持在评估基础上的查找字典一些得分的结果。 这里有两个相关的输出,通过使用2遍你的文字:

enter image description here

这outout用于第二遍:

enter image description here

,让你转换为“ “最近的发展,这是一个有力的”。

要验证转换,您将不得不使用一些相似性算法和评分来筛选出无效/不太好的结果。

一个原始技术可能是使用difflib比较标准化字符串。

>>> import difflib 
>>> import re 
>>> input = "more recen t ly the develop ment, wh ich is a po ten t " 
>>> output = "more recently the development, which is a potent " 
>>> input_norm = re.sub(r'\W+', '', input).lower() 
>>> output_norm = re.sub(r'\W+', '', output).lower() 
>>> input_norm 
'morerecentlythedevelopmentwhichisapotent' 
>>> output_norm 
'morerecentlythedevelopmentwhichisapotent' 
>>> difflib.SequenceMatcher(None,input_norm,output_norm).ratio() 
1.0 
+1

瓶颈将是可以发送到免费谷歌的最大100个查询api =) – alvas

4

您的目标是改善文本,不一定非要完美;所以你所概述的方法在我看来是有道理的。我会保持简单并使用“贪婪”的方法:只要结果在字典中,从第一个片段开始并粘贴片段;如果结果不是,请吐出你目前为止的内容,并从下一个片段开始。是的,偶尔你会因为诸如the me thod之类的情况而犯错,所以如果你将使用这个很多,你可以寻找更复杂的东西。但是,这可能够好了。

主要是你需要的是一个大字典。如果您将使用它,我会将它编码为“前缀树”(又名trie),以便您可以快速找出片段是否是真实单词的开头。 nltk提供了一个Trie implementation.

由于这种虚假的word中断是不一致的,我还会用当前文档中已经处理过的单词扩展我的字典;你可能早就看过完整的单词,但现在它已经被分解了。

+0

由于您可以检查子节点之一是否使用了'recen'之后的't',因此trie将是一个很好的解决方案的确如此),因此,您可以合并“跳过空格”和“查找可能的单词”算法。 –

3

我会建议剥离空间并寻找字典单词将其分解。有几件事你可以做,以使其更准确。为了使文本中的第一个单词无空格,请尝试整个字符串,并从文件中查找字典单词(可从http://wordlist.sourceforge.net/下载几个这样的文件),这是最长的一个,而不是从末尾取下字母你想要分割的字符串。如果你想让它工作在一个大的字符串上,你可以使它自动从后面取下字母,这样你查找第一个单词的字符串只有最长的字典单词。这应该会导致您找到最长的单词,并使其不太可能将类别“异步”分类为“同步”。下面是一个使用原始输入取文本纠正一个例子,一个名为字典文件dictionary.txt:

dict = open("dictionary.txt",'r')        #loads a file with a list of words to break string up into 
words = raw_input("enter text to correct spaces on: ") 
words = words.strip()           #strips away spaces 
spaced = []              #this is the list of newly broken up words 
parsing = True             #this represents when the while loop can end 
while parsing: 
    if len(words) == 0:           #checks if all of the text has been broken into words, if it has been it will end the while loop 
     parsing = False 
    iterating = True 
    for iteration in range(45):         #goes through each of the possible word lengths, starting from the biggest 
     if iterating == False: 
      break 
     word = words[:45-iteration]        #each iteration, the word has one letter removed from the back, starting with the longest possible number of letters, 45 
     for line in dict: 
      line = line[:-1]          #this deletes the last character of the dictionary word, which will be a newline. delete this line of code if it is not a newline, or change it to [1:] if the newline character is at the beginning 
      if line == word:          #this finds if this is the word we are looking for 
       spaced.append(word) 
       words = words[-(len(word)):]      #takes away the word from the text list 
       iterating = False 
       break 
print ' '.join(spaced)           #prints the output 

如果你希望它是更准确,你可以尝试使用自然语言解析程序,有几种可用于python免费在线。

2

你可以迭代单词词典来找到最合适的。未找到匹配项时将单词添加到一起。

def iterate(word,dictionary): 
    for word in dictionary: 
     if words in possibleWord: 
     finished_sentence.append(words) 
     added = True 
     else: 
     added = False 
     return [added,finished_sentence] 
sentence = "more recen t ly the develop ment, wh ich is a po ten t " 
finished_sentence = "" 
sentence = sentence.split() 
for word in sentence: 
    added,new_word = interate(word,dictionary) 
    while True: 
    if added == False: 
     word += possible[sentence.find(possibleWord)] 
     iterate(word,dictionary) 
    else: 
     break 
    finished_sentence.append(word) 

这应该工作。对于变量dictionary,请下载每个英语单词的txt file,然后在程序中打开它。