2

逆のドキュメント インデックスを作成しようとしているため、コレクション内のすべての一意の単語から、それらがどのドキュメントにどのくらいの頻度で出現するかを知る必要があります。

ネストされた辞書を作成するために、この回答を使用しました。提供されたソリューションは問題なく動作しますが、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'

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

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

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

とにかく辞書は一意のキーを強制するため、一意のインスタンスを分離する理由はありません。

于 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 が発生するからです。:so キーが辞書に存在するかどうかを確認する必要があります...

于 2011-02-22T15:10:00.370 に答える
0

まだ存在しない辞書エントリに 1 を追加しようとしていると思います。getitem メソッドは、何らかの理由で、ルックアップが失敗したときに AutoVivification クラスの新しいインスタンスを返します。したがって、クラスの新しいインスタンスに 1 を追加しようとしています。

答えは、カウンターがまだ存在しない場合はカウンターを 0 に設定するように getitem メソッドを更新することだと思います。

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

ここでネストされた辞書が必要な理由がわかりません。典型的なインデックス シナリオでは、前方インデックス マッピングがあります。

ドキュメント ID -> [word_ids]

および逆インデックス マッピング

word_id -> [document_ids]

これがここに関連しているかどうかはわかりませんが、2 つのインデックスを使用すると、あらゆる種類のクエリを非常に効率的に実行でき、ネストされたデータ構造を処理する必要がないため、実装は簡単です。

于 2011-02-22T15:11:40.437 に答える
0

AutoVivification クラスでは、次を定義します。

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

これは、そのコンテキストでの AutoVivification である self のインスタンスを返します。エラーはその後明らかになります。

欠落しているキー クエリに対して 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標準ライブラリからチェックアウトします。内側の辞書は、デフォルトで整数値になる defaultdicts である必要があり、外側の辞書は、デフォルトで inner-dict 値になる defaultdicts になります。

于 2011-02-22T15:15:07.297 に答える
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 に答える