3

2つの名前が同じ人物であることを識別できる宝石またはプロジェクトを探しています。例えば

J.R. Smith == John R. Smith == John Smith == John Roy Smith == Johnny Smith

私はあなたがその考えを理解したと思います。100%正確になるものはないことはわかっていますが、少なくともほとんどの場合を処理できるものを入手したいと思います。最後のものはおそらくニックネームのデータベースが必要になるだろうと私は知っています。

4

8 に答える 8

4

これは少し遅れています (そして起動するための恥知らずなプラグインです) が、その価値があるために、GSoC プロジェクト中に人名パーサーgem install namaeを作成しました。明らかに重複を確実に検出するわけではありませんが、そのような種類のタスクには役立ちます。

たとえば、例の名前を解析し、イニシャルを使用して表示フォームを使用して、イニシャルが同一である名前を検出することができます。

names = Namae.parse('J.R. Smith and John R. Smith and John Smith and John Roy Smith and Johnny Smith ')
names.map { |n| [n.given, n.family] }
#=> => [["J.R.", "Smith"], ["John R.", "Smith"], ["John", "Smith"], ["John Roy", "Smith"], ["Johnny", "Smith"]]
names.map { |n| n.initials expand: true }
#=> ["J.R. Smith", "J.R. Smith", "J. Smith", "J.R. Smith", "J. Smith"]
于 2013-06-17T14:15:00.993 に答える
4

1つのオプションは、レーベンシュタイン距離のルビー実装を使用することだと思います

2 つの文字列間のレーベンシュタイン距離は、1 つの文字列を別の文字列に変換するために必要な編集の最小数として定義されます。許容される編集操作は、1 文字の挿入、削除、または置換です。

次に、距離が X より小さい名前 (X は微調整が必​​要な数値) が同じ人物からのものであると定義できます。

EDIT少し検索して、 Metaphone と呼ばれる音声学に基づいた別のアルゴリズムを見つけることができました

まだ多くの穴がありますが、この場合、誰もができる最善のことは、テストして何が最適かを確認するための代替案を提供することだと思います

于 2011-01-19T04:36:02.427 に答える
3

何かのようなもの:

1: 名前を配列に変換します。

irb> names.map!{|n|n.scan(/[^\s.]+\.?/)}
["J.", "R.", "Smith"]
["John", "R.", "Smith"]
["John", "Smith"]
["John", "Roy", "Smith"]
["Johnny", "Smith"]

2: アイデンティティの機能:

for a,b in names.combination(2)
    p [(a&b).size,a,b]
end
[2, ["J.", "R.", "Smith"], ["John", "R.", "Smith"]]
[1, ["J.", "R.", "Smith"], ["John", "Smith"]]
[1, ["J.", "R.", "Smith"], ["John", "Roy", "Smith"]]
[1, ["J.", "R.", "Smith"], ["Johnny", "Smith"]]
[2, ["John", "R.", "Smith"], ["John", "Smith"]]
[2, ["John", "R.", "Smith"], ["John", "Roy", "Smith"]]
[1, ["John", "R.", "Smith"], ["Johnny", "Smith"]]
[2, ["John", "Smith"], ["John", "Roy", "Smith"]]
[1, ["John", "Smith"], ["Johnny", "Smith"]]
[1, ["John", "Roy", "Smith"], ["Johnny", "Smith"]]

または、代わりに+ +を&使用して、特定のカスタム関数を適用し、名前の一部が同一であることを確認することもできます。.permutation.zip.max


更新:

aim = 'Rob Bobbie Johnson'
candidates = [
    "Bob Robbie John",
    "Bobbie J. Roberto",
    "R.J.B.",
]

$synonyms = Hash[ [
    ["bob",["bobbie"]],
    ["rob",["robbie","roberto"]],
] ]

def prepare name
    name.scan(/[^\s.]+\.?/).map &:downcase
end

def mf a,b # magick function
    a.zip(b).map do |i,j|
        next 1 if i == j
        next 0.9 if $synonyms[i].to_a.include?(j) || $synonyms[j].to_a.include?(i)
        next 0.5 if i[/\.$/] && j.start_with?(i.chomp '.')
        next 0.5 if j[/\.$/] && i.start_with?(j.chomp '.')
        -10 # if some part of name appears to be different -
            # it's bad even if another two parts were good
    end.inject :+
end

for c in candidates
    results = prepare(c).permutation.map do |per|
        [mf(prepare(aim),per),per]
    end
    p [results.transpose.first.max,c]
end

[-8.2, "Bob Robbie John"]  # 0.9 + 0.9 - 10 # Johnson != John # I think ..)
[2.4, "Bobbie J. Roberto"] # 1 + 0.9 + 0.5 # Rob == Roberto, Bobbie == Bobbie, Johnson ~~ J.
[1.5, "R.J.B."]            # 0.5 + 0.5 + 0.5
于 2011-01-19T04:45:15.037 に答える
1

このためにおそらく見つかる最適な事前コード化は、「テキスト」と呼ばれる宝石です。

https://github.com/threedaymonk/text

レーベンシュタイン距離、Metaphone、Soundex など、多数のマッチング アルゴリズムがあります。

于 2013-12-28T02:07:36.853 に答える
0

そのような図書館は存在しないと思います。

気分を害するつもりはありませんが、この問題はデザインの悪さから生じているようです。解決しようとしている一般的な問題について詳細を投稿すると、人々はより良​​い方法を提案できるかもしれません。

于 2011-01-19T04:32:55.533 に答える
0

Ruby での堅牢な人名マッチャー/クラスタリング ソリューションの最初の試み: https://github.com/adrianomitre/match_author_names

于 2016-12-12T02:35:22.197 に答える