2016-10-16 6 views
2

私は電子メールのドキュメント(単語を含む文字列)で分類練習をしようとしています。Pythonの距離関数を改善する方法

Iは、次のように距離関数を定義:

def distance(wordset1, wordset2): 

if len(wordset1) < len(wordset2): 
    return len(wordset2) - len(wordset1) 
elif len(wordset1) > len(wordset2): 
    return len(wordset1) - len(wordset2) 
elif len(wordset1) == len(wordset2): 
    return 0  

しかし、最終的に精度が(0.8)はかなり低いです。私は、それほど正確ではない距離関数のためだと思います。どのように機能を改善できますか?または、電子メールドキュメント間の「距離」を計算する他の方法は何ですか?

+1

多分、両方の単語セットの交差の長さが、より良い距離機能になる可能性があります。 –

+2

その関数は1行にすることができます。 'math.abs(len1 - len2)' –

答えて

1

wordset1wordset2のタイプについては言及していません。私は彼らが両方ともstringsであると仮定します。

あなたの距離を単語カウントとして定義し、スコアが悪いです。同じサイズの2つの電子メールは完全に異なるものの話をされながら、異なるサイズを持つ2通の電子メールが、同じことについて話すことができます。これは明らかに、テキストの長さが良い非類似性の尺度ではないのです。上記で示唆したよう

だから、あなたは試みることができるし、代わりに類似した単語をチェック:

import numpy as np 

def distance(wordset1, wordset2): 
    wordset1 = set(wordset1.split()) 
    wordset2 = set(wordset2.split()) 

    common_words = wordset1 & wordset2 
    if common_words: 
     return 1/len(common_words) 
    else: 
     # They don't share any word. They are infinitely different. 
     return np.inf 

それに伴う問題は、二つの大きな電子メールは、このメトリック二つの小さなものよりも言葉を共有する可能性が高い、とということですそれらを好意して、小さなものと比べてより「互いに似ている」ようにします。これをどうやって解決するのですか?さて、何とかメトリックを正規化します:

これはクールだが、単語の頻度を完全に無視します。これを考慮に入れて、Bag-of-wordsモデルを使用することができます。つまり、すべての可能な単語のリストを作成し、それぞれの文書の外観をヒストグラム化します。

from sklearn.feature_extraction.text import CountVectorizer 

def distance(wordset1, wordset2): 
    model = CountVectorizer() 
    X = model.fit_transform([wordset1, wordset2]).toarray() 

    # uses Euclidean distance between bags. 
    return np.linalg.norm(X[0] - X[1]) 

しかし、今の電子メールの2組を考慮してください。私たちの仕事はeaiserにするために、学ぶscikitからCountVectorizer実装を使用してみましょう。最初のペアのメールは必要それは文法的に正しいとは、「小」の単語(例えばaanisandthat)の完全な、完全に書かれた英語で構成されています。 2番目のペアのメールは異なります。キーワードのみが含まれているため、非常に乾燥しています。あなたは、最初のペアは2番目のペアよりも似ている可能性があります。私たちは、各テキストに意味のある言葉を優先しなければならない一方で、我々は現在、すべての単語のために同じ占めているので、それは起こります。これを行うには、term frequency–inverse document frequencyを使用しましょう。 Luckly、非常によく似た実装がscikit-学ぶにあります:

from sklearn.feature_extraction.text import TfidfVectorizer 

def distance(wordset1, wordset2): 
    model = TfidfVectorizer() 
    X = model.fit_transform([wordset1, wordset2]).toarray() 

    similarity_matrix = X.dot(X.T) 
    # The dissimilarity between samples wordset1 and wordset2. 
    return 1-similarity_matrix[0, 1] 

はこのquestionでこの詳細についてはこちらをご覧ください。また、複製?

あなたは今、かなり良い精度を持つ必要があります。やってみて。まだそれがあなたの望みどおりではないなら、もっと深く進む必要があります(それを得るには?なぜなら、深い学習)。最初に、訓練するデータセットまたは既に訓練されたモデルのいずれかが必要であることです。有用な変換を提供するためにネットワークには多くのパラメータを調整しなければならないので、これが必要です。

これまでに見逃していたことは理解できません。単語をヒストグラム化し、文脈や意味からストライピングしました。代わりに、それらをどこに残してパターンのブロックを認識しようとしましょう。これはどうすればできますか?

  1. さまざまなサイズの単語を扱う数字に単語を埋め込みます。
  2. すべての数字(単語埋め込み)シーケンスを単一の長さにパッドします。
  3. 畳み込みネットワークを使用して、シーケンスから意味のある機能を抽出します。
  4. 完全に接続されたネットワークを使用して、類似の電子メール間の距離を最小限に抑え、類似しない電子メール間の距離を最大にする空間に抽出された機能を投影します。

Kerasを私たちの生活に使いましょう。

# ... imports and params definitions 

model = Sequential([ 
    Embedding(max_features, 
       embedding_dims, 
       input_length=maxlen, 
       dropout=0.2), 
    Convolution1D(nb_filter=nb_filter, 
        filter_length=filter_length, 
        border_mode='valid', 
        activation='relu', 
        subsample_length=1), 
    MaxPooling1D(pool_length=model.output_shape[1]), 
    Flatten(), 
    Dense(256, activation='relu'), 
]) 

# ... train or load model weights. 

def distance(wordset1, wordset2): 
    global model 
    # X = ... # Embed both emails. 
    X = sequence.pad_sequences(X, maxlen=maxlen) 
    y = model.predict(X) 
    # Euclidean distance between emails. 
    return np.linalg.norm(y[0]-y[1]) 

あなたがKeras github repoを確認することができ文処理の実用的な例があります:それは次のようになります。また、誰かがこのstackoverflow questionのsiamese recurrentネットワークを使ってこのまったく同じ問題を解決します。

これはあなたにある方向性を与えてくれることを願っています。 :-)

+0

ありがとう!私はこれを実装しようとするとエラーが表示されます: – trika

+0

申し訳ありません!私はこの例でそれを修正しました。エラーの説明: '.fit_transform(...)'メソッドはスパース行列を返します。その結果、ドット操作は「ValueError:ディメンションの不一致」となる可能性があります。これを修正するために、 '.fit_transform(...)。toarray()'に変更しました。これは密な行列を返します。 :-) – ldavid

2

この状況で使用する類似点の一般的な尺度は、Jaccard similarityです。 0から1の範囲で、0は完全な非類似性を示し、1は2つの文書が同一であることを示します。本質的に、それは単語の集合の和集合の比に単語のセットの共通部分の割合である

wordSet1 = set(wordSet1) 
wordSet2 = set(wordSet2) 
sim = len(wordSet1.intersection(wordSet2))/len(wordSet1.union(wordSet2)) 

として定義されます。これはサイズの異なる電子メールの制御を助け、類似性の優れた尺度を提供します。

+0

しかし、距離が大きくなるほど、文書の相違は大きくなりません。文書のマッピングに役立ちます。それとも問題じゃない? – trika

+0

@trikaそれはあなたに "電子メールの距離"が何であるかにまで下がります。それが大きさの違いを意味するならば、この解決策はそれを抑制します。しかし、私たちは通常、意味の相違に興味があります(つまり、「これらの2つのメールは同じことを話していますか?」)。これらの場合、サイズはまったく重要ではありません。 – ldavid

+1

あなたは2つのセットを分けることができますか?タイプミスはありますか? 'TypeError:/: 'set'と 'set''のためのサポートされていないオペランドのタイプ –

関連する問題