web-dev-qa-db-ja.com

大量の文字列のセットから類似した文字列のグループを見つける

それらの類似性によって特徴付けられるいくつかのサブグループを持つ、かなり大きな文字列のセット(たとえば100)があります。これらのグループを合理的に効率的に見つけるアルゴリズムを見つけ、設計しようとしています。

例として、入力リストが左下にあり、出力グループが右にあるとしましょう。

Input                           Output
-----------------               -----------------
Jane Doe                        Mr Philip Roberts
Mr Philip Roberts               Phil Roberts     
Foo McBar                       Philip Roberts   
David Jones                     
Phil Roberts                    Foo McBar        
Davey Jones            =>         
John Smith                      David Jones      
Philip Roberts                  Dave Jones       
Dave Jones                      Davey Jones      
Jonny Smith                     
                                Jane Doe         

                                John Smith       
                                Jonny Smith 

これを合理的に効率的に解決する方法を知っている人はいますか?

類似の文字列を見つけるための標準的な方法はレーベンシュタイン距離であると思われますが、すべての文字列をリスト内の他のすべての文字列と比較せずに、どういうわけか違いを判断することなく、ここでそれをうまく活用する方法を理解できません2つの文字列が同じグループにあるかどうかを決定するためのしきい値。

別の方法としては、文字列を整数にハッシュするアルゴリズムがあります。類似した文字列は、数直線上で近接している整数にハッシュします。存在する場合でも、どのようなアルゴリズムになるのか私にはわかりません

誰かが何か考え/ポインタを持っていますか?


更新:@Will A:おそらく名前は、私が最初に思ったほど良い例ではありませんでした。開始点として、操作するデータでは、文字列に小さな変更を加えても、あるグループから別のグループにジャンプしないと思います。

42
latentflip

別の一般的な方法は、Jaccardインデックスによって文字列を関連付けることです。 http://en.wikipedia.org/wiki/Jaccard_index から始めます。

Jaccard-index(および他のいくつかの方法)を使用して、あなたのような問題を解決する方法についての記事を次に示します。

http://matpalm.com/resemblance/

23

あなたが解決しようとしている問題は、典型的な clusterization 問題です。

単純な K-Means アルゴリズムで開始し、要素とクラスターの中心間の距離を計算するための関数としてレーベンシュタイン距離を使用します。

ところで、レーベンシュタイン距離計算のアルゴリズムは、Apache Commons StringUtils- StringUtils.getLevenshteinDistance に実装されています

K-Meansの主な問題は、クラスター(サブグループ)の数を指定する必要があることです。したがって、2つのオプションがあります:いくつかのユーリスティックでK-Meansを改善するか、クラスター番号を指定する必要のない別のクラスター化アルゴリズムを使用します(ただし、このアルゴリズムはパフォーマンスが低下する可能性があり、実装する場合、実装が非常に困難になる可能性がありますあなた自身)。

7
Roman

実際の発音可能な単語について話している場合、それらの メタフォン の(開始)を比較すると役立ちます。

MRFLPRBRTS: Mr Philip Roberts
FLRBRTS: Phil Roberts   
FLPRBRTS: Philip Roberts 
FMKBR: Foo McBar      
TFTJNS: David Jones    
TFJNS: Dave Jones     
TFJNS: Davey Jones    
JNT: Jane Doe       
JNSM0: John Smith     
JNSM0: Jonny Smith
3
Wrikken

あなたが与える例では、「ボニー・スミス」は「ジョニー・スミス」と「非常に似ている」ので、ほぼ確実に同じクラスにあると見なされることになるので、レーベンシュタイン距離は不適切であると考えます。

同義語(たとえば、「John」、「Jon」、「Jonny」、「Johnny」など)を持つ特定の名前と、これらに基づくマッチングの観点から、これに取り組む必要があると思います。

2
Will A

私はそのような問題を解決しました。まず、テキストを正規化し、InCのように、文字列全体に値のない文字列の単語から抜け出します。アメリカ...

この無価値の言葉はあなたが定義する必要があります。

正規化した後、Jaro Winklerの距離を使用して名前で検査を実行し、結果を類似のオブジェクトのリストを持つオブジェクトにグループ化しました。

それは本当に良かったです。

私はこれをJavaで実行し、3万人の名前で

このアイデアが誰かに役立つことを願っています

1
Sibok666

オープンソースに記載されているこの正確な問題の解決策がありますJavaファジーマッチング用ライブラリ https://github.com/intuit/fuzzy-matcher

そこで使用されているアイデアは、単語(トークン)で名前を分解し、テキストマッチングアルゴリズムを使用して単語(Soundex、Jaccard、Lavenshtieinなど)の類似性を見つけることです。

次に、各単語から見つかったスコアを使用して、各名前のスコアを平均します。

このようなマッチングのパフォーマンスはかなり重要です。なぜなら、すべての名前をお互いにマッチングし続けると、指数関数的に複雑さが増すからです。

このライブラリは、一致アルゴリズムの等価性と推移的プロパティに依存しています。「David」が「Davey」と一致する場合、逆の一致が暗示され、これらの一致を実行する必要はありません。

このライブラリには、マッチの複雑さを軽減するためのいくつかのトリックがあり、約2秒で4000の名前に対してマッチを実行することができました。

0
mob