Ausgabe
Ich habe unten ein Skript, das die Genauigkeit einer Spalte mit Adressen in meinem Datenrahmen mit einer Spalte mit Adressen in einem anderen Datenrahmen überprüft, um zu sehen, ob sie übereinstimmen und wie gut sie übereinstimmen.
Ich verwende Rapid Fuzz. Ich habe gehört, dass es schneller ist als Fuzzywuzzy. Es dauert jedoch immer noch sehr lange, den Abgleich und die Berechnungen durchzuführen. Hier sind die CSV-Dateien. main_dataset.csv enthält etwa 3 Millionen Datensätze und reference_dataset.csv enthält etwa 10 Datensätze.
Unten ist die Zeit, die für jeden Datensatz benötigt wurde.
start time: Thu Oct 6 10:51:18 2022
end time: Thu Oct 6 10:51:23 2022
start time: Thu Oct 6 10:51:23 2022
end time: Thu Oct 6 10:51:28 2022
start time: Thu Oct 6 10:51:28 2022
end time: Thu Oct 6 10:51:32 2022
start time: Thu Oct 6 10:51:32 2022
end time: Thu Oct 6 10:51:36 2022
start time: Thu Oct 6 10:51:36 2022
end time: Thu Oct 6 10:51:41 2022
start time: Thu Oct 6 10:51:41 2022
end time: Thu Oct 6 10:51:45 2022
start time: Thu Oct 6 10:51:45 2022
end time: Thu Oct 6 10:51:50 2022
start time: Thu Oct 6 10:51:50 2022
end time: Thu Oct 6 10:51:54 2022
start time: Thu Oct 6 10:51:54 2022
end time: Thu Oct 6 10:51:59 2022
Mein Skript ist hier:
import pandas as pd
from rapidfuzz import process, fuzz
import time
from dask import dataframe as dd
ref_df = pd.read_csv('reference_dataset.csv')
df = dd.read_csv('main_dataset.csv', low_memory=False)
contacts_addresses = list(df.address)
ref_addresses = list(ref_df.ref_address.unique())
def scoringMatches(x, s):
o = process.extract(x, s, score_cutoff = 60)
if o != None:
return o[1]
def match_addresses(add, contacts_addresses, min_score=0):
response = process.extract(add, contacts_addresses, scorer=fuzz.token_sort_ratio)
return response
def get_highest_score(scores):
total_scores = []
for val in scores:
total_scores.append(val[1])
max_value = max(total_scores)
max_index = total_scores.index(max_value)
return scores[max_index]
scores_list = []
names = []
for x in ref_addresses:
# start = time.time()
# print("start time:", time.ctime(start))
scores = match_addresses(x, contacts_addresses, 75)
match = get_highest_score(scores)
name = (str(x), str(match[0]))
names.append(name)
score = int(match[1])
scores_list.append(score)
# end = time.time()
# print("end time:", time.ctime(end))
name_dict = dict(names)
match_df = pd.DataFrame(name_dict.items(), columns=['ref_address', 'matched_address'])
scores_df = pd.DataFrame(scores_list)
merged_results_01 = pd.concat([match_df, scores_df], axis=1)
merged_results_02 = pd.merge(ref_df, merged_results_01, how='right', on='ref_address')
merged_results_02.to_csv('results.csv')
Lösung
Es wird empfohlen, process.cdist
which vergleicht zwei Sequenzen und erhält eine Ähnlichkeitsmatrix anstelle von process.extract
/ process.extractOne
jetzt, da viele der neueren Leistungsverbesserungen bisher nur zu diesem Algorithmus hinzugefügt wurden.
Diese Verbesserungen sind nämlich:
- Unterstützung für Multithreading mit dem
workers
Argument - Unterstützung für den parallelen Vergleich mehrerer kurzer Sequenzen (<= 64 Zeichen) mit SIMD auf x64.
Diese beiden Verbesserungen werden irgendwann zu process.extract
und hinzugefügt process.extractOne
, aber zu diesem Zeitpunkt (rapidfuzz==v2.11.1) existieren sie nur.
Ein paar relevante Punkte für zukünftige Verbesserungen an dieser Front sind:
- simd-Unterstützung für alle Funktionen im Prozessmodul
- simd-Unterstützung für längere Sequenzen
- Multithreading-Unterstützung für alle Funktionen im Prozessmodul
- Erweiterung des Prozessmoduls .
Dies könnte z. B. folgendermaßen umgesetzt werden:
from itertools import islice
chunk_size = 100
ref_addr_iter = iter(ref_addresses)
while ref_addr_chunk := list(islice(ref_addr_iter, chunk_size)):
scores = process.cdist(ref_addr_chunk, contacts_addresses, scorer=fuzz.token_sort_ratio, score_cutoff=75, workers=-1)
max_scores_idx = scores.argmax(axis=1)
for ref_addr_idx, score_idx in enumerate(max_scores_idx):
names.append((ref_addr_chunk[ref_addr_idx], contacts_addresses[score_idx]))
scores_list.append(scores[ref_addr_idx,score_idx])
Beantwortet von – maxbachmann
Antwort geprüft von – Senaida (FixError Volunteer)