2

我正在尝试制作一个反向文档索引,因此我需要从集合中的所有唯一单词中知道它们出现在哪个文档中以及它们出现的频率。

我已经使用了这个答案来创建一个嵌套字典。提供的解决方案工作正常,但有一个问题。

首先,我打开文件并列出唯一单词。这些独特的词我想与原始文件进行比较。当有匹配时,频率计数器应该被更新并且它的值被存储在二维数组中。

输出最终应如下所示:

word1, {doc1 : freq}, {doc2 : freq} <br>
word2, {doc1 : freq}, {doc2 : freq}, {doc3:freq}
etc....

问题是我无法更新字典变量。尝试这样做时,我收到错误:

  File "scriptV3.py", line 45, in main
    freq = dictionary[keyword][filename] + 1
TypeError: unsupported operand type(s) for +: 'AutoVivification' and 'int'

我想我需要以某种方式将 AutoVivification 的实例转换为 int....

怎么去?

提前致谢

我的代码:

#!/usr/bin/env python 
# encoding: utf-8

import sys
import os
import re
import glob
import string
import sets

class AutoVivification(dict):
    """Implementation of perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value

def main():
    pad = 'temp/'
    dictionary  = AutoVivification()
    docID = 0
    for files in glob.glob( os.path.join(pad, '*.html') ):  #for all files in specified folder:
        docID = docID + 1
        filename = "doc_"+str(docID)
        text = open(files, 'r').read()                      #returns content of file as string
        text = extract(text, '<pre>', '</pre>')             #call extract function to extract text from within <pre> tags
        text = text.lower()                                 #all words to lowercase
        exclude = set(string.punctuation)                   #sets list of all punctuation characters
        text = ''.join(char for char in text if char not in exclude) # use created exclude list to remove characters from files
        text = text.split()                                 #creates list (array) from string
        uniques = set(text)                                 #make list unique (is dat handig? we moeten nog tellen)

        for keyword in uniques:                             #For every unique word do   
            for word in text:                               #for every word in doc:
                if (word == keyword and dictionary[keyword][filename] is not None): #if there is an occurence of keyword increment counter 
                    freq = dictionary[keyword][filename]    #here we fail, cannot cast object instance to integer.
                    freq = dictionary[keyword][filename] + 1
                    print(keyword,dictionary[keyword])
                else:
                    dictionary[word][filename] = 1

#extract text between substring 1 and 2 
def extract(text, sub1, sub2): 
    return text.split(sub1, 1)[-1].split(sub2, 1)[0]    

if __name__ == '__main__':
    main()
4

9 回答 9

6

可以使用 Python 的 collections.defaultdict 而不是创建 AutoVivification 类,然后将字典实例化为该类型的对象。

import collections
dictionary = collections.defaultdict(lambda: collections.defaultdict(int))

这将创建一个默认值为 0 的字典字典。当您希望增加一个条目时,请使用:

dictionary[keyword][filename] += 1
于 2011-02-22T15:15:40.517 回答
2

我同意你应该避免额外的课程,尤其是__getitem__. (小的概念性错误可能会导致调试__getitem____getattr__非常痛苦。)

对于您正在做的事情, Pythondict似乎足够强大。

直截了当怎么办dict.setdefault

    for keyword in uniques:                             #For every unique word do   
        for word in text:                               #for every word in doc:
            if (word == keyword):
                dictionary.setdefault(keyword, {})
                dictionary[keyword].setdefault(filename, 0)
                dictionary[keyword][filename] += 1

当然,这dictionary只是一个dict,而不是collections您自己的自定义类或自定义类。

话又说回来,这不只是:

        for word in text:                               #for every word in doc:
            dictionary.setdefault(word, {})
            dictionary[word].setdefault(filename, 0)
            dictionary[word][filename] += 1

没有理由隔离唯一实例,因为 dict 无论如何都会强制使用唯一键。

于 2014-09-04T15:29:56.653 回答
0
if (word == keyword and dictionary[keyword][filename] is not None): 

我猜这不是正确的用法,而是试试这个:

if (word == keyword and filename in dictionary[keyword]): 

因为,检查不存在的键的值会引发 KeyError。:所以您必须检查字典中是否存在键...

于 2011-02-22T15:10:00.370 回答
0

我认为您正在尝试将 1 添加到尚不存在的字典条目中。您的 getitem 方法由于某种原因在查找失败时返回 AutoVivification 类的新实例。因此,您尝试将 1 添加到该类的新实例中。

我认为答案是更新 getitem 方法,以便在计数器尚不存在时将其设置为 0。

class AutoVivification(dict):
    """Implementation of perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            self[item] = 0
            return 0

希望这可以帮助。

于 2011-02-22T15:10:58.583 回答
0
#!/usr/bin/env python
# encoding: utf-8
from os.path import join
from glob import glob as glob_
from collections import defaultdict, Counter
from string import punctuation

WORKDIR  = 'temp/'
FILETYPE = '*.html'
OUTF     = 'doc_{0}'.format

def extract(text, startTag='<pre>', endTag='</pre>'):
    """Extract text between start tag and end tag

    Start at first char following first occurrence of startTag
      If none, begin at start of text
    End at last char preceding first subsequent occurrence of endTag
      If none, end at end of text
    """
    return text.split(startTag, 1)[-1].split(endTag, 1)[0]    

def main():
    DocWords = defaultdict(dict)

    infnames = glob_(join(WORKDIR, FILETYPE))
    for docId,infname in enumerate(infnames, 1):
        outfname = OUTF(docId)
        with open(infname) as inf:
            text = inf.read().lower()
        words = extract(text).strip(punctuation).split()
        for wd,num in Counter(words).iteritems():
            DocWords[wd][outfname] = num

if __name__ == '__main__':
    main()
于 2011-02-22T16:14:00.763 回答
0

不知道为什么在这里需要嵌套的字典。在典型的索引方案中,您有一个正向索引映射

文档 ID -> [word_ids]

和逆索引映射

word_id -> [document_ids]

不确定这是否与此处相关,但使用两个索引可以非常有效地执行各种查询,并且实现很简单,因为您不需要处理嵌套数据结构。

于 2011-02-22T15:11:40.437 回答
0

在 AutoVivification 类中,您定义

value = self[item] = type(self)()
return value

它返回一个 self 的实例,它是该上下文中的 AutoVivification。然后错误变得清晰。

您确定要对任何缺失的键查询返回 AutoVivification 吗?从代码中,我假设您想返回一个带有字符串键和 int 值的普通字典。

顺便说一句,也许你会对defaultdict类感兴趣。

于 2011-02-22T15:11:53.447 回答
0

最好AutoVivification一起踢出去,因为它什么也没增加。

以下行:

if (word == keyword and dictionary[keyword][filename] is not None):

由于您的类的工作方式,无法按预期工作,dictionary[keyword]将始终返回 的实例AutoVivification,因此dictionary[keyword][filename].

于 2011-02-22T15:12:57.993 回答
0

这个 AutoVivification 类不是您正在寻找的魔法。

collections.defaultdict从标准库中签出。您的内部字典应该是默认为整数值的默认字典,而您的外部字典将是默认为内部字典值的默认字典。

于 2011-02-22T15:15:07.297 回答