2016-07-14 4 views
1

名前に基づいて一部のデータのクロスバリデーションを行う必要があります。名前の類似点を比較する

が 私が直面してる問題がソースに応じて、名前は例えば、わずかな変化を持っているということです

:そう、それは手動で非常に時間が厳しいだろうか

L & L AIR CONDITIONING vs L & L AIR CONDITIONING Service 

BEST ROOFING vs ROOFING INC 

私は、レコードの数千を持っているが、私が欲しいですできるだけプロセスを自動化します。

追加の単語があるので、名前を小文字にするだけでは十分ではありません。

これを処理する良いアルゴリズムはどれですか?たぶん、「INC」や「サービス」

編集のような言葉に低い重みを与える相関を計算する

私はまともなを取得していますdifflibライブラリに

difflib.SequenceMatcher(None,name_1.lower(),name_2.lower()).ratio() 

を試してみましたその結果。

+1

これは非常に難しい問題です。 – maxymoo

答えて

3

これを実現するには、コサインの類似性を使用します。それは、文字列がどのくらい近いかにマッチするスコアを与えます。私は重宝別のバージョンが

import re, math 
from collections import Counter 

WORD = re.compile(r'\w+') 

def get_cosine(vec1, vec2): 
    # print vec1, vec2 
    intersection = set(vec1.keys()) & set(vec2.keys()) 
    numerator = sum([vec1[x] * vec2[x] for x in intersection]) 

    sum1 = sum([vec1[x]**2 for x in vec1.keys()]) 
    sum2 = sum([vec2[x]**2 for x in vec2.keys()]) 
    denominator = math.sqrt(sum1) * math.sqrt(sum2) 

    if not denominator: 
     return 0.0 
    else: 
     return float(numerator)/denominator 

def text_to_vector(text): 
    return Counter(WORD.findall(text)) 

def get_similarity(a, b): 
    a = text_to_vector(a.strip().lower()) 
    b = text_to_vector(b.strip().lower()) 

    return get_cosine(a, b) 

get_similarity('L & L AIR CONDITIONING', 'L & L AIR CONDITIONING Service') # returns 0.9258200997725514 

た - ここで

は同じのお手伝いをするためのコードは(今のリンクを見つけることができなかった私は数ヶ月前に、StackOverflowの自体からこのコードを取得覚えている)であります少しNLPベースで、私はそれを執筆しました。

import re, math 
from collections import Counter 
from nltk.corpus import stopwords 
from nltk.stem.porter import * 
from nltk.corpus import wordnet as wn 

stop = stopwords.words('english') 

WORD = re.compile(r'\w+') 
stemmer = PorterStemmer() 

def get_cosine(vec1, vec2): 
    # print vec1, vec2 
    intersection = set(vec1.keys()) & set(vec2.keys()) 
    numerator = sum([vec1[x] * vec2[x] for x in intersection]) 

    sum1 = sum([vec1[x]**2 for x in vec1.keys()]) 
    sum2 = sum([vec2[x]**2 for x in vec2.keys()]) 
    denominator = math.sqrt(sum1) * math.sqrt(sum2) 

    if not denominator: 
     return 0.0 
    else: 
     return float(numerator)/denominator 

def text_to_vector(text): 
    words = WORD.findall(text) 
    a = [] 
    for i in words: 
     for ss in wn.synsets(i): 
      a.extend(ss.lemma_names()) 
    for i in words: 
     if i not in a: 
      a.append(i) 
    a = set(a) 
    w = [stemmer.stem(i) for i in a if i not in stop] 
    return Counter(w) 

def get_similarity(a, b): 
    a = text_to_vector(a.strip().lower()) 
    b = text_to_vector(b.strip().lower()) 

    return get_cosine(a, b) 

def get_char_wise_similarity(a, b): 
    a = text_to_vector(a.strip().lower()) 
    b = text_to_vector(b.strip().lower()) 
    s = [] 

    for i in a: 
     for j in b: 
      s.append(get_similarity(str(i), str(j))) 
    try: 
     return sum(s)/float(len(s)) 
    except: # len(s) == 0 
     return 0 

get_similarity('I am a good boy', 'I am a very disciplined guy') 
# Returns 0.5491201525567068 

あなたはもっと自分のユースケースのために働くかを見るためにget_similarityまたはget_char_wise_similarity両方を呼び出すことができます。私は、本当に近いものから通常の類似性を取り除いた後、十分に近いものを取り除くという性格上の類似性を使用しました。残りのものは手動で処理する必要がありました。

+0

私はdifflibライブラリを試しましたが、まともな結果が得られました。どのようにこのライブラリに対して関数を比較しますか? –

0

名前が似ていることが何を意味するのか把握する必要があります。 少しのスペルの違いは難しいでしょう - 私はそれに焦点を当てません。

のは、次の3つのバリエーションがあるとしましょう:
を -
大文字/小文字 - 追加の言葉
- スペース

対句読点私は、彼らはハイフンで区切るかどうか、その単語に、各文字列を分割することをお勧め、スペース、ピリオドなど。各文字列を、単語である要素を順番に配列に変換します。

すべて大文字にします。

次の部分はデータによって異なります。あなたは長い文字列から短い単語を削除することができます、あなたは特定のキーワードを削除することができます、あなたは配列の長い単語の大部分が一致するかどうかをチェックすることができます...あなたが選ぶものによっては、これは計算集中的かもしれません。

私には、この種のもののための既存のツールもあると確信しています。あなたの目標がここにあるかどうかによって決まります。

1

おそらくFuzzy String Matchingを試してみることができます。 this Pythonライブラリを使うことができます。

2つの単語/フレーズ間の類似度を計算するために内部的にLevenshtein Distance(@ user3080953で提案)を使用します。

fuzz.ratio("hello", "hello") 
Out: 100 

fuzz.ratio("L & L AIR CONDITIONING", "L & L AIR CONDITIONING Service") 
Out: 85 

おそらく2つの単語/句が似ていると思われるしきい値を設定できます。

+0

ファジーストリングマッチングはdifflibよりもどのように優れていますか? –

+0

それは同じことです。 'difflib'の上に構築されたばかりです – KartikKannapur

関連する問題