2016-07-13 2 views
2

Ich habe 2 Listen von potenziell überlappenden Filmtiteln, aber möglicherweise in einer anderen Form geschrieben.
Sie sind in 2 verschiedenen Datenrahmen von Pandas. Also habe ich versucht, die map() Funktion mit der fuzzywuzzy Bibliothek zu verwenden, wie so:Wie man Filme mit difflib und Pandas fuzzy match?

df1.title.map(lambda x: process.extractOne(x, choices=df2.title, score_cutoff=95)) 

, die einige gute Qualität Ergebnisse. Aber die Zeit Komplexität ist so, dass ich es nur auf einer sehr kleinen Teilmenge von beiden Datenrahmen ausführen kann. Wenn ich versuche, die Größe der Datenrahmen zu erhöhen, wird sie schnell unbrauchbar.

Dann habe ich versucht, fuzzywuzzy durch difflib zu ersetzen. Und es ist viel schneller. Aber ich kann nicht die gewünschten Ergebnisse erzielen.

Zuerst versuchte ich:

df1.title.map(lambda x: difflib.get_close_matches(x, df2.title, n=1) 

Und das war schnell, aber die Qualität der Ergebnisse war schlecht. Es fehlen sogar einige einfache Änderungen in Groß-/Kleinschreibung. Das Spielen mit der cutoff hat nicht geholfen.

Also dachte ich, ich benutze das falsche Werkzeug. In den Dokumenten und Beispielen sah ich get_close_matches auf einzelne Wörter verwendet. In Titeln gibt es verschiedene Wörter.

Ist SequenceMatcher eine bessere Wahl?

Und wenn ja, wie passe ich es in die map() so tut es das gleiche wie die oben genannten Funktionen: nur das beste Ergebnis zurückgeben, und nur wenn das Ergebnis über einem bestimmten Verhältnis ist?

Antwort

0

ich ein Python-Paket geschrieben haben, die dieses Problem lösen soll. Unter anderem adressiert es die Komplexität des Problems (z. B. bei zwei Datasets der Länge 100 benötigt Ihr Code 10.000 Vergleiche).

Sie können es installieren pip install fuzzymatcher

verwenden Sie den here Repo here und docs zu finden.

Grund Nutzung:

Gegeben zwei Datenrahmen df_left und df_right, die Sie fuzzy wollen beitreten, können Sie die folgende schreiben:

from fuzzymatcher import link_table, left join 

# Columns to match on from df_left 
left_on = ["fname", "mname", "lname", "dob"] 

# Columns to match on from df_right 
right_on = ["name", "middlename", "surname", "date"] 

# The link table potentially contains several matches for each record 
fuzzymatcher.link_table(df_left, df_right, left_on, right_on) 

Oder wenn Sie wollen einfach nur auf dem nächsten Spiel verknüpfen:

fuzzymatcher.fuzzy_left_join(df_left, df_right, left_on, right_on) 
+0

Viel benötigtes Paket. Aber es erfordert "Visual C++ Build Tools", die 4 GB auf der Festplatte ist. – user2978216

+0

Interessant - Ich denke du bist auf Windows? Hast du schon Pandas/Numpy installiert? Können Sie Einzelheiten darüber angeben, wo/wann Sie die Fehlermeldung erhalten? – RobinL

+0

Ich bin auf Windows, Pandas/Numpy sind installiert. Installationsversuch wirft [Fehlermeldung] (https://imgur.com/a/DXD5g) – user2978216

1

Um die Möglichkeit von Partituren mit geringer Punktzahl als Ergebnis von Fallunterschieden zu eliminieren, würde ich vorschlagen, .upper() oder .lower() auf die Spalten anzuwenden, die Sie zuordnen. Nachdem Sie den Fall angepasst haben, können Sie eine Liste aller Titel in ThisList kompilieren und die folgende Funktion (unter der Angabe von SequenceMatcher) mit einer gegebenen tolerance anwenden.

def fuzzy_group_list_elements(ThisList,Tolerance): 
    from difflib import SequenceMatcher 
    Groups = {} 
    TempList = ThisList.copy() 
    for Elmt in TempList: 
     if Elmt not in Groups.keys(): 
      Groups[Elmt] = [] 
     for OtherElmt in TempList: 
      if SequenceMatcher(None,Elmt,OtherElmt).quick_ratio() > Tolerance: 
       Groups[Elmt] = Groups[Elmt] + [OtherElmt] 
       TempList.remove(OtherElmt) 
    Groups[Elmt] = list(set(Groups[Elmt])) 
    return dict((v,k) for k in Groups for v in Groups[k]) 

Anschließend können Sie die obige Funktion auf die die Filmtitel enthalten Datenrahmen Spalten anwenden:

Mapping = fuzzy_group_list_elements(ThisList,0.85) 
df['Matched Title'] = df['Title'].replace(Mapping) 
Verwandte Themen