2017-01-16 12 views
0

Ich habe zwei Sätze von Namen, von denen ich die beste Übereinstimmung zwischen den beiden finden möchte, wenn keine "nahe genug" Übereinstimmung gefunden wird Ich möchte den Namen zu sich selbst passen .Die nächste ungefähre Übereinstimmung zwischen zwei Arten von Namen finden

Mein aktueller Ansatz besteht darin, einen Datenrahmen mit allen möglichen Kombinationen zu erstellen und mit .apply oder lists zu iterieren und ein Ähnlichkeitsverhältnis über SequenceMatcher zu berechnen (importiert als sm).

Das Problem ist, ich habe ein paar tausend Namen in beiden Listen, die in hartnäckigen Laufzeiten führt.

Meine passenden Kriterien wären im Idealfall ein Sm-Verhältnis von> = 0,85, wobei der Vorname im zweiten Namen als ganzes Wort vorkommt. Wenn diese Kriterien nicht erfüllt sind, sollte der Name mit sich selbst übereinstimmen.

Der letzte Schritt, den ich gerne implementieren würde, ist dann, die ursprüngliche Serie durch diese übereinstimmenden Namen zu ersetzen.

Hier ist der Code für meine aktuelle Ansatz ist, lassen Sie mich bitte wissen, ob dies ein unklar ist, wie ich klären helfen:

stop_words = [ 
      'pharmaceuticals', 
      'pharmaceutical', 
      'pharma', 
      'therapeutic', 
      'biopharma', 
      'therapeutics', 
      'international', 
      'biotechnology', 
      'vaccines', 
      '\&', 
      '&', 
      'co.', 
      'co', 
      'biotherapeutics', 
      'biotherapeutic', 
      'life science', 
      'life sciences', 
      'laboratories', 
      'biologics', 
      ] 

temp_db_companies = db['Company'] 

def approximate_match(s1, s2): 
    return str(sm(None, str(s1).lower().strip(), str(s2).lower().strip()).ratio()) + '|' + str(s2).strip() 


def replace_val_w_best_match(df, col_initial, series_final, stop_words): 
    init_names = df[col_initial].str.lower().str.split(" ", expand=True).replace(stop_words, "").fillna('') 

    init_names = pd.Series(['' for n in range(len(init_names))]).str.cat([init_names[col] for col in init_names.columns], sep= " ").str.replace(' ', ' ').reset_index() 

    matching_df = pd.DataFrame(columns = list(init_names.columns) + list(series_final), data = init_names) 

    matching_df = pd.melt(matching_df, 
          id_vars = ['index', 0], 
          value_vars = list(series_final), 
          var_name = 'Comparators', 
          value_name = 'Best match') 

# matching = matching_df.apply(lambda row: approximate_match(row[0], row['Comparators']), axis = 1) 

    l = [(matching_df[0]), list(matching_df['Comparators'])] 

    ratio = [sm(None, name1, name2) for name1 in l[0] for name2 in l[1]] 

    match = [name2 for name1 in l[0] for name2 in l[1]] 

    print(ratio[:5]) 
    print(match[:5]) 

Antwort

1

Was suchen Sie wahrscheinlich für die Distanz-Algorithmus Levenshtein ist. Es berechnet die minimale Anzahl von Bearbeitungen, die benötigt werden, um eine Zeichenfolge in die andere umzuwandeln.

Schauen Sie sich diese Bibliothek: https://github.com/ztane/python-Levenshtein/

Die Levenshtein-Bibliothek hat eine Klasse namens StringMatcher.py Ihnen mit diesem Problem zu helfen.

Diese Bibliothek enthält auch eine ähnliche Funktionalität: https://github.com/gfairchild/pyxDamerauLevenshtein

+0

Ist dies effizienter als Folge Matcher? Mein Problem ist mehr die Laufzeit als die Fähigkeit, ungefähre Zeichenfolgen zu vergleichen. – wingsoficarus116

+0

Es ist schwer zu sagen, ohne die Zeiten Ihrer bestehenden Implementierung zu sehen, aber wenn Leistung die wichtigste Sache ist, würde ich empfehlen, die zweite Implementierung zu benchmarken. Es ist in Cython geschrieben, also sollte es extrem schnell sein. Die Benchmarks auf der pyxDamerauLevenshtein-Bibliothek zeigen, laufen etwa 500.000 Vergleiche in 2 Minuten –

+0

Sieht aus wie es eine Größenordnung schneller ist, aber ich muss MS Visual C++ zuerst installieren? Der reguläre Pip-Installationsbefehl funktioniert nicht. Tut mir leid, wenn das eine banale Frage ist, würde aber gerne Ihre Empfehlung umsetzen. – wingsoficarus116

Verwandte Themen