2. NOME O LOGO 2
Indice
Introduzione
- Scopo del lavoro
- Clustering
- Distanza
- Fuzzy Matching
Ricerca
- Primi passi
- Complicazioni e Fallimenti
- Stato attuale
- Test e OpenRefine
3. NOME O LOGO
Introduzione
Parte di studio effettuata prima di iniziare il
lavoro, oltre all’apprendimento del linguaggio
di programmazione Python
3
4. NOME O LOGO
Alla ricerca di errori sintattici in collezioni di
stringhe
4
Scopo del lavoro
I dati sono preziosissimi, di conseguenza la
propensione a renderli Open è di vitale importanza.
La loro qualità, però, non è sempre garantita a
causa di errori di battitura, o di errori nella
generazione automatica dei campi.
Come è possibile individuare tali errori usando
tecniche di clustering?
Al fine di giungere ad una soluzione bisogna
risolvere alcune problematiche:
Se si può lavorare direttamente con stringhe;
Come valutare la similarità tra stringhe;
Se è necessario specificare il numero di cluster;
5. NOME O LOGO 5
Clustering
Selezione e raggruppamento di
elementi omogenei in un insieme di
dati
Esempi:
- K-Means
- Affinity Propagation
- Agglomerative Clustering
Algoritmi disponibili
nella libreria
Esempio di utilizzo di K-Means, con k=3
6. NOME O LOGO 6
In generale, «lontananza» tra due
punti di un insieme, in base ad una
specifica metrica.
Esempi:
- Distanza Euclidea
- Distanza di Hamming
- Distanza di Levenshtein (o di edit)
Esempio di calcolo di distanza di
Levenshtein
Distanza
7. NOME O LOGO 7
Fuzzy String Searching
Esempio tratto dalla pagina di Wikipedia
«Approximate String Matching»
Lavora sul concetto di «Similarità», e
lavora propriamente su stringhe
Permette di operare anche sulla
similarità di sottostringhe
Sfrutta la distanza di Levenshtein
8. NOME O LOGO
Confronto tra i due possibili approcci, che
possono sembrare simili
8
Distanza di Levenshtein
VS
Fuzzy String Searching
(FuzzyWuzzy)
- Fuzzy offre più metodi di paragone tra due
stringhe, lavorando o meno con le
sottostringhe;
- La computazione della distanza di
Levenshtein è più veloce e meno onerosa in
termini di spazio;
- La distanza di edit esprime il numero di
mosse per rendere uguali le stringhe;
- Fuzzy fornisce un valore da 0 a 100 della
corrispondenza tra stringhe;
9. NOME O LOGO
Primi passi
Primo approccio al problema, con la
valutazione delle varie metriche e dei vari
algoritmi di clustering
9
10. NOME O LOGO 10
Tecniche di clustering…
per stringhe???
Le tecniche di clustering lavorano su
insieme di punti.
Dato questo input vengono calcolate le
distanze (Euclidea) e poi
successivamente si applica l’algoritmo
sulle distanze.
Quindi come fare?
11. NOME O LOGO 11
Pre-computare tutto…
lev_similarity = np.array([[similarity(w1, w2) for w1 in words] for w2 in words])
n_cluster = int(input('Inserire numero di clustern'))
cluster = AC(affinity="precomputed", n_clusters=n_cluster, linkage="complete")
cluster.fit(lev_similarity)
1. Computare per tutte le possibili coppie di parole la loro distanza (in base alla metrica scelta);
2. Scegliere il numero di cluster (se necessario);
3. Utilizzare l’istanza di una classe che implementa un algoritmo di clustering
4. Chiamare il metodo per allenare il modello passando la matrice delle similarità
12. NOME O LOGO 12
… ma come?
Distanza Euclidea? Distanza di Hamming?
Distanza di Levenshtein? FuzzyWuzzy?
13. NOME O LOGO
- Richiede il numero di cluster;
- Individua iterativamente k centroidi;
- Ricava il numero di cluster;
- Lavora inviando messaggi tra le coppie di
esemplari della matrice;
- Richiede il numero di cluster;
- Approccio Bottom-Up;
Scelta della tecnica di clustering
K-Means
13
Affinity Propagation Agglomerative Clustering
Prese in considerazioni varie tecniche, per verificarne adattamento e prestazioni sulla matrice delle distanze
14. NOME O LOGO
Complicazioni e
fallimenti
Provando le combinazioni tra le tecniche su
differenti dataset, non tutto funzionava come
di dovere, anzi…
14
15. NOME O LOGO
The Dark Side of the… FuzzyMatching
Il tanto amato (da me) metodo per computare le
distanze non è perfetto:
- Lento rispetto alla semplice distanza di Levenshtein;
- Esistenza di «Falsi positivi» (es: Nocera Superiore e
Nocera Inferiore sono «equivalenti»)
E come detto in precedenza, la distanza di edit da sola
non basta…
15
16. NOME O LOGO 16
FuzzyWuzzy & Co.
Confrontare due stringhe porta alla
creazione di una matrice
La computazione delle distanze, soprattutto per il
fuzzy matching, ha portato alla saturazione della
memoria su grandi dataset
# custom PyCharm VM options
-Xms128m
-Xmx2048m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
Pycharmx64.exe.vmoptions
Per n stringhe significa creare nxn
matrici, il cui risultato serve per riempire
una matrice nxn
17. NOME O LOGO
Scalabilità delle tecniche di clustering
La qualità della soluzione dipende da due parametri: n° di campioni e n° di cluster, e quindi con numerosi test
ho verificato quale si adattasse alla mia situazione
17
Scalabilità
Algoritmi N°campioni N°cluster
AffinityPropagation Bassa /
K-Means Alta Media
Agglomerative Alta Alta
18. NOME O LOGO
Ma… Qual è il n° di cluster giusto?
18
Con il fallimento di AffinityPropagation è nata la
necessità di determinare qual è il numero
giusto di cluster, o perlomeno un range
indicativo di valori su cui provare
20. NOME O LOGO
WomboCombo: l’unione fa la forza
Usare insieme FuzzyMatching, Distanza di
Levenshtein e un Dizionario:
Levenshtein per verificare se sono
esattamente uguali due stringhe;
Dizionario per verificare se si tratta di falsi
positivi
Eventualmente computare il FuzzyMatching
20
Distanza di
Levenshtein
FuzzyMatching
FuzzyMatching +
Levenshtein
FuzzyMatching +
Levenshtein +
Dizionario
21. NOME O LOGO
WomboCombo: il codice
21
def single_wombocombo(w1: str, w2: str, dictionary):
lev_d = single_lev(w1, w2)
if lev_d == 0:
return lev_d
if dictionary.get(w1.lower()) is not None and
dictionary.get(w2.lower()) is not None
return lev_d + 20
fuz1 = fw.ratio(w1, w2)
fuz2 = fw.partial_ratio(w1, w2)
fuz3 = fw.token_set_ratio(w1, w2)
fuzAverage = (fuz1 + fuz2 + fuz3)//3
fuzsum = (fuz2 + fuz3) // 2
if (fuzAverage > 85) or (fuzsum >= 90):
return 0
if (fuzAverage < 75) or (fuzsum < 85):
lev_d = lev_d + 20
return lev_d + 5
22. NOME O LOGO
Conteggio degli esemplari unici
22
def perfect_matching(words, dictionary):
w = np.array([x.lower() if isinstance(x, str) else x for x in words])
n_matching = 0
for word in np.unique(w):
if dictionary.get(word) is not None:
n_matching += 1
return n_matching, len(np.unique(words))
Determina rispettivamente il minimo e il massimo numero di cluster per quella collezione di stringhe
Il numero esatto si può ottenere con:
Silhouette, per restringere il range;
Mio algoritmo di verifica per individuare il numero esatto;
23. NOME O LOGO
Algoritmo di verifica
23
def check_clusters(clusters, dictionary):
if not split(clusters, dictionary):
return False, "Aumentare il n° di cluster"
if not collapse(clusters, dictionary):
return False, "Diminuire il n° di cluster"
return True, "Numero esatto di cluster"
1. Split: verifico la presenza di
due elementi presenti nel
dizionario in uno stesso
cluster
2. Collapse: verifico se due
parole simili, usando il
metodo WomboCombo,
sono in cluster diversi
Esempio di test su un dataset di 1492
stringhe, riguardanti le regioni italiane.
Erano presenti tutte le regioni, quindi il
numero atteso di cluster era 20.
Clusterizzando nel range individuato,
l’algoritmo riconosce la correttezza di
formato con 20 cluster
24. NOME O LOGO
Test e OpenRefine
Verifica su vari dataset le tecniche individuate
e confronto con un prodotto open source
targato Google (http://openrefine.org)
24
Caratteristiche dispositivo per test:
- Modello: MSI GP63 Leopard 8RF
- Intel i7 8750H
- RAM (messa a disposizione) 2GB
25. NOME O LOGO
• WomboCombo = 16.37s
• Levenshtein = 11.08s
• FuzzyWuzzy = 46.83s
Tutte e 3 le matrici permettono di
ricavare il numero di cluster
giusto
• WomboCombo = 16.78s
• Levenshtein = 9.07s
• FuzzyWuzzy = 49.83s
Levenshtein NON fornisce una
matrice ottimale (troppo simili le
parole «Rieti» e «Chieti»)
• WomboCombo = 29.10s
• Levenshtein = 20.16s
• FuzzyWuzzy = 54.63s
SOLO WomboCombo fornisce
una matrice ottimale.
Test Report
1492 regioni (N° cluster = 20)
25
1492 province (N° cluster = 89) 1492 comuni (N° cluster = 608)
Confronto tra i vari modi di calcolare le distanze, in termini di qualità e prestazioni. NB: dataset manipolati.
Lo spazio occupato per il calcolo rimane sempre elevato.
26. NOME O LOGO
OpenRefine: tool per la manipolazione dei dati
26
Tra le varie funzionalità
messe a disposizione, c’è
quella di effettuare
operazioni di clustering sulle
colonne.
La scelta è limitata a due
metodi, e ognuno di essi ha
diverse «metriche»
27. NOME O LOGO
WomboCombo vs OpenRefine
○ Nearest neighbour, distanza di edit (max 2) - Cluster non
disgiunti:
Fornisce (ovviamente) più di 5 cluster, ma con operazioni
di merge si riesce ad ottenere un risultato buono
Unica eccezione «Avellinoooo», che non inserisce in
nessun cluster
○ Key Collision con fonetica inglese o tedesca:
Si ottiene un risultato discreto, sempre con qualche
pecca, specialmente se l’errore in una stringa è presente
nella parte iniziale
○ Con nessuno degli algoritmi precedenti si riesce ad
ottenere un risultato discreto, anche per la mancata
possibilità di dividere i cluster, ma solo di unirli
Qui si avverte maggiormente l’assenza di un dizionario.
○ Unica soluzione accettabile con algoritmo KeyCollision –
fingerprint, dove crea un cluster per elemento unico. Si
ottiene il risultato finale solo mediante merge manuali
dell’utente
27
524 province (n°cluster attesi = 5) 1492 comuni (n°cluster attesi = 608)
Verifico il comportamento di OpenRefine con alcuni dei miei dataset, per vedere il suo comportamento e la soluzione proposta.
Test eseguiti su dataset manipolati. Con dataset «immacolati» clusterizza senza problemi
28. NOME O LOGO 28
WomboCombo vs OpenRefine
TEST1
Tramite merge manuale si riesce ad
ottenere una soluzione ottima
Il mio approccio fornisce direttamente
la soluzione attesa grazie all’utilizzo di
più metriche e di un dizionario
29. NOME O LOGO 29
WomboCombo vs OpenRefine
TEST2
5 errori introdotti = 5 nuovi cluster
Con la mia soluzione, l’introduzione
di errori non altera la soluzione
proposta
31. NOME O LOGO
Cosa bisogna aggiungere/migliorare a quanto già
fatto
31
Come proseguire
• Non limitarsi ad una libreria in Python, ma
scrivere anche la versione in Javascript;
• Riscrivere alcuni metodi della libreria
sfruttando tecniche di programmazione in
parallelo; scrivere meglio
• Proporre una correzione dei valori «errati»