5

23万語のリストから重複する単語を数えようとしていました.Python辞書を使用してそうしました. コードを以下に示します。

for words in word_list:
    if words in word_dict.keys():
       word_dict[words] += 1
    else:
       word_dict[words] = 1

上記のコードは 3 分かかりました!. 私は同じコードを 150 万ワード以上実行しましたが、25 分以上実行され、我慢できずに終了しました。次に、ここから次のコードを使用できることがわかりました(以下にも示されています)。結果は驚くべきもので、数秒で完了しました。だから私の質問は、この操作を行うためのより速い方法は何ですか?. ディクショナリの作成プロセスに O(N) 時間かかっているに違いないと思います。Counter メソッドはどのようにしてこのプロセスを数秒で完了し、単語をキーとして、頻度を値として正確な辞書を作成できたのでしょうか?

from collections import Counter
word_dict = Counter(word_list)
4

5 に答える 5

6

これが原因です:

if words in word_dict.keys():

.keys()すべてのキーのリストを返します。リストのスキャンには線形時間がかかるため、プログラムは2次時間で実行されていました。

代わりにこれを試してください:

if words in word_dict:

また、興味があれば、自分でCounter実装を見ることができます。通常のPythonで書かれています。

于 2013-01-17T08:10:11.763 に答える
4

あなたの辞書カウント方法はうまく構築されていません。

defaultdict次のようにa を使用できます。

d = defaultdict(int)

for word in word_list:
    d[word] += 1

ただし、counteritertools のメソッドは、より効率的な実装で記述されているため、ほぼ同じことを行っていますが、それでも高速です。ただし、counter メソッドでは count にリストを渡す必要がありますが、defaultdict を使用すると、さまざまな場所からソースを配置して、より複雑なループを作成できます。

最終的にはあなたの好みです。リストをカウントするcounter場合、複数のソースから反復する場合、または単にプログラムにカウンターが必要で、アイテムが既にカウントされているかどうかを確認するために追加のルックアップを行いたくない場合に使用します。それからdefaultdictあなたの選択です。

于 2013-01-17T08:14:04.080 に答える
1

実際にCounterコードを見ることができます。これは、initで呼び出されるupdateメソッドです。

(のローカル定義を定義するパフォーマンストリックを使用していることに注意してくださいself.get

def update(self, iterable=None, **kwds):
    '''Like dict.update() but add counts instead of replacing them.

    Source can be an iterable, a dictionary, or another Counter instance.

    >>> c = Counter('which')
    >>> c.update('witch')           # add elements from another iterable
    >>> d = Counter('watch')
    >>> c.update(d)                 # add elements from another counter
    >>> c['h']                      # four 'h' in which, witch, and watch
    4

    '''
    # The regular dict.update() operation makes no sense here because the
    # replace behavior results in the some of original untouched counts
    # being mixed-in with all of the other counts for a mismash that
    # doesn't have a straight-forward interpretation in most counting
    # contexts.  Instead, we implement straight-addition.  Both the inputs
    # and outputs are allowed to contain zero and negative counts.

    if iterable is not None:
        if isinstance(iterable, Mapping):
            if self:
                self_get = self.get
                for elem, count in iterable.iteritems():
                    self[elem] = self_get(elem, 0) + count
            else:
                super(Counter, self).update(iterable) # fast path when counter is empty
        else:
            self_get = self.get
            for elem in iterable:
                self[elem] = self_get(elem, 0) + 1
    if kwds:
        self.update(kwds)
于 2013-01-17T08:10:42.137 に答える
0

defaultdictより競争力のある選択肢として使用することもできます。試す:

from collections import defaultdict

word_dict = defaultdict(lambda: 0)
for word in word_list:
    word_dict[word] +=1

print word_dict
于 2013-01-17T08:14:21.363 に答える