Analysis of user names and their mapping in Ruby

I am looking for a gem or project that will allow me to determine that two names are the same person. for instance

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

I think you get the point. I know that nothing will be 100% accurate, but I would like to get what at least handles most cases. I know that for the latter, you probably need a database of nicknames.

+3
source share
7 answers

I think one option would be to use a ruby ​​implementation of Levenshtein distance

, , , .

, X ( X , ) .

, Metaphone

, , , , ,

+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"]
+4

- :

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 , , .


UPD:

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 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
+3

, .

, , - . , , , .

+1

, , , , , "".

https://github.com/threedaymonk/text

: , , ..

+1

Ruby text, , Text::WhiteSimilarity ,

0

Source: https://habr.com/ru/post/1786307/


All Articles