Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 13
  1. #1

    Algoritmi di similarità tra stringhe

    Salve amici del forum,

    Sto per mettermi a lavorare ad un piccolo software che all'interno di un DB di circa 70.000 record di Nominativi e Data di nascita abbia la capacità di individuare i possibili Nominativi Duplicati (e fin qui niente da dire).

    Il software però deve avere anche la capacità di individuare i possibili nominativi simili (ad esempio per errori di battitura).

    Ho pensato di utilizzare l'algoritmo di Jaro-Winkler per risolvere il problema. Ma...

    Il fatto è che non posso confrontare 70.000 stringhe tra di loro per ovvi motivi di prestazioni. Quindi vorrei implementare una variante che assegni e memorizzi per ogni nominativo un VALORE DI SIMILARITA' con una stringa FISSA: (ad es. AAAAAAAAAAAAAAAAA)

    Questo dovrebbe permettermi di individuare rapidamente I possibili nominativi più simili tra di loro. Poi eseguire Jaro-Winkler solo a questa piccola porzione di nominativi per beccare i possibili Duplicati con errori di ortografia.

    Voi avete qualche soluzione già codificata e testata migliore? Avete porzioni di codice da testare?

    Grazie!
    Non sei qui per fare una scelta, la scelta l'hai già fatta...Ora devi comprendere le ragioni per cui l'hai fatta. Non possiamo vedere oltre le scelte che non ci sono chiare. http://www.chicercatrova2000.it

  2. #2
    Avendo la stringa di riferimento potresti creare una tabella temporanea che, ad esempio, ha come riferimento "Rossi" e prenda come elementi tutte i cognomi di lunghezza 5 e che cominciano con R in modo tale da scremare. Nella tabella poi potresti anche cominciare ad assegnare il valore di similarità dividendo gli elementi in "Rxxxx","Roxxx","Rosxx","Rossx","Rossi". Per la ricerca userei 3 thread che ricerchi 3 settori ben definiti della tabella.

  3. #3
    Anche senza considerare le date di nascita, puoi procedere in questa maniera:
    - parti dai nomi propri, che hanno la minima variabilità interna al gruppo; costruisci una hashtable da nome (tutto minuscolo) a lista di id in cui compare;
    - la hashtable in questione, dato che i nomi propri sono pochi, è più che gestibile a livello di confronti, per cui puoi tranquillamente fare il confronto "tutti contro tutti" (o meglio, l'elemento x con tutti gli elementi che lo seguono, quindi in tutto n*(n-1)/2 confronti);
    - stabilita una soglia sotto cui dai come "probabile" il match, se l'elemento a è "simile" all'elemento b puoi procedere a fare il check con i cognomi, che vai a cercare in base all'ID del record; rispetto al caso "tutti contro tutti in generale" hai ucciso il fattore O(n^2) sui cognomi, che è il problema principale.

    Riassumo il procedimento descritto sopra in pseudo-Python:
    codice:
    from collections import defaultdict
    data = [{}] # cursore sul DB
    names = {}
    surnames = {}
    matches = []
    for elem in data:
        n = elem.name.strip().lower()
        l = names.setdefault(n, [])
        l.append(elem.id)
        surnames[elem.id] = elem.surname
    
    for k,v in names:
        found = False
        for kk,vv in names:
            if not found:
                if k==kk:
                    found = True
                else:
                    continue
            if similar(k, kk):
                for id1 in v:
                    for id2 in vv:
                        if similar(surnames[id1], surnames[id2]):
                            matches.append((id1, id2))
    
    # ora in matches hai le coppie di ID di record con nome e cognome simile
    Si possono usare anche le date di nascita per scremare a priori, ma sarebbe da capire meglio come le hai memorizzate.
    Amaro C++, il gusto pieno dell'undefined behavior.

  4. #4
    Interessante tecnica. Hai anche il codice in Java?
    Non sei qui per fare una scelta, la scelta l'hai già fatta...Ora devi comprendere le ragioni per cui l'hai fatta. Non possiamo vedere oltre le scelte che non ci sono chiare. http://www.chicercatrova2000.it

  5. #5
    Quote Originariamente inviata da FedeV92 Visualizza il messaggio
    Avendo la stringa di riferimento potresti creare una tabella temporanea che, ad esempio, ha come riferimento "Rossi" e prenda come elementi tutte i cognomi di lunghezza 5 e che cominciano con R in modo tale da scremare. Nella tabella poi potresti anche cominciare ad assegnare il valore di similarità dividendo gli elementi in "Rxxxx","Roxxx","Rosxx","Rossx","Rossi". Per la ricerca userei 3 thread che ricerchi 3 settori ben definiti della tabella.
    Tieni presente che potrei avere in input fino a 300 record da confrontare con i 70.000. Non lo so se può essere una tecnica adatta al mio caso...
    Non sei qui per fare una scelta, la scelta l'hai già fatta...Ora devi comprendere le ragioni per cui l'hai fatta. Non possiamo vedere oltre le scelte che non ci sono chiare. http://www.chicercatrova2000.it

  6. #6
    Si hai ragione, la tecnica di MItaly è interessante e la mia in questo caso non è molto efficace...

  7. #7
    Quote Originariamente inviata da prozac2000 Visualizza il messaggio
    Interessante tecnica. Hai anche il codice in Java?
    No, e anche i codice Python che ho scritto è scritto di getto giusto per dare un'idea dell'algoritmo (similar non è una funzione vera, e data lì è una lista di dictionary, nella realtà sarà qualche genere di cursore sul DB), in ogni caso è abbastanza banale da implementare.
    Amaro C++, il gusto pieno dell'undefined behavior.

  8. #8
    MItaly ma nel tuo caso vuoi usare una tabella di appoggio con elementi i nomi propri più comuni?

  9. #9
    No, come detto sopra intendo usare una hashtable da tutti i nomi "normalizzati" (lowercase + trim degli spazi) alla lista degli ID in database.
    (in realtà la hashtable era utile per una versione precedente dell'algoritmo, effettivamente per come è impostato adesso basta semplicemente una lista di tuple nome=>lista id)
    Amaro C++, il gusto pieno dell'undefined behavior.

  10. #10
    Quote Originariamente inviata da MItaly Visualizza il messaggio
    No, come detto sopra intendo usare una hashtable da tutti i nomi "normalizzati" (lowercase + trim degli spazi) alla lista degli ID in database.
    (in realtà la hashtable era utile per una versione precedente dell'algoritmo, effettivamente per come è impostato adesso basta semplicemente una lista di tuple nome=>lista id)
    Mi intriga molto questa soluzione. Potrei anche affiancarla come alternativa all'Algoritmo di Jaro-Winkler.

    P.S.: Se avete pezzi di codice Java da postare saranno ben accetti comunque!
    Non sei qui per fare una scelta, la scelta l'hai già fatta...Ora devi comprendere le ragioni per cui l'hai fatta. Non possiamo vedere oltre le scelte che non ci sono chiare. http://www.chicercatrova2000.it

Tag per questa discussione

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.