Python:如何在嵌套字典中更新键值对的值?

Python:如何在嵌套字典中更新键值对的值?,python,object,casting,autovivification,Python,Object,Casting,Autovivification,我正在尝试建立一个反向文档索引,因此我需要从集合中的所有唯一单词中知道它们出现在哪个文档中,以及出现的频率 我使用了答案,以便创建嵌套字典。提供的解决方案运行良好,但有一个问题 首先,我打开文件,列出一些独特的单词。这些独特的单词我不想与原始文件进行比较。当存在匹配时,应更新频率计数器,并将其值存储在二维数组中 输出最终应如下所示: word1, {doc1 : freq}, {doc2 : freq} <br> word2, {doc1 : freq}, {doc2 : freq}

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

我使用了答案,以便创建嵌套字典。提供的解决方案运行良好,但有一个问题

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

输出最终应如下所示:

word1, {doc1 : freq}, {doc2 : freq} <br>
word2, {doc1 : freq}, {doc2 : freq}, {doc3:freq}
etc....
我想我需要在某种程度上把自生的例子转换成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()
#/usr/bin/env python
#编码:utf-8
导入系统
导入操作系统
进口稀土
导入glob
导入字符串
导入集
类别自活(dict):
“”“perl的自动激活功能的实现。”“”
定义获取项目(自身,项目):
尝试:
返回指令。获取项目(自身,项目)
除KeyError外:
值=自身[项目]=类型(自身)()
返回值
def main():
pad='temp/'
字典=自动活化()
docID=0
对于glob.glob(os.path.join(pad,'.*.html'))中的文件:#对于指定文件夹中的所有文件:
docID=docID+1
filename=“doc”+str(docID)
text=open(files,'r')。read()以字符串形式返回文件内容
text=extract(text,,“”)#调用extract函数从标记中提取文本
if (word == keyword and filename in dictionary[keyword]): 
text=text.lower() 排除=设置(字符串.标点符号)#设置所有标点符号的列表 text=''.join(如果字符不在排除中,则字符对应文本中的字符)#使用创建的排除列表从文件中删除字符 text=text.split()#从字符串创建列表(数组) uniques=集合(文本)#制作列表唯一(dat handig?we moeten nog tellen) 对于uniques中的关键字:#对于每个唯一的单词do 对于文本中的单词:#对于文档中的每个单词: 如果(word==关键字,dictionary[keyword][filename]不是None):#如果出现关键字递增计数器 freq=dictionary[keyword][filename]#这里我们失败了,无法将对象实例强制转换为整数。 freq=字典[关键字][文件名]+1 打印(关键字,字典[关键字]) 其他: 字典[单词][文件名]=1 #提取子字符串1和2之间的文本 def摘录(文本,sub1,sub2): 返回text.split(sub1,1)[-1]。split(sub2,1)[0] 如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu': main()
我想这不是正确的用法,请尝试以下方法:

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

因为,检查不存在的密钥raise KeyError的值:所以您必须检查字典中是否存在键…

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

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

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

希望这有帮助

不确定您为什么需要这里的嵌套dict。在典型的索引场景中,您有一个正向索引映射

文档id->[word\u id]

和一个逆索引映射

word\u id->[文档\u id]

不确定这是否与此相关,但使用两个索引可以执行所有类型的查询 非常高效,而且实现过程非常简单,因为您不需要处理
使用嵌套的数据结构。

在Autovification类中,您可以定义

import collections
dictionary = collections.defaultdict(lambda: collections.defaultdict(int))
它返回一个self实例,这是该上下文中的一个自动激活。然后错误就变得清晰了

是否确实要对任何缺少的密钥查询返回自动激活?从代码中,我假设您希望返回一个包含字符串键和int值的普通字典


顺便说一句,也许你会对这门课感兴趣。

最好把
自动活体化
一起踢出去,因为它不会增加任何东西

以下一行:

dictionary[keyword][filename] += 1

由于类的工作方式,
dictionary[keyword]
将始终返回一个
AutoVivification
的实例,因此
dictionary[keyword][filename]

这个autovification类并不是您想要的魔法


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

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

#!/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()
这将创建一个默认值为0的字典字典。如果要增加条目,请使用:

    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
#/usr/bin/env python
#编码:utf-8
从os.path导入联接
从全局导入全局作为全局_
从集合导入defaultdict,计数器
从字符串导入标点符号
WORKDIR='temp/'
文件类型='*.html'
outp='doc_{0}'。格式
def extract(文本,起始标记=“”,结束标记=“”):
“”“提取开始标记和结束标记之间的文本
startTag第一次出现后的第一个字符开始
如果没有,则从文本开头开始
endTag第一次后续出现之前的最后一个字符结束
如果无,则在文本末尾结束
"""
返回text.split(startTag,1)[-1]。split(endTag,1)[0]
def main():
DocWords=defaultdict(dict)
infnames=g
dictionary[keyword][filename] += 1
#!/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()
    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
        for word in text:                               #for every word in doc:
            dictionary.setdefault(word, {})
            dictionary[word].setdefault(filename, 0)
            dictionary[word][filename] += 1