0

文を含むデータフレーム シリーズがあります。(長いものもあります)

キーとしての単語とカウントとしてのintを含む2つの辞書もあります。

文字列のすべての単語が両方の辞書に存在するわけではありません。1 つだけに含まれるものもあれば、どちらにも含まれないものもあります。

データフレームの長さは 124011 ユニットです。関数は、文字列ごとに約 0.4 かかります。これは長いです。

W は単なる辞書の参照値です (weights = {}, weights[W] = {})

ここに関数があります:

def match_share(string, W, weights, rel_weight):

    words = string.split()

    words_counts = Counter(words)

    ratios = []

    for word in words:

        if ((word in weights[W].keys())&(word in rel_weight[W].keys())):

            if (weights[W][word]!=0):

                ratios.append(words_counts[word]*rel_weight[W][word]/weights[W][word])

        else:

            ratios.append(0)

    if len(words)>0:

        ratios = np.divide(ratios, float(len(words)))

    ratio = np.sum(ratios)

    return ratio

どうも

4

3 に答える 3

1

少しきれいにしましょう:

def match_share(string, W, weights, rel_weight):

    words = string.split()

    words_counts = Counter(words)

    words = string.split()

    words_counts = Counter(words)

それは冗長です!4 つのステートメントを 2 に置き換えます。

def match_share(string, W, weights, rel_weight):

    words = string.split()    
    words_counts = Counter(words)

次:

    ratios = []

    for word in words:    

        if ((word in weights[W].keys())&(word in rel_weight[W].keys())):

            if (weights[W][word]!=0):

                ratios.append(words_counts[word]*rel_weight[W][word]/weights[W][word])

        else:

            ratios.append(0)

そのコードが何をするかはわかりません。あなたがトリッキーではないことを願っています。しかし.keys、イテラブルを返し、X in <iterable>よりもかなり遅いですX in <dict>。また、注意:weights[W][word] != 0最も内側の ( ) 条件が失敗した場合、何も追加しません。別の else 条件で 0 を追加しようとするため、これはバグである可能性があります。(あなたが何をしているのかわかりませんので、指摘するだけです。) そして、これは Python であり、Perl でも C でも Java でもありません。したがって、周りに括弧は必要ありませんif <test>:

それで行きましょう:

    ratios = []

    for word in words:
        if word in weights[W] and word in rel_weight[W]:
            if weights[W][word] != 0:    
                ratios.append(words_counts[word] * rel_weight[W][word] / weights[W][word])

        else:
            ratios.append(0)

次:

    if len(words)>0:

        ratios = np.divide(ratios, float(len(words)))

ゼロ除算を防ごうとしています。ただし、リストの真実性を使用してこれを確認し、比較を回避できます。

    if words:
        ratios = np.divide(ratios, float(len(words)))

残りは問題ありませんが、変数は必要ありません。

    ratio = np.sum(ratios)

    return ratio

これらの mod を適用すると、関数は次のようになります。

def match_share(string, W, weights, rel_weight):

    words = string.split()    
    words_counts = Counter(words)
    ratios = []

    for word in words:
        if word in weights[W] and word in rel_weight[W]:
            if weights[W][word] != 0:    
                ratios.append(words_counts[word] * rel_weight[W][word] / weights[W][word])

        else:
            ratios.append(0)

    if words:
        ratios = np.divide(ratios, float(len(words)))

    ratio = np.sum(ratios)
    return ratio

少し難しく見てみると、次のようにしていることがわかります。

word_counts = Counter(words)

for word in words:
    append(   word_counts[word] * ...)

私によると、それは「apple」が 6 回出現する場合、単語ごとに 6*... をリストに追加することを意味します。したがって、リストには 6*... が 6 回出現します。それがあなたが望むものだと確信していますか?それともfor word in word_counts、個別の単語を反復処理する必要がありますか?

もう 1 つの最適化は、ループ内からルックアップを削除することです。の値が変化しないにもかかわらず、weights[W]とを検索し続けます。これらの値をループの外にキャッシュしましょう。また、メソッドへのポインタをキャッシュしましょう。rel_weight[W]Wratios.append

def match_share(string, W, weights, rel_weight):

    words = string.split()    
    words_counts = Counter(words)
    ratios = []

    # Cache these values for speed in loop
    ratios_append = ratios.append
    weights_W = weights[W]
    rel_W = rel_weight[W]

    for word in words:
        if word in weights_W and word in rel_W:
            if weights_W[word] != 0:    
                ratios_append(words_counts[word] * rel_W[word] / weights_W[word])

        else:
            ratios_append(0)

    if words:
        ratios = np.divide(ratios, float(len(words)))

    ratio = np.sum(ratios)
    return ratio

それを試して、それがどのように機能するかを見てください。上記の太字のメモと質問を見てください。バグがあるかもしれませんし、スピードアップする方法が他にもあるかもしれません。

于 2017-04-03T00:09:37.003 に答える
1

その関数実行のプロファイルがあればよいのですが、一般的なアイデアをいくつか示します。

  1. 反復ごとに不必要にいくつかの要素を取得します。ループの前にこれらを抽出できます

例えば

weights_W = weights[W]
rel_weights_W = rel_weights[W]
  1. 辞書を呼び出す必要はありません.keys()

これらは同等です:

word in weights_W.keys()
word in weights_W
  1. 最初に値を調べずに値を取得しようとします。これにより、ルックアップが 1 回節約されます。

たとえば、次の代わりに:

if ((word in weights[W].keys())&(word in rel_weight[W].keys())):
        if (weights[W][word]!=0):

できるよ:

word_weight = weights_W.get(word)
if word_weight is not None:
    word_rel_weight = rel_weights_W.get(word)
    if word_rel_weight is not None:
        if word_weight != 0:  # lookup saved here
于 2017-04-03T00:12:16.607 に答える