2011-02-22 4 views
2

逆の文書インデックスを作成しようとしているので、文書が出現するコレクション内のすべてのユニークな単語とその頻度を知る必要があります。Python:ネストされた辞書のキー値ペアの値を更新するにはどうすればよいですか?

私はthis答えをネストされた辞書を作成するために使用しました。提供されたソリューションはうまく動作しますが、1つの問題があります。

まず、ファイルを開いてユニークな単語のリストを作成します。これらのユニークな言葉は元のファイルと比較したいものです。一致がある場合、周波数カウンタを更新し、その値を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' 

私が行くことをどのように

....私はintに何らかの方法でAutoVivificationのインスタンスをキャストする必要があると思いますか?事前に

おかげ

私のコードは:私は推測正しい使い方ではありません

#!/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() 

答えて

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

は、代わりにこれを試してみてください。

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

、そのための値をチェックします存在しないキーはKeyErrorを送出します。 :辞書にキーが存在するかどうかを確認する必要があります。

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 

これが役立ちます。

0

なぜここにネストされたディクテーションが必要なのかよく分かりません。 > [word_ids]

と逆インデックスマッピング

word_id - - > [document_ids]

ない、これがあれば必ず代表的な指標のシナリオでは、前方のインデックスマッピング

ドキュメントIDを持っています2つのインデックスを使用すると、すべての種類のクエリ を非常に効率よく実行することができ、ネストされたデータ構造で を処理する必要がないため、実装は簡単です。AutoVivificationクラスの

0

は、その文脈でAutoVivificationであり、自己のインスタンスを返す

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

を定義します。エラーはクリアされます。

はあなたが欠落しているキーのクエリにAutoVivificationを返すようにしてもよろしいですか?コードから、文字列のキーとint値を持つ通常の辞書を返すと仮定します。

ちなみに、defaultdictクラスに興味があるかもしれません。

0

何も追加しないので、AutoVivificationをまとめて蹴る方が良いでしょう。

次の行:予想通り、あなたのクラスの動作方法で、dictionary[keyword]は常にAutoVivificationのインスタンスを返し、そうdictionary[keyword][filename]がするので

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

は、動作しません。

+0

[OK]をthatsの本当の、autovivicationクラスがなくなって、代わりにdefaultdictのために行ってきました、良さそうです – Jorrit

0

このAutoVivificationクラスは、あなたが探しているの魔法ではありません。

標準ライブラリからcollections.defaultdictをご覧ください。あなたの内部ディクテーションは、デフォルト値が整数値であるdefaultdictでなければならず、外側のdictsはdefault-dictsであり、デフォルトはinner-dict値になります。

6

AutoVivificationクラスを作成して辞書をそのタイプのオブジェクトとしてインスタンス化する代わりに、Pythonのcollections.defaultdictを使用できます。

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

これは、あなたがエントリー、使用インクリメントしたい場合は、0のデフォルト値で辞書の辞書を作成します。

dictionary[keyword][filename] += 1 
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() 
2

を、私はあなたが余分なクラスを避ける必要があります同意し、特に__getitem__である。 (小さな概念的なエラーにより、__getitem__または__getattr__がデバッグするのが非常に苦しいことがあります)。

Python dictは、あなたがしていることに対して十分に強いようです。

dictionarycollectionsから何かしたり、独自のカスタムクラスがちょうどdictではなく、どこ

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 

dict.setdefault率直についてはもちろん、これはどのようになりますか。辞書はとにかくユニークなキーを強制するので、ユニークなインスタンスを分離する

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

ない理由:

その後、再び、これはただではありません。

関連する問題