You are on page 1of 69

Corso di Laurea (ordinamento ex D.M.

270/2004) in Informatica Tesi di Laurea

UN NUOVO ALGORITMO PER IL MINING DEI CONDENSED C O L O C AT I O N PAT T E R N

relatore Dott. Claudio Silvestri laureando Andrea Lazzarotto Matricola 833897 anno accademico 2012/2013

UN NUOVO ALGORITMO PER IL MINING DEI C O N D E N S E D C O L O C AT I O N PAT T E R N andrea lazzarotto

Dipartimento di Scienze Ambientali, Informatica e Statistica Università Ca’ Foscari Venezia Ottobre 2013

Andrea Lazzarotto: Un nuovo algoritmo per il mining dei condensed colocation pattern, © Ottobre 2013

At leve er ikke nok. . . solskin, frihed og en lille blomst må man have. — Hans Christian Andersen Vivere non è abbastanza. . . uno deve avere il sole, la libertà e un piccolo fiore.

ABSTRACT

Il mining dei colocation pattern è stato studiato per diverse tipologie di applicazioni. Nonostante ciò, spesso tale processo porta alla generazione di un numero eccessivamente elevato di candidati. In molti contesti, è sufficiente o preferibile esaminare un’approssimazione del participation index invece di un valore esatto. Questa scelta determina un insieme di colocation pattern compatto, i cui elementi vengono definiti condensed colocation pattern. Lo scopo di questa tesi è quello di proporre un algoritmo per il mining dei condensed colocation pattern. Tale algoritmo viene messo a confronto con altri algoritmi per i colocation pattern presenti in letteratura, per analizzarne l’efficienza e la qualità dei risultati.

vii

RICONOSCIMENTI

Ci sono state numerose persone che a vario titolo hanno influenzato ed aiutato il percorso che mi ha portato al raggiungimento di questo traguardo. Un sentito ringraziamento va a tutti coloro i quali credono in me, a partire dai miei genitori che mi hanno sempre supportato e permesso di proseguire negli studi. Ringrazio coloro i quali sono miei compagni di studi ma soprattutto amici quotidiani, anche se sono troppi per essere nominati uno per uno, meriterebbero ciascuno una menzione personale. Un grazie di cuore va inoltre alla mia migliore amica Paola, a Nicolò, e agli altri amici sempre presenti nella mia vita. Le esperienze vissute durante il mio corso di laurea sono state numerose e variegate, ma quella dell’Erasmus resterà sempre un ricordo vivo e indelebile. Pertanto desidero ringraziare le persone conosciute ad Aabenraa, tra cui Tana, Sergio, Henrik, Justina, Silja, Bettina e tutti gli altri. Grazie per quello che è stato il mese che mi ha fornito finora la più intensa esperienza umana e accademica di sempre. Infine, ringrazio il Dott. Claudio Silvestri per il suo ruolo di supervisore nella mia attività di tirocinio, il quale ha avuto fiducia nel mio lavoro per questa tesi.

Andrea

ix

INDICE

i il mining dei colocation pattern 1 descrizione del problema 1.1 Concetti basilari . . . . . . . . . . . . . . 1.2 Enunciato del problema . . . . . . . . . 1.3 Strategie utilizzate in letteratura . . . . 2 maximal colocation pattern 2.1 Definizioni . . . . . . . . . . . . . . . . . 2.2 Enunciato del problema . . . . . . . . . 2.3 Algoritmo MAXColoc . . . . . . . . . . 3 top - k closed colocation pattern 3.1 Definizioni . . . . . . . . . . . . . . . . . 3.2 Enunciato del problema . . . . . . . . . 3.3 Algoritmo TopKColoc . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1 3 3 5 6 9 9 11 11 17 17 18 18 25 27 27 29 31 34 35 35 35 40 43 45 47 47 53 55

ii il nuovo algoritmo 4 condensed colocation pattern 4.1 Un nuovo tipo di colocation pattern . . . . 4.2 Enunciato del problema . . . . . . . . . . . 4.3 Algoritmo e caratteristiche delle soluzioni . 4.4 Vantaggi attesi . . . . . . . . . . . . . . . . . 5 analisi dei risultati 5.1 Descrizione dei test . . . . . . . . . . . . . . 5.2 Confronto con MAXColoc . . . . . . . . . . 5.3 Confronto con TopKColoc . . . . . . . . . . 6 conclusioni

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

iii appendice a porzioni significative di codice a.0.1 main.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . a.0.2 Metodo FPGrowth da FPTree.cpp . . . . . . . . . . . . . bibliografia

xi

ELENCO DELLE FIGURE

Figura 1.1 Figura 2.1 Figura 2.2 Figura 2.3 Figura 3.1 Figura 4.1 Figura 5.1 Figura 5.2 Figura 5.3 Figura 5.4 Figura 5.5 Figura 5.6 Figura 5.7

Un esempio di grafo formato da S e R . . . Pre-elaborazione e transazioni [11] . . . . . Generazione dei candidati [11] . . . . . . . Pruning dei sottoinsiemi in MAXColoc [11] Pruning dei candidati in TopKColoc [10] . Esempio di partizionamento non univoco . Rappresentazione dei nodi contenuti in D1 Risultati dell’Esperimento 1 . . . . . . . . . Risultati dell’Esperimento 2 . . . . . . . . . Risultati dell’Esperimento 3 . . . . . . . . . Risultati dell’Esperimento 4 . . . . . . . . . Risultati dell’Esperimento 5 . . . . . . . . . Risultati dell’Esperimento 6 . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

4 10 12 13 19 29 36 38 38 39 41 41 42

E L E N C O D E L L E TA B E L L E

Tabella 2.1 Tabella 2.2 Tabella 3.1 Tabella 3.2 Tabella 4.1

Variabili di input per MAXColoc . . . Simboli utilizzati in MAXColoc . . . . Variabili di input per TopKColoc . . . Simboli utilizzati in TopKColoc . . . . Variabili di input per TopKCondensed

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

14 15 20 22 32

ELENCO DEGLI ALGORITMI

Algoritmo 2.1 Algoritmo 3.1 Algoritmo 4.1

MAXColoc . . . . . . . . . . . . . . . . . . . . . TopKColoc . . . . . . . . . . . . . . . . . . . . . TopKCondensed . . . . . . . . . . . . . . . . . .

14 21 33

xii

Parte I I L M I N I N G D E I C O L O C AT I O N PAT T E R N

DESCRIZIONE DEL PROBLEMA

1

L’attività di data mining consiste nell’estrazione di informazioni da una grande quantità di dati. L’utilizzo sempre più diffuso dei sensori e degli strumenti di raccolta automatica dei dati ha portato alla produzione sempre maggiore di grandi collezioni di dati spaziali [4]. Da ciò deriva il crescente interesse per l’estrazione di informazioni utili ma implicite e di conseguenza è necessario disporre di algoritmi che consentano di affrontare il problema in modo efficiente [9]. In questo capitolo vengono presentate le definizioni generali relative al problema del mining dei colocation pattern e sono presentate diverse soluzioni presenti in letteratura. I Capitoli 2 e 3 specializzano la trattazione discutendo due specifici algoritmi e la Parte ii della tesi illustra il nuovo tipo di pattern proposto, nonché un algoritmo per estrarne le istanze. 1.1 concetti basilari

Il nostro interesse si concentra sulle relazioni che intercorrono tra le istanze di elementi (o categorie) E = {e1 , e2 , . . . , em }. Tali relazioni sono derivanti dal fatto che gli oggetti sono posizionati nello spazio. Il modo in cui tali istanze compaiono frequentemente vicine dà luogo a delle regolarità dette colocation pattern. Si può in sintesi dire che un colocation pattern è un’associazione che rappresenta la coesistenza di un insieme di oggetti con un certo rapporto di vicinanza [7]. Alcuni esempi di utilizzo dei colocation pattern includono lo studio della relazione tra le sorgenti di acque stagnanti e le malattie infettive, l’analisi delle combinazioni dei prodotti acquistati più spesso insieme nei supermercati, o i servizi richiesti dagli utenti di reti mobili in una determinata area geografica [10]. I campi di applicazione di questo tipo di data mining sono vastissimi e includono problematiche relative a biologia, scienze della terra, salute pubblica, trasporti, geografia, ingegneria e altro [4, 12]. Di seguito vengono definiti i termini fondamentali relativi al mining dei colocation pattern, similmente a quanto riportato in Bow [2]. evento spaziale Un elemento di interesse. Un esempio potrebbe essere un tipico punto di interesse come un aereoporto o una scuola. Tuttavia si può trattare anche del verificarsi di un evento appartenente ad una certa categoria, come ad esempio il verificarsi di un caso di infezione da virus.

3

4

descrizione del problema

Figura 1.1: Un esempio di grafo formato da S e R

colocation Sono dati un insieme di eventi spaziali E, le corrispondenti istanze S e una relazione di vicinanza R su S. Una colocation X è un insieme di eventi X ⊆ E le cui istanze formano frequentemente clique o, in altre parole, formano spesso dei sottografi completi in riferimento alla relazione R. La relazione R vige sull’insieme delle istanze S formando un grafo non orientato i cui nodi ni sono elementi di S e ciascun arco (ni , n j ) è presente se e solo se i nodi ni e n j sono vicini secondo R, ovvero se la loro distanza massima è sotto ad una certa soglia, per esempio 200 metri. In Figura 1.1 è possibile vedere un esempio di dati con eventi I = { Bar, Parco, Scuola} e gli archi che indicano le coppie di nodi vicini. In questo caso si individuano le seguenti colocation: { B, P } , { B, S } , { P, S } e { B, P, S }. colocation instance Un’istanza I di una colocation X è un insieme di oggetti I ⊆ S il quale include tutti i tipi di evento di X e forma una clique. Per esempio, nella Figura 1.1 { B.1, S.1} e { B.3, S.2} sono istanze di { B, S} mentre l’insieme { B.1, S.2} non costituisce un’istanza valida. Il livello di prevalenza di una colocation instance è usualmente misurato tramite il participation index [2, 9]. Tale valore viene anche definito supporto [7, 8, 12]. participation index Questa misura viene indicata con PI ( X ), relativamente ad una colocation X , ed è definita come: PI ( X ) = min { Pr ( X , ei )}
ei ∈ X

Nella formula, Pr ( X , ei ) rappresenta il participation ratio di un tipo di evento ei nella colocation X .

1.2 enunciato del problema

5

participation ratio In una colocation X , si definisce il participation ratio di un evento ei come il rapporto tra gli oggetti di tipo ei nelle vicinanze delle istanze di X − {ei }. In sintesi: Pr ( X , ei ) = Num. di oggetti distinti di tipo ei nelle ist. di X Numero di elementi di ei

Prendendo sempre ad esempio la Figura 1.1, è possibile vedere come l’evento B abbia tre oggetti, mentre gli eventi P ed S presentano due oggetti ciascuno. La colocation X = { B, S} ha istanze { B.1, S.1} e { B.3, S.2}. È possibile quindi calcolare i valori di Pr ( X , ei ) relativi a ciascun evento spaziale e di conseguenza il valore di PI ( X ). In particolare, per quanto riguarda l’evento B, si ha che Pr ( X , B) = 2 2 3 mentre per S si ha che Pr ( X , S ) = 2 = 1. Ne consegue che PI ( X ) = 2 min 2 3 , 1 = 3 è il corretto valore del participation index di X . Come verrà approfondito nella seguente sezione, una colocation X viene considerata frequente se il valore di PI ( X ) risulta maggiore di una determinata soglia. 1.2 enunciato del problema

Lo scopo di questa sezione è descrivere il problema del mining dei colocation pattern nella sua forma più generale, senza perciò trattare di uno specifico tipo di pattern. Nel Capitolo 2 vengono descritti i maximal colocation pattern, mentre il Capitolo 3 affronta i top-k closed colocation pattern. La definizione del condensed colocation pattern introdotto in questa tesi segue nel Capitolo 4. Il problema può essere formulato nel seguente modo [9, 11, 12]: dati 1. Un insieme di eventi spaziali E = {e1 , . . . , em } 2. Un dataset di oggetti S = S1 ∪ . . . ∪ Sm in cui Si è un insieme di oggetti con tipo di evento ei , ciascuno dei quali contiene informazioni relative al tipo di evento ei , un identificatore univoco e la posizione nello spazio 3. Una relazione di vicinanza R 4. Una soglia di prevalenza minima θ sviluppare Un algoritmo per trovare tutti i colocation pattern frequenti in modo efficiente e corretto. condizioni 1. R è una relazione simmetrica e riflessiva 2. La misura di prevalenza (participation index) è monotona

6

descrizione del problema

Un approccio naïve per la risoluzione di questo problema consiste nell’effettuare un vero e proprio processo di brute force. Innanzitutto si procede ad individuare tutte le istanze di colocation che formano delle clique secondo la relazione R. Quindi viene calcolato il valore di PI ( X ) per ogni colocation X e l’insieme dei risultati viene filtrato dagli elementi per cui PI ( X ) < θ . Un procedimento di questo tipo comporta l’analisi di circa 2m diversi insiemi di eventi, dove m = | E|. Ciò si traduce in una complessità di tipo esponenziale che rende impraticabile il mining in presenza di grandi quantità di dati. Per questo motivo sono stati sviluppati diversi algoritmi con lo scopo di rendere efficiente il mining dei pattern. La prossima sezione elenca le principali tecniche utilizzate. 1.3 strategie utilizzate in letteratura

Le numerose pubblicazioni a riguardo del mining dei colocation pattern hanno prodotto diversi algoritmi dediti a risolvere il problema usando varie strategie e ottimizzazioni, tuttavia la maggior parte di essi è basata su un principio basilare denominato proprietà della monotonicità del participation index [9]: proprietà di monotonicità Si consideri una qualsiasi colocation Y che sia sottoinsieme di una colocation X . Dalla definizione del participation index segue che: Y ⊂ X ⇒ PI (Y ) ≥ PI ( X ) Da questo deriva che se X è frequente, anche Y lo è. Tutti gli algoritmi di seguito descritto sfruttano almeno in parte la suddetta proprietà allo scopo di cercare di ridurre al minimo gli insiemi di eventi candidati che devono essere analizzati per individuare i colocation pattern frequenti. La lista non è esaustiva in quanto non comprende tutte le varianti del problema, alcune delle quali saranno discusse successivamente. Tuttavia elenca delle metodologie generali che possono essere adattate a dei possibili problemi derivati. Apriori Si tratta del primo algoritmo sviluppato per sfruttare la proprietà di monotonicità, descritto in Agrawal and Srikant [1]. Per essere precisi, l’algoritmo si occupa del mining delle association rule, ovvero regole formate da implicazioni della forma ex ⇒ ey dove ex e ey sono eventi spaziali contenuti in E. Tali regole sono supportate da un livello di confidenza. Nonostante questa differenza rispetto alle colocation, il principio di Apriori è di fondamentale importanza in quanto costituisce la base della maggior parte degli algoritmi per il mining dei colocation pattern sviluppati successivamente. In breve, la generazione

1.3 strategie utilizzate in letteratura

7

dei candidati (definiti itemset) avviene tramite un processo iterativo che inizia dagli insiemi composti da un solo elemento, raccogliendo in L1 i risultati frequenti. In ogni successiva iterazione k, il contenuto di Lk−1 viene usato come base per formare gli elementi frequenti Lk combinando elementi più piccoli. L’unione di tutti questi risultati intermedi costituisce l’insieme degli itemset frequenti. Co-location miner Questo algoritmo viene introdotto in Shekhar and Huang [9] e si applica ai colocation pattern, che vengono definiti tramite una relazione di vicinanza R invece di usare transazioni. L’algoritmo Apriori viene adattato con l’implementazione di una nuova procedura chiamata generalized apriori_gen: ciò è necessario in quanto, pur sembrando simili, il problema delle colocation è molto diverso da quello delle association rule. Joinless colocation mining La differenza di questa strategia consiste nell’assenza di operazioni di join, le quali sono dispendiose in termini di tempo di esecuzione ed è descritto in Yoo and Shekhar [12]. Il grafo degli eventi spaziali viene partizionato seguendo un modello a stella o in alternativa un modello a clique. Vengono quindi estratti dei candidati da ciascuna partizioni e vengono filtrate quelle che sono le vere colocation instance, da cui vengono derivate le colocation.

M A X I M A L C O L O C AT I O N PAT T E R N

2

Le caratteristiche dell’algoritmo Apriori descritto nel Capitolo 1 pongono delle limitazioni sulla scalabilità del suo utilizzo nell’analisi dei dati. In particolare, esso si dimostra poco adatto al mining su insiemi di dati molto grandi oppure densi. In presenza di pattern molto lunghi, la generazione ed il test di tutti i sottoinsiemi è spesso impraticabile, perciò gli algoritmi basati su Apriori possono essere vincolati a limitarsi all’analisi di pattern corti [11]. Tuttavia, i pattern lunghi si presentano molto frequentemente nei dataset densi e pertanto è necessario tenerli in considerazione. Lo sviluppo di nuove strategie ha reso possibile il mining di vari tipi di pattern. Nella seguente sezione vengono introdotti i maximal colocation pattern, che consentono di rappresentare in forma concisa tutti i colocation pattern. Successivamente viene definito formalmente il problema della loro ricerca e viene presentato in particolare l’algoritmo per effettuarne il mining descritto in Yoo and Bow [11]. 2.1 definizioni

Innanzitutto è necessario definire il tipo di pattern qui considerato: maximal colocation Si consideri una colocation X . Se X è frequente ma non esiste alcuna colocation Y tale che X ⊂ Y e Y è frequente, allora X viene definita una maximal colocation. Intuitivamente, dalla proprietà di monotonicità deriva che il maximal colocation pattern X è rappresentativo anche di tutti i suoi sottoinsiemi Z1 , . . . , Zn ⊆ X , in quanto se X è frequente, anche ogni Zi lo è. Prima di esporre l’enunciato del problema e un algoritmo per risolverlo, è opportuno introdurre anche un ulteriore concetto che verrà poi utilizzato anche nei Capitoli 3 e 4: pruning dei sottoinsiemi Durante l’elaborazione dei dati, nel caso in cui venga stabilito che una colocation X è frequente, viene meno l’interesse per i suoi sottinsiemi Z1 , . . . , Zn ⊂ X . Si supponga di avere una lista di colocation candidate da analizzare: da quanto detto si evince che è possibile eliminare dai candidati ogni sottoinsieme di X , in quanto verificarne la frequenza è superfluo. Questo processo di eliminazione dei candidati viene detto pruning. I meccanismi utilizzati per effettuare il pruning possono influire in maniera significativa sul tempo di esecuzione dell’algoritmo utilizza-

9

10

maximal colocation pattern

Figura 2.1: Pre-elaborazione e transazioni [11]

to. In particolare, conta molto il metodo per verificare rapidamente la relazione di sottoinsieme tra due colocation. Nelle sezioni seguenti verrà illustrato come l’utilizzo di opportune strutture dati permetta di ottimizzare tale processo ed eliminare i candidati superflui il prima possibile. Ciò ha lo scopo di ridurre lo spazio di ricerca. Oltre all’importanza di eliminare i sottoinsiemi in modo rapido, è di grande beneficio la possibilità di generare un insieme iniziale di potenziali colocation candidate escludendo fin dall’inizio le clique che non possono essere presenti nel grafo dei dati. Allo scopo, vengono introdotti due concetti utilizzati in Yoo and Bow [10] nonché in Yoo and Bow [11] e nell’algoritmo proposto nel Capitolo 4: neighborhood transaction Dato un oggetto oi ∈ S, si definisce neighborhood transaction l’insieme di istanze di eventi spaziali: NT (oi ) = {oi } ∪ o j ∈ S| R(oi , o j ) ∧ tipo di oi = tipo di o j Dove R è la relazione di vicinanza. event neighborhood transaction L’insieme di eventi distinti in una neighborhood transaction viene definito event neighborhood transaction. Va notato che, mentre NT (oi ) è unica per ciascun oi , ci possono essere più event neighborhood transaction che fanno riferimento ad uno stesso tipo di evento. Inoltre, tipicamente l’insieme delle event neighborhood transaction è più compatto di quello contenente le neighborhood transaction. La Figura 2.1 mostra un dataset con le neighborhood transaction e le event neighborhood transaction. Si può vedere ad esempio che l’oggetto D.2 ha una relazione di vicinanza con A.1, C.1 e E.1 e quindi NT ( D.2) = { D.2, A.1, C.1, E.1}. Per convenzione il primo elemento rappresentato nell’insieme è l’oggetto a cui si riferisce la neighborhood transaction.

2.2 enunciato del problema

11

2.2

enunciato del problema

La formulazione del problema dei maximal colocation pattern è una variante del problema descritto nel Capitolo 1: dati 1. Un insieme di eventi spaziali E = {e1 , . . . , em } 2. Un dataset di oggetti S = S1 ∪ . . . ∪ Sm in cui Si è un insieme di oggetti con tipo di evento ei , ciascuno dei quali contiene informazioni relative al tipo di evento ei , un identificatore univoco e la posizione nello spazio 3. Una relazione di vicinanza R 4. Una soglia di prevalenza minima θ sviluppare Un algoritmo per trovare tutti i maximal colocation pattern in modo efficiente e corretto. condizioni 1. R è una relazione simmetrica e riflessiva 2. La misura di prevalenza (participation index) è monotona Anche tale variante può essere risolta in modo simile con un metodo naïve. Analogamente al problema generale, è necessario individuare tutte le istanze di colocation che formano delle clique secondo la relazione R. Quindi viene calcolato il valore di PI ( X ) per ogni colocation X , si eliminano gli elementi per cui PI ( X ) < θ e i rimanenti vengono analizzati per effettuare il pruning dei sottoinsiemi. 2.3 algoritmo maxcoloc

L’algoritmo MAXColoc è stato ideato da Yoo and Bow [11] partendo dalla considerazione che la verifica di tutte le clique che avviene in Apriori sia il punto debole in merito all’efficienza e che è necessario considerare anche pattern lunghi per risolvere il problema delle maximal colocation. Il design dell’algoritmo è basato su una procedura divisa in quattro parti: pre-elaborazione, generazione dei candidati, pruning dei candidati, e filtraggio delle istanze. Di seguito vengono descritte le varie fasi riassumendo quanto illustrato nel loro paper, e successivamente viene presentato l’algoritmo in pseudo-codice. Pre-elaborazione Il primo passo consiste nel rappresentare il dataset come un grafo, i cui vertici sono gli oggetti (istanze di eventi spaziali) e gli archi

12

maximal colocation pattern

Figura 2.2: Generazione dei candidati [11]

collegano i nodi per cui vale la relazione R(oi , o j ). In seguito, si genera la neighborhood transaction per ciascun nodo e le relative event neighborhood transaction, necessarie per una generazione efficiente dei candidati. Generazione dei candidati L’idea di base per generare un insieme possibilmente ridotto di candidati è quella di evitare l’inclusione di insiemi che non possono avere una relazione di clique. Prendendo ad esempio la Figura 2.1, si nota che l’insieme di eventi { A, D, E} non costituisce una colocation in quanto le istanze di tali eventi non formano nessuna clique. Conoscendo anticipatamente i candidati da evitare, è possibile ridurre il tempo di elaborazione necessario. Per tale motivo, le neighborhood transaction vengono combinate per ricavare solo candidati che potrebbero formare clique. L’algoritmo impiega una struttura dati derivante dall’FP-Tree e utilizza l’algoritmo FP-Growth [3]. L’FP-Tree è una struttura dati che viene costruita per ogni tipo di evento ei ∈ E e rappresenta in forma compatta le event neighborhood transaction che hanno ei come riferimento. In Figura 2.2 è possibile vedere gli FP-Tree generati per ciascun tipo di evento. Ogni nodo dell’albero contiene tre informazioni: tipo di evento, conteggio e node-link. Il conteggio è determinato dal numero di event neighborhood transaction che attraversano il nodo, scendendo a partire dalla radice. Il node-link è un puntatore che fa riferimento al prossimo nodo dell’albero con il medesimo tipo di evento.

2.3 algoritmo maxcoloc

13

Figura 2.3: Pruning dei sottoinsiemi in MAXColoc [11]

Questo tipo di FP-Tree riferito ad un tipo di evento viene definito dagli autori il candidate pattern tree dell’evento. Gli insiemi di eventi con una soglia di supporto minimo vengono generati utilizzando l’algoritmo FP-Growth [3] e i risultati vengono definiti star candidate. Le istanze di star candidate presenti nell’insieme delle neighborhood transactions sono dette star instance. FPGrowth fornisce come output anche un valore di supporto per i risultati, il quale rappresenta un limite superiore del participation index della possibile clique. Va notato che gli star candidate non sono necessariamente candidati di colocation, in quanto bisogna prima verificare che possa sussistere effettivamente una relazione di clique tra tutti gli elementi dell’insieme. Ad esempio, l’insieme { A, B, C } può essere una colocation soltanto nel caso in cui tra gli star candidate compaiano { A, B, C }, { B, A, C } e anche {C, A, B}. In questo caso si dice che { A, B, C } costituisce un clique candidate. Pruning dei candidati Per effettuare il pruning, si suppone che gli elementi di E possano essere ordinati secondo un ordinamento totale ≥ L (per esempio l’ordine lessicografico). Viene costruito un albero dei sottoinsiemi, nel quale gli elementi di dimensione k sono ordinati, come mostrato in Figura 2.3. Di ciascun nodo si individuano la testa (rappresentata dal tipo di evento) e la coda (rappresentata dal tipo dei figli). Per esempio, il nodo Y ha testa A e coda { B, C, D, E} e l’unione di questi elementi viene definita HUT [11]. Nel caso specifico HUT (Y ) = { A, B, C, D, E}. L’albero viene attraversato in due diversi modi: l’approccio depthfirst serve ad identificare rapidamente i candidati di lunghezza maggiore, mentre l’approccio breadth-first è utilizzato per effettuare il pruning. Una volta individuata una maximal colocation X , ogni nodo n dell’albero viene valutato. Se HUT (n) ⊆ X , l’albero di radice n viene eliminato.

14

maximal colocation pattern

nome E = { e1 , . . . , e m } S R θ

descrizione Insieme di tipi di eventi spaziali Dataset di eventi spaziali Relazione di vicinanza Soglia di prevalenza minima

Tabella 2.1: Variabili di input per MAXColoc

Codice dell’algoritmo L’Algoritmo 2.1 riporta lo pseudo-codice di MAXColoc [11]. Rispetto alla versione originale ci sono delle lievi differenze: la condizione del ciclo while riporta solo k ≥ 2, in quanto indicare anche C = ∅ risulta ridondante. Inoltre la funzione find_clique_instances prende come input SIc invece di SIk . Algoritmo 2.1 MAXColoc 1: NP = find_neighbor_pairs(S, R) 2: ( NT , ENT ) = gen_neighbor_transactions( NP) 3: for i = 1 to m do 4: Ti = build_candidate_pattern_tree(ei , ENT , θ ) 5: C = gen_candidates( T1 , . . . , Tm ) 6: k = find_longest_size(C) 7: while k ≥ 2 do 8: Ck = get_k_candidates(C, k) 9: SIk = find_star_instances(Ck , NT ) 10: for each candidate c ∈ Ck do 11: CIc = find_clique_instances(SIc , c, NP) 12: pic = calcute_pi(CIc ) 13: if pic > θ then 14: insert(c, Rk ) 15: R = R ∪ Rk 16: C = C − Ck 17: C = subset_pruning( Rk , C) 18: k = k−1 19: return R La Tabella 2.1 indica il significato delle variabili di input, mentre in Tabella 2.2 è contenuto l’elenco di tutti i simboli utilizzati. Le principali parti dell’algoritmo sono così suddivise [11]: pre - elaborazione ( righe 1 – 2 ) Il dataset viene convertito in un grafo verificando la relazione R tra le coppie di punti. Questo può avvenire in diversi modi, a seconda del tipo di distanza utilizzata. Le neighborhood transaction vengono generate raggruppando i vicini di ciascun nodo.

2.3 algoritmo maxcoloc

15

nome NT ENT NP Ti k C Ck pi CIc SIc SIk R Rk

descrizione Insieme di neighborhood transaction Insieme di event neighborhood transaction Insieme di tutte le coppie di nodi vicini Candidate pattern tree dell’evento ei Dimensione dei candidati considerati Insieme di tutti i candidati Insieme dei candidati di dimensione k Participation index Insieme delle istanze di clique di c Insieme delle star instance di c Insieme di tutti gli SIc per cui |c| = k Insieme di maximal colocation pattern Insieme di maximal colocation pattern di dimensione k
Tabella 2.2: Simboli utilizzati in MAXColoc

generazione dei candidati ( righe 3 – 5 ) Si costruisce un candidate pattern tree per ogni tipo di evento, e gli star candidate vengono estratti usando FP-Growth. Successivamente, vengono combinati per ottenere i clique candidate. selezione dei candidati di dim . k ( righe 6 – 8 ) Il processo di mining inizia dal valore massimo di k e prosegue fino ai candidati di dimensione 2. Vengono quindi estratti i candidati di lunghezza k . individuazione delle star instance ( riga 9 ) Tutte le neighborhood transaction vengono suddivise in gruppi e vengono estratte le star instance. Esse vengono inserite nel relativo insieme S I c , in cui ogni c è un elemento di C k . L’insieme contenente tutti gli S I c del passo k è S I k . filtraggio delle clique ( righe 10 – 14 ) Tutte le relazioni tra i nodi interessati vengono esaminate per filtrare solo le effettive clique. Ne viene quindi calcolato il valore del participation index e vengono inserite nell’insieme R k . aggiornamento e pruning ( righe 15 – 17 ) L’insieme dei risultati viene aggiornato e viene effettuato il pruning dei sottoinsiemi con la tecnica dell’ H U T . insieme dei risultati finale ( riga 19 ) Il processo viene iterato fino a che k non raggiunge 2 o l’insieme C risulta vuoto. Infine viene restituito l’insieme R dei risultati.

T O P - k C L O S E D C O L O C AT I O N PAT T E R N

3

La maggior parte degli algoritmi di mining dei colocation pattern richiede che l’utente specifichi in input una soglia minima θ per indicare i pattern desiderati. Tuttavia, è spesso difficile decidere anticipatamente la soglia di prevalenza minima senza una precedente conoscenza delle caratteristiche del dataset da analizzare [10]. Questo motivo si aggiunge a quanto precedentemente discusso nel Capitolo 2 come ulteriore ragione per sviluppare alternative ad Apriori. In questo capitolo viene introdotto il concetto di closed colocation ed è descritto il processo di mining dei k pattern maggiormente prevalenti. Infine viene illustrato l’algoritmo per il mining presentato in Yoo and Bow [10]. 3.1 definizioni

Di seguito verrà considerato il tipo di pattern così definito: closed colocation Una colocation X è definita closed colocation se non esiste alcun sovrainsieme Y ⊃ X con lo stesso livello di supporto, vale a dire P I ( Y ) = P I ( X ) .
2 2 Ad esempio, se P I ( { A , B } ) = 3 e P I ({ A, B, C}) = 3 risulta che { A , B } non è una closed colocation ma { A , B , C } potrebbe esserlo, nel caso in cui rispettasse la definizione. Da ciò ne deriva che una closed colocation X è rappresentativa dei suoi sottoinsiemi Z 1 , . . . , Z n ⊆ X e inoltre la sua misura di supporto fornisce un limite inferiore al supporto di ogni Z i . Volendo escludere la soglia minima θ dai dati di input, è necessario definire l’insieme dei pattern di interesse. In particolare, viene introdotto il parametro k che indica la quantità di closed colocation da considerare:

top - k closed colocation Sia L la lista di tutte le closed colocation, ordinate in modo decrescente secondo il loro participation index. L’insieme delle top- k closed colocation è definito come: { X 1 , . . . , X k }. La definizione qui riportata è differente da quella presentata in Yoo and Bow [10], che si basa sul considerare tutte le closed colocation X i tali che P I ( X i ) ≥ P I ( X k ) . In questo caso infatti l’insieme considerato potrebbe contenere un numero di elementi maggiore di k in alcune circostanze. Tuttavia l’algoritmo di seguito presentato estrae sempre al massimo k closed colocation.

17

18

top - k closed colocation pattern

3.2

enunciato del problema

Anche la formulazione del mining dei top- k closed colocation pattern rappresenta una variante del problema descritto nel Capitolo 1: dati 1. Un insieme di eventi spaziali E = {e1 , . . . , em } a) Un dataset di oggetti S = S1 ∪ . . . ∪ Sm in cui Si è un insieme di oggetti con tipo di evento ei , ciascuno dei quali contiene informazioni relative al tipo di evento ei , un identificatore univoco e la posizione nello spazio b) Una relazione di vicinanza R c) Un numero k di pattern desiderati sviluppare Un algoritmo per trovare i top-k closed colocation pattern in modo efficiente e corretto. condizioni 1. R è una relazione simmetrica e riflessiva 2. La misura di prevalenza (participation index) è monotona L’approccio naïve in questo caso consiste inizialmente nel trovare tutte le istanze di colocation formanti delle clique secondo R e calcolarne il participation index. Quindi è necessario trovare tutte le closed colocation, ordinarle in modo decrescente a seconda del loro supporto ed infine restituire i primi k elementi della lista. 3.3 algoritmo topkcoloc

L’algoritmo TopKColoc è stato introdotto in Yoo and Bow [10]. Oltre alle considerazioni sui punti di debolezza di Apriori discusse nella Sezione 2.3, un’altra differenza rispetto ad altri algoritmi di mining è la mancanza di una soglia minima di supporto θ , in quanto il parametro di input è invece il numero k di pattern richiesti. In questa sezione vengono descritti gli aspetti principali dell’algoritmo TopKColoc, riassumendo il contenuto del paper originale: preelaborazione, generazione dei candidati, mantenimento della soglia minima, riutilizzo delle istanze e ricerca dei sottoinsiemi. Successivamente viene mostrato e commentato lo pseudo-codice dell’algoritmo. Pre-elaborazione Questa fase risulta del tutto analoga a quanto descritto nella Sezione 2.3, riguardante l’algoritmo MAXColoc.

3.3 algoritmo topkcoloc

19

Figura 3.1: Pruning dei candidati in TopKColoc [10]

Generazione dei candidati Anche TopKColoc utilizza una struttura derivante dall’FP-Tree e l’algoritmo FP-Growth [3]. La principale differenza rispetto a quanto illustrato nella Sezione 2.3 è che in questo caso non viene utilizzata alcuna soglia di supporto minimo nella generazione dei candidati: tutte le transazioni vengono usate per creare l’albero. Anche in questo caso i risultati sono corredati da un limite superiore di supporto, il quale viene definito upper participation index. Mantenimento della soglia minima Nonostante la mancanza di una soglia in input, è possibile utilizzare un accorgimento per ridurre il numero di candidati analizzati. I candidati vengono inseriti in un albero detto candidate subset tree, in modo simile a quanto descritto nella Sezione 2.3 per il processo di pruning. Nell’albero è importante che ogni nodo contenga anche il valore dell’upper participation index della colocation relativa al percorso dalla radice al nodo stesso. Anche nel caso in cui l’insieme dei risultati sia pieno, è necessario verificare se le k colocation sono closed colocation oppure no, perché in caso contrario altre colocation potrebbero essere inserite nei risultati. In questo caso torna utile mantenere un valore interno θ impostato al participation index del k-esimo risultato. Nel caso in cui il candidato successivo avesse un upper participation index inferiore, sarebbe completamente inutile valutarne l’inserimento. Inoltre, è possibile eliminare anche i sovrainsiemi di tale candidato in base alla proprietà di monotonicità. Il valore di θ viene perciò utilizzato per eliminare i sottoalberi la cui radice abbia un upper participation index inferiore alla soglia. Questo meccanismo è visibile in Figura 3.1 e consente di ridurre in modo significativo i candidati che è necessario analizzare. Riutilizzo delle istanze L’algoritmo attraversa il candidate subset tree un livello alla volta, a partire da l = 2, utilizzando lo schema di pruning e cercando le

20

top - k closed colocation pattern

nome E = { e1 , . . . , e m } S d k

descrizione Insieme di tipi di eventi spaziali Dataset di eventi spaziali Relazione di vicinanza Numero di closed colocation richieste

Tabella 3.1: Variabili di input per TopKColoc

istanze di clique. Una volta trovate delle star instance, è necessario verificare che si tratti effettivamente di clique. Questo può essere effettuato nel modo descritto nella Sezione 2.3, tuttavia il processo può essere ottimizzato. Ciò è possibile in quanto al passo l sono già note le clique del livello l − 1 le quali possono essere riutilizzate per verificare se la coda di una star instance fosse anche una colocation instance. Ricerca dei sottoinsiemi Se una colocation X possiede un participation index PI ( X ) > θ è possibile inserirla all’interno della lista dei risultati. Nel fare ciò è necessario verificare se sono già presenti dei sottoinsiemi di X con lo stesso participation index, e in tal caso essi devono essere rimossi. Al fine di evitare di allungare inutilmente il tempo di elaborazione, la relazione di sottoinsieme viene verificata solo per i risultati il cui participation index sia effettivamente uguale a quello di X . Codice dell’algoritmo L’Algoritmo 3.1 riporta lo pseudo-codice di TopKColoc [10]. Il codice è stato leggermente modificato: alla riga 23 è stato inserito un break, al contrario di continue per ovviare ad una contraddizione con la descrizione testuale dello pseudo-codice. A ciò si aggiunge il fatto che la funzione filter_clique_instances è stata utilizzata includendo CIl −1 nella firma, in modo da enfatizzare l’ottimizzazione riguardo al riutilizzo delle istanze. La Tabella 3.1 indica il significato delle variabili di input, mentre in Tabella 3.2 è contenuto l’elenco di tutti i simboli utilizzati. Le principali parti dell’algoritmo sono così suddivise [10]: pre - elaborazione ( righe 1 – 2 ) Il dataset viene convertito in un grafo verificando la relazione R, in modo analogo a quanto fatto per MAXColoc nella Sezione 2.3. generazione dei candidati ( righe 3 – 6 ) Si costruisce un candidate pattern tree per ogni tipo di evento, e gli star candidate

3.3 algoritmo topkcoloc

21

Algoritmo 3.1 TopKColoc 1: NP = find_neighbor_pairs(S, d) 2: ( NT , ENT ) = gen_neighbor_transactions( NP) 3: for i = 1 to m do 4: Ti = build_candidate_pattern_tree(ei , ENT ) 5: C = gen_candidates( T1 , . . . , Tm ) 6: calculate_upper_pi(C) 7: R = ∅ 8: l = 2 9: θ = 0 10: while Cl = ∅ do 11: Cl = sort_by_upper_pi(Cl ) 12: if | R| = k then 13: prune_candidates(C, l , θ ) 14: if Cl = ∅ then 15: break 16: SIl = find_star_instances(Cl , NT ) 17: CIl = ∅ 18: for all c ∈ Cl do 19: if | R| = k ∧ c.upper_pi < θ then 20: prune_candidates(C, l , θ ) 21: break 22: if l > 2 then 23: CIc = filter_clique_instances(SIc , CIl −1 ) 24: else 25: CIc = SIc 26: pi = calculate_true_pi(CIc ) 27: if | R| < k then 28: subsets = find_sub_closed( R, c, pi) 29: if subsets = ∅ then 30: insert(c, pi, R) 31: else 32: replace( R, subsets, c, pi) 33: else 34: if θ < pi then 35: subsets = find_sub_closed( R, c, pi) 36: if subsets = ∅ then 37: replace( R, R.last, c, pi) 38: else 39: replace( R, subsets, c, pi) 40: θ = R.last.pi 41: CIl = CIl ∪ CIc 42: l = l+1 43: return R

22

top - k closed colocation pattern

nome NT ENT NP Ti l θ C Cl c.upper_pi pi CIc CIl SIc SIl subsets R R.last

descrizione Insieme di neighborhood transaction Insieme di event neighborhood transaction Insieme di tutte le coppie di nodi vicini Candidate pattern tree dell’evento ei Lunghezza delle colocation Soglia minima interna Insieme di tutti i candidati Insieme dei candidati di dimensione k Approssimazione del participation index di c Vero participation index Insieme delle istanze di clique di c Insieme delle istanze di clique di dimensione l Insieme delle star instance di c Insieme di tutti gli SIc per cui |c| = l Insieme di sottoinsiemi closed di un candidato Insieme di top-k closed colocation pattern Ultimo risultato presente in R
Tabella 3.2: Simboli utilizzati in TopKColoc

sono estratti usando FP-Growth, senza utilizzare una soglia minima. Infine i risultati estratti vengono combinati per ottenere i clique candidate. Viene calcolato l’upper participation index di ciascuno di essi. scelta dei candidati di dim . l ( righe 7 – 15 ) Il mining ha inizio da l = 2 e la soglia interna θ viene impostata a 0. Se l’insieme R è pieno, viene avviata una procedura di pruning prima del mining al passo l . Se un candidato possiede un upper participation index maggiore di θ , tutti i suoi sottoinsiemi vengono eliminati dall’insieme C l . raccolta delle star instance ( riga 16 ) Le istanze candidate vengono estratte dall’insieme delle neighborhood transaction. verifica della terminazione ( righe 18 – 21 ) Se l’insieme R è pieno durante l’elaborazione del passo l , i candidati rimanenti subiscono una verifica dell’upper participation index. Se uno di essi presenta un valore inferiore a θ , i rimanenti vengono eliminati e l’esecuzione salta al passo l + 1. filtraggio delle clique ( righe 22 – 26 ) Le vere clique vengono filtrate e si procede al calcolo del loro participation index.

3.3 algoritmo topkcoloc

23

aggiornamento dei risultati ( righe 27 – 40 ) La modalità di aggiornamento dipende da R : se non è pieno, la colocation viene inserita, sostituendo eventuali sottoinsiemi con lo stesso participation index. Se invece R è pieno, la colocation viene inserita soltanto se ha un supporto maggiore di R .last, sostituendo gli eventuali sottoinsiemi oppure R .last stesso. Il valore di θ viene quindi aggiornato. insieme dei risultati finale ( riga 43 ) Il processo viene iterato fino a che non viene raggiunto un valore di l per cui Cl = ∅. Infine viene restituito l’insieme R dei risultati.

Parte II IL NUOVO ALGORITMO

C O N D E N S E D C O L O C AT I O N PAT T E R N

4

Nella Parte i è stato illustrato il mining dei colocation pattern da diversi punti di vista e tramite varie strategie. In particolare, nei Capitoli 2 e 3 la trattazione ha riguardato due varianti del problema aventi lo scopo di ridurre l’insieme dei pattern risultanti. Questo avviene considerando soltanto determinate colocation scelte specificamente per essere rappresentative anche dei loro sottoinsiemi. Nonostante queste soluzioni riescano a ridurre l’insieme dei risultati, entrambe sono comunque basate su una misura esatta del valore del supporto. Nella pratica, accade molto spesso che esistano colocation con minime differenze negli elementi e nel participation index. In questo caso, può essere sufficiente o preferibile esaminare un’approssimazione della frequenza, invece di un valore esatto [8]. Tale scelta può consentire l’eliminazione di diversi pattern ridondanti, permettendo di ottenere una lista di risultati più compatti. Nelle seguenti sezioni viene introdotta una nuova tipologia di pattern che consente una approssimazione controllata del participation index. Il problema del loro mining è presentato formalmente ed infine è descritto l’algoritmo che è stato sviluppato per risolverlo. Il Capitolo 5 è invece dedicato all’analisi dei test effettuati su alcuni dataset e il Capitolo 6 contiene le conclusioni. 4.1 un nuovo tipo di colocation pattern

L’idea di effettuare il mining di colocation con una misura di supporto approssimata è in parte basata sul lavoro di Pei et al. [8]. In tale articolo gli autori si occupano dell’estrazione di pattern frequenti dai database transazionali e forniscono alcune possibilità per la definizione di una frequenza approssimata dei pattern. Tuttavia, il problema del mining dei colocation pattern è diverso dal precedente, a partire dal fatto che la misura di supporto viene definita tramite il participation index. Lo scopo di questa tesi è di definire il concetto di supporto approssimato per i colocation pattern e fornire un algoritmo che ne permetta il mining. Prima di illustrare le nuove definizioni, è opportuno utilizzare un esempio, al fine di comprendere le motivazioni per cui è desiderabile approssimare il supporto. Si supponga di dover analizzare un dataset spaziale dal quale estrarre i colocation pattern maggiormente frequenti e che due colocation siano X = { A, B, C } con PI ( X ) = 30% e Y = { A, B, C, E} con PI (Y ) = 28.7%. I participation index sono qui indicati sotto forma percentua-

27

28

condensed colocation pattern

le. Molto spesso l’analista è interessato al significato dei dati e alle prevalenze che ne derivano, piuttosto che al calcolo del supporto con precisione estrema. In questo caso, se ad esempio si tollera un errore entro il 2%, risulta evidente che X può essere scartata dai risultati, in quanto essa è rappresentata da Y . È possibile quindi definire il tipo di pattern trattato: condensed colocation pattern Un condensed colocation pattern P è un insieme rappresentato da una colocation X e include anche alcuni sottoinsiemi di X . In esso si individua un intervallo di frequenza delimitato da estremi denominati PIlb e PIub . In particolare i sottoinsiemi Zi ⊆ X da considerarsi nel contesto del pattern P rispettano le seguenti condizioni: 1. Zi ∈ P ⇒ PI ( Zi ) ≤ PI ( X ) + δ 2. PI ( Zi ) > PI ( X ) ∧ Zi ∈ / P ⇒ ∃ Q| Zi ∈ Q 3. ∀ Zi ∈ P [ PIlb ≤ PI ( Zi ) ≤ PIub ], in particolare poniamo: a) PIlb = min { PI ( Zi )| Zi ∈ P} = PI ( X ) b) PIub = max { PI ( Zi )| Zi ∈ P} Dove δ è la massima approssimazione consentita e Q è un condensed colocation pattern. Dalla definizione deriva immediatamente che se Zi ⊂ X non fa parte del condensed colocation pattern P rappresentato da X , esso sarà incluso in un altro condensed colocation pattern Q. È facilmente verificabile dalla proprietà di monotonia del participation index che si avrà P. PIub < Q. PIub . L’utilizzo di questo intervallo ci consente di derivare informazioni approssimate sulla frequenza delle colocation a partire dai pattern trovati. Supponiamo ad esempio che il processo di mining con δ = 2% produca tra i risultati il pattern { A, B, C, E} [28.7%, 30%] e si desidera ricavare la frequenza della colocation W = { A, B, E}. Ci sono due casi mutualmente esclusivi: 1. 28.7% ≤ PI (W ) ≤ 30% e possiamo stimare il participation index di W entro la tolleranza prefissata 2. W appare come sottoinsieme di un altro pattern nel dataset1 , il quale ha un valore di PIub maggiore Da quanto mostrato deriva che estraendo i condensed colocation pattern si ottiene una rappresentazione compatta delle colocation frequenti. Inoltre, per avere una stima del participation index di W è sufficiente trovare il pattern con il valore di PIub maggiore tra tutti
1 Per semplicità si parla di W come un sottoinsieme del pattern P, tuttavia sarebbe formalmente più preciso specificare che si parla dell’eventuale relazione tra W e la colocation X ; la quale rappresenta il pattern P.

4.2 enunciato del problema

29

{ A, B} [50%] { A, B, C } [48%]

{ A, B, C, D } [46%] { A, B, C, D, E} [44%]

(a) Elenco delle closed colocation

{ A, B, C, D } [46%, 50%] { A, B, C, D, E} [44%, 44%]
(b) Partizionamento dall’alto

{ A, B} [50%, 50%] { A, B, C, D, E} [44%, 48%]
(c) Partizionamento dal basso

Figura 4.1: Esempio di partizionamento non univoco

quelli di cui W è sottoinsieme. La seguente sezione descrive il problema del mining e della suddivisione delle colocation in condensed colocation pattern, secondo la definizione precedentemente data. 4.2 enunciato del problema

Per quanto riguarda il processo di mining e partizionamento delle colocation in condensed colocation pattern, si verifica facilmente che la scelta della metodologia di suddivisione non è univoca [8]. Si prenda ad esempio in considerazione un dataset le cui colocation sono indicate in Figura 4.1a, assieme al relativo supporto. Per semplicità sono mostrate solo le closed colocation, senza indicare tutti i sottoinsiemi con il medesimo supporto. Le Figure 4.1b e 4.1c mostrano due possibili partizionamenti del dataset con δ = 5%, i quali si possono definire rispettivamente dall’alto e dal basso. Intuitivamente, è possibile osservare come la suddivisione cambi a seconda di quali colocation vengono considerate per prime, perciò ce n’è può essere più di una. Il partizionamento dall’alto viene effettuato considerando prima le colocation di dimensione inferiore e successivamente estendendo i condensed colocation pattern assimilando i sovrainsiemi che rientrano nella misura di approssimazione consentita. Nel prosieguo della trattazione verrà considerato questo tipo di partizionamento. Tale scelta ha un vantaggio costruttivo in quanto permette di usare un algoritmo simile a TopKColoc, presentato nel Capitolo 3. Inoltre, il partizionamento dall’alto permette anche di ottenere una migliore approssimazione del participation index delle colocation con frequenza maggiore, come è possibile vedere nell’esempio. Questo consente di effettuare una scelta simile a quella del mining dei top-k colocation pattern: permettere all’utente di indicare il numero desiderato di pattern, senza specificare una soglia di supporto minimo che in determinati contesti può essere difficile da prevedere. È opportuno quindi definire un concetto analogo per i condensed colocation pattern:

30

condensed colocation pattern

top - k condensed colocation pattern Sia L la lista di tutti i closed colocation pattern selezionati partizionando le colocation dall’alto. Inoltre, si richiede che L sia ordinata in modo decrescente secondo il valore di PIub . L’insieme dei top-k condensed colocation pattern è definito come: { X1 , . . . , Xk }. La differenza importante tra le top-k closed colocation e i top-k condensed colocation pattern riguarda la rappresentatività dei risultati. Infatti, mentre nel caso delle closed colocation si ha una corrispondenza uno-a-uno tra risultato e closed colocation, un condensed colocation pattern potrebbe essere rappresentativo di più di una closed colocation considerata secondo le definizioni date nel Capitolo 3. Inoltre in generale un condensed colocation pattern ha la possibilità di aggregare un maggior numero di colocation. Questo deriva dal fatto che si tollera un margine di errore nel valore del participation index. Il problema di mining qui considerato può essere formalizzato nel seguente modo: dati 1. Un insieme di eventi spaziali E = {e1 , . . . , em } a) Un dataset di oggetti S = S1 ∪ . . . ∪ Sm in cui Si è un insieme di oggetti con tipo di evento ei , ciascuno dei quali contiene informazioni relative al tipo di evento ei , un identificatore univoco e la posizione nello spazio b) Una relazione di vicinanza R c) Un numero k di pattern desiderati d) Un valore δ rappresentante l’errore massimo sul participation index sviluppare Un algoritmo per trovare i top-k condensed colocation pattern in modo efficiente e corretto. condizioni 1. R è una relazione simmetrica e riflessiva 2. La misura di prevalenza (participation index) è monotona Il problema può essere risolto in modo naïve trovando tutte le istanze di colocation formanti clique e calcolandone il participation index. Successivamente è necessario filtrare i risultati individuando i condensed colocation pattern partendo dai risultati di dimensione minima. Infine i pattern vanno ordinati secondo PIub e i primi k vengono prodotti come output.

4.3 algoritmo e caratteristiche delle soluzioni

31

4.3

algoritmo e caratteristiche delle soluzioni

L’algoritmo qui presentato, chiamato TopKCondensed, è una variante di TopKColoc, il quale è stato presentato nel Capitolo 3. Oltre al parametro k rappresentante il numero di condensed colocation pattern richiesti, l’adattamento necessita anche del parametro δ. Quest’ultimo rappresenta la tolleranza massima che può essere accettata nell’effettuare l’accorpamento delle colocation. Le fasi principali dell’algoritmo sono le stesse di TopKColoc: preelaborazione, generazione dei candidati, mantenimento della soglia minima, riutilizzo delle istanze e ricerca dei sottoinsiemi. Pre-elaborazione Questa fase risulta del tutto analoga a quanto descritto nella Sezione 2.3, riguardante l’algoritmo MAXColoc. Generazione dei candidati La fase di generazione dei candidati è invece totalmente affine alla propria corrispettiva in TopKColoc, come descritta nella Sezione 3.3. Mantenimento della soglia minima Il valore interno della soglia minima θ richiede una gestione più accurata: è necessario infatti considerare che i pattern contenuti nella lista dei risultati sono forniti di due valori limitanti l’intervallo di supporto, ovvero [ PIlb , PIub ]. Per questo motivo, effettuare il pruning in modo non accurato può portare all’eliminazione di candidati che potrebbero invece essere inseriti in qualche pattern. Chiamando R.last l’ultimo elemento della lista dei risultati, in TopKCondensed alla fine della valutazione di ciascun candidato si imposta θ = R.last. PIub − δ e il pruning viene effettuato rispetto alle colocation X con PI ( X ) < θ . In alcuni casi è possibile introdurre un’ottimizzazione che permette il pruning di un numero maggiore di candidati, come sarà possibile vedere nello pseudo-codice presentato successivamente nella trattazione. Riutilizzo delle istanze Anche TopKCondensed utilizza le informazioni acquisite al livello l − 1 per verificare rapidamente le clique di livello l , similmente a quanto mostrato per TopKColoc nella Sezione 3.3.

32

condensed colocation pattern

nome E = { e1 , . . . , e m } S d δ k

descrizione Insieme di tipi di eventi spaziali Dataset di eventi spaziali Relazione di vicinanza Massima tolleranza sul participation index Numero di closed colocation richieste

Tabella 4.1: Variabili di input per TopKCondensed

Ricerca dei sottoinsiemi Riguardo alla ricerca dei sottoinsiemi di un candidato X da inserire, non devono essere considerati soltanto i candidati con lo stesso participation index. Nel caso di TopKCondensed è necessario verificare ogni risultato Yi per cui X . PIub − δ ≤ PI (Yi ) ≤ X . PIlb , dove la parte destra della disuguaglianza deriva dalla proprietà di monotonicità. Va notato che nel caso in cui δ = 0 si ottiene: Yi . PIub − 0 ≤ PI ( X ) ≤ Yi . PIlb ⇒ Yi . PIub ≤ PI ( X ) ≤ Yi . PIlb

(def. → Yi . PIub ≥ Yi . PIlb ) ⇒ Yi . PIlb ≤ PI ( X ) ≤ Yi . PIlb ⇒ PI ( X ) = Yi . PIlb
Dato che il pattern Yi rappresentato da W ha una tolleranza pari a zero, ne deriva che PI (W ) = Yi . PIlb = Yi . PIub . Questa è esattamente la condizione esaminata da TopKColoc. Quindi se δ = 0 l’algoritmo TopKCondensed è equivalente a TopKColoc. Codice dell’algoritmo L’Algoritmo 4.1 riporta lo pseudo-codice di TopKCondensed, mentre la Tabella 4.1 indica il significato delle variabili di input. I simboli utilizzati nel codice sono essenzialmente gli stessi di TopKColoc, come indicati nella Tabella 3.2. Le principali parti dell’algoritmo presentano numerose analogie con quanto discusso nel Capitolo 3, tuttavia ci sono alcune fondamentali differenze: pruning ( righe 13 – 16 e 23 – 26 ) Come è stato descritto in precedenza, normalmente il pruning dei candidati riguardarebbe le colocation X con PI ( X ) < θ . Tuttavia, nel caso in cui l’elemento R.last abbia lunghezza pari a l , è impossibile che sia un sottoinsieme della colocation c. Per tale motivo, e grazie al fatto che le colocation sono valutate in ordine decrescente secondo il participation index, è possibile effettuare un pruning con so-

4.3 algoritmo e caratteristiche delle soluzioni

33

Algoritmo 4.1 TopKCondensed 1: NP = find_neighbor_pairs(S, d) 2: ( NT , ENT ) = gen_neighbor_transactions( NP) 3: for i = 1 to m do 4: Ti = build_candidate_pattern_tree(ei , ENT ) 5: C = gen_candidates( T1 , . . . , Tm ) 6: calculate_upper_pi(C) 7: R = ∅ 8: l = 2 9: θ = 0 10: while Cl = ∅ do 11: Cl = sort_by_upper_pi(Cl ) 12: if | R| = k then 13: if R.last.size < l then 14: prune_candidates(C, l , θ ) 15: else 16: prune_candidates(C, l , R.last. PIlb ) 17: if Cl = ∅ then 18: break 19: SIl = find_star_instances(Cl , NT ) 20: CIl = ∅ 21: for all c ∈ Cl do 22: if | R| = k ∧ c.upper_pi < θ then 23: if R.last.size < l then 24: prune_candidates(C, l , θ ) 25: else 26: prune_candidates(C, l , R.last. PIlb ) 27: break 28: if l > 2 then 29: CIc = filter_clique_instances(SIc , CIl −1 ) 30: else 31: CIc = SIc 32: pi = calculate_true_pi(CIc ) 33: if | R| < k then 34: subsets = find_sub_closed( R, c, pi, δ) 35: if subsets = ∅ then 36: insert(c, pi, R) 37: else 38: replace( R, subsets, c, pi) 39: else 40: if θ < pi then 41: subsets = find_sub_closed( R, c, pi, δ) 42: if subsets = ∅ then 43: replace( R, R.last, c, pi) 44: else 45: replace( R, subsets, c, pi) 46: θ = R.last. PIub − δ 47: CIl = CIl ∪ CIc 48: l = l+1 49: return R

34

condensed colocation pattern

glia R.last. PIlb ≥ θ . Questa operazione comporta una potenziale riduzione dei candidati da valutare. ricerca dei sottoinsiemi ( righe 34 e 41 ) È necessario utilizzare anche il valore di δ nella chiamata alla funzione. aggiornamento della soglia ( riga 46 ) Anche in questo caso si tiene conto della tolleranza massima. Soluzioni prodotte L’output prodotto dall’esecuzione di TopKCondensed è formato da una lista R dei top-k closed colocation pattern presenti nel dataset. Tali pattern sono ordinati in modo decrescente secondo il valore del rispettivo PIub . Per ogni pattern viene visualizzata la colocation che lo rappresenta e l’intervallo di frequenza [ PIlb , PIub ]. La rappresentazione dei k pattern non consente soltanto di stimare il supporto delle colocation rappresentative, bensì permette anche di ottenere informazioni sulla frequenza di qualsiasi sottoinsieme di tali colocation. Per calcolare approssimativamente il participation index di una colocation X , è sufficiente trovare il minimo indice i per cui X ⊆ Yi ∈ R. Si avrà che Yi . PIlb ≤ PI ( X ) ≤ Yi . PIub con 1 ≤ i ≤ k. 4.4 vantaggi attesi

In base alla definizione di condensed colocation pattern data nella Sezione 4.1, è atteso che l’insieme dei risultati prodotti da TopKCondensed sia maggiormente compatto e rappresentativo rispetto all’esecuzione di TopKColoc. Con ciò si intende che a parità di k, la tolleranza δ permette di ottenere una lista più significativa di pattern, i quali contengono informazioni su un numero maggiore di colocation. Inoltre, l’approssimazione consente l’eliminazione di pattern sostanzialmente ridondanti. Tale effetto aumenta con l’aumentare di δ, ovvero riducendo la precisione. Per quanto riguarda l’algoritmo MAXColoc, ci si aspetta che TopKCondensed fornisca informazioni sulle stesse colocation in modo più preciso, in particolare in riferimento al valore del supporto. Questo perché l’algoritmo qui proposto garantisce un tasso d’errore massimo nella misurazione del participation index, mentre MAXColoc consente solo di ottenerne un limite inferiore.

A N A L I S I D E I R I S U LTAT I

5

Per effettuare delle verifiche qualitative sulla precisione dei dati estratti tramite l’algoritmo TopKCondensed sono stati effettuati alcuni test, i quali sono descritti in questo capitolo. L’osservazione dei rispettivi risultati consente di apprezzare le differenze tra l’algoritmo proposto e rispettivamente MAXColoc e TopKColoc. Oltre a ciò, la lettura dei risultati permette di verificare sperimentalmente i vantaggi teorici attesi descritti nel Capitolo 4 e poggia le basi per le conclusioni illustrate nel Capitolo 6. 5.1 descrizione dei test

Gli algoritmi MAXColoc, TopKColoc e TopKCondensed sono stati implementati utilizzando il linguaggio C++ e sono stati eseguiti su un sistema Linux con 4gb di memoria RAM e processore con frequenza di 1 . 60ghz . La strutturazione dei grafi è stata in parte basata sui principi contenuti in Li and Kiran [6], e alcuni esempi significativi di codice sorgente sono presentati nell’Appendice A. Per quanto riguarda i dati utilizzati, sono stati considerati i punti di interesse della California [5], contenente 62 tipi di eventi e 103863 nodi. A partire dal dataset iniziale, sono stati prodotti sei dataset differenti D1 , . . . , D6 aventi ciascuno 60 tipi di eventi e 24000 nodi. Una rappresentazione esemplificativa degli elementi contenuti in D1 è visibile in Figura 5.1, nella quale si può riconoscere la forma dello stato della California. 5.2 confronto con maxcoloc

Gli esperimenti condotti per confrontare TopKCondensed con MAXColoc si sono concentrati sulla verifica del livello di precisione della misura di supporto fornita dai due algoritmi. In tutti i casi di seguito descritti, è stato eseguito TopKCondensed con un valore prefissato di k e quindi è stato selezionato il valore minimo di soglia riscontrato, ovvero R.last. PIlb come soglia minima θ da utilizzare con MAXColoc. Questo permette di riscontrare le informazioni sulle medesime colocation in entrambi gli algoritmi. Con tale metodologia sono stati eseguiti i seguenti test: esperimento 1 – tolleranza Il valore di δ è stato fatto variare nell’insieme {2%, 4%, 6%, 8%} mentre è stato fissato il parametro k = 40 e la distanza massima tra nodi vicini è stata definita in 800 metri. Per questo test è stato usato D1 .

35

36

analisi dei risultati

Figura 5.1: Rappresentazione dei nodi contenuti in D1

5.2 confronto con maxcoloc

37

esperimento 2 – numero di pattern Il valore di k è stato fatto variare nell’insieme {20, 30, 40, 50} mentre è stato fissato il parametro δ = 4% e la distanza massima tra nodi vicini è stata definita in 800 metri. Per questo test è stato usato D2 . esperimento 3 – distanza massima Il valore della distanza è stato fatto variare nell’insieme {600m, 800m, 1000m, 1200m}. Il numero di pattern è stato fissato a k = 40 e la tolleranza è stata posta a δ = 4%. Per questo test è stato usato D3 . Per effettuare una comparazione dei risultati, è stata costruita una lista di valori rappresentanti le frequenze delle colocation restituite dai due algoritmi. Nello specifico, per TopKCondensed è stata considerata la media aritmetica tra PIlb e PIub di ogni pattern, contando il valore una volta per ciascuna colocation rappresentata dal pattern. Il conteggio viene memorizzato durante l’esecuzione della funzione replace. Nel caso di MAXColoc, viene considerato il valore di frequenza restituito e direttamente associato ad ogni colocation. Una volta costruite le liste di frequenze relative a ciascuna esecuzione degli algoritmi, sono stati disegnati dei box-plot in cui le scatole rettangolari rappresentano i limiti del primo e terzo quartile (q 1 e q 3 ), 4 4 mentre la linea orizzontale interna individua la mediana. I segmenti che si estendono oltre ai rettangoli rappresentano i valori minimi e massimi nei dati, tra quelli interni al limite di 1.5 volte lo scarto interquartile. La rappresentazione permette di ottenere informazioni sintentiche ma significative sulla distribuzione dei valori di frequenza forniti dai due algoritmi. Esperimento 1 La Figura 5.2 mostra i risultati. È possibile vedere che al variare della tolleranza, i valori di supporto forniti da MAXColoc sono sostanzialmente simili e non presentano molta variazione, concentrandosi su frequenze molto basse. Al contrario, TopKCondensed individua anche valori maggiori, quindi da ritenere più precisi. La differenza marcata viene ridotta dall’aumentare di δ, anche in considerazione del fatto che una maggiore tolleranza permette la rilevazione di numerose colocation specialmente con frequenza bassa. Nonostante ciò, è possibile riscontrare comunque dei valori più precisi nel caso di TopKCondensed. Esperimento 2 La Figura 5.3 mostra i risultati. Nel caso di valori piccoli di k la differenza è particolarmente marcata: mentre le frequenze individuate da MAXColoc sono totalmente appiattite, la distribuzione dei risultati di TopKCondensed è molto più ampia.

38

analisi dei risultati

Figura 5.2: Risultati dell’Esperimento 1

Figura 5.3: Risultati dell’Esperimento 2

5.2 confronto con maxcoloc

39

Figura 5.4: Risultati dell’Esperimento 3

Tale effetto viene ridotto in modo considerevole all’aumentare dei pattern richiesti, per ragioni simili a quanto riportato nell’esperimento precedente. Si può osservare come anche in questo caso la tolleranza garantita sull’errore, determinata dal parametro δ, consente di ottenere risultati decisamente più precisi nella misura del supporto. Esperimento 3 La Figura 5.4 mostra i risultati. In questo caso è possibile vedere un comportamento in parte diverso. L’algoritmo TopKCondensed fornisce sempre risultati migliori di MAXColoc, tuttavia la differenza riscontra un aumento al crescere della distanza. In questo caso sia il numero di pattern richiesti che la tolleranza sono costanti, tuttavia è da considerare che l’aumentare della distanza fa crescere esponenzialmente anche il numero di colocation presenti all’interno del grafo. In particolare, aumentano le colocation di dimensione piccola, le quali hanno un valore del participation index maggiore. Dato che MAXColoc individua le maximal colocation ignorandone i sottoinsiemi, è portato a considerare un limite inferiore del participation index il più piccolo possibile. Al contrario, TopKCondensed riscontra la presenza di sottoinsiemi molto frequenti e ne misura il supporto con errore massimo δ. Ciò consente risultati più precisi in particolare in presenza di numerosi archi, dati ad esempio da una soglia di distanza massima alta.

40

analisi dei risultati

5.3

confronto con topkcoloc

Per confrontare TopKCondensed con TopKColoc è utile analizzare la differenza di rappresentatività tra i risultati prodotti dai due algoritmi. Nell’esecuzione dei test, entrambi gli algoritmi sono stati eseguiti con il medesimo valore di k e sono state analizzate le quantità di colocation rappresentate, conteggiate nella funzione replace. Per essere precisi, nella valutazione di TopKColoc, si è semplicemente eseguito TopKCondensed con tolleranza nulla, cioè δ = 0. Anche in questo caso sono stati eseguiti tre differenti test, del tutto simili a quelli descritti nella Sezione 5.2: esperimento 4 – tolleranza Il valore di δ è stato fatto variare nell’insieme {2%, 4%, 6%, 8%} mentre è stato fissato il parametro k = 40 e la distanza massima tra nodi vicini è stata definita in 800 metri. Per questo test è stato usato D4 . esperimento 5 – numero di pattern Il valore di k è stato fatto variare nell’insieme {20, 30, 40, 50} mentre è stato fissato il parametro δ = 4% e la distanza massima tra nodi vicini è stata definita in 800 metri. Per questo test è stato usato D5 . esperimento 6 – distanza massima Il valore della distanza è stato fatto variare nell’insieme {600m, 800m, 1000m, 1200m}. Il numero di pattern è stato fissato a k = 40 e la tolleranza è stata posta a δ = 4%. Per questo test è stato usato D6 . Il confronto dei risultati è stato fatto conteggiando le colocation rappresentate dagli output dei due algoritmi a parità di k pattern richiesti. Dopodiché è stato prodotto un grafico per ciascun test. Esperimento 4 La Figura 5.5 mostra i risultati. Dato che l’unico parametro ad essere variato è stato δ, le quattro colonne rosse rappresentano di fatto un solo output ripetuto quattro volte. Dal grafico è possibile vedere come una variazione della tolleranza aumenti drasticamente l’effetto di compattazione fornito da TopKCondensed. Ovviamente si deve tenere in considerazione che questa maggiore rappresentatività va a scapito dell’accuratezza relativa alla misura del participation index: non è possibile incrementare a dismisura δ, altrimenti il valore di supporto fornito dall’algoritmo sarebbe talmente impreciso da risultare inutile. Esperimento 5 La Figura 5.6 mostra i risultati. Anche in questo caso, relativo alla variazione del parametro k, si possono notare chiaramente gli effetti

5.3 confronto con topkcoloc

41

Figura 5.5: Risultati dell’Esperimento 4

Figura 5.6: Risultati dell’Esperimento 5

42

analisi dei risultati

Figura 5.7: Risultati dell’Esperimento 6

della compressione derivanti dalla tolleranza sulla misura del participation index. L’aumento di k comporta anche una crescita del livello di compressione. Questo effetto è determinato dal criterio stesso con il quale le colocation vengono accorpate nei pattern. Esso è maggiore con valori di k elevati anche in virtù del fatto che gli ultimi pattern presentano frequenze inferiori. I risultati ottenuti con TopKCondensed rendono possibile ricavare informazioni su un maggior numero di colocation, a parità di pattern richiesti. Esperimento 6 La Figura 5.7 mostra i risultati. In questo esperimento l’aumento della distanza tra i nodi porta invece ad una riduzione del livello di compressione. Il numero di colocation rappresentate dall’output di TopKCondensed tende ad avvicinarsi a quello relativo a TopKColoc. Come discusso precedentemente, l’aumento della distanza comporta una crescita del numero di colocation, in particolare quelle di dimensione inferiore. Ciò implica la crescita del participation index delle colocation piccole ma non dei rispettivi sovrainsiemi. Pertanto ne deriva una differenza di frequenza tale da consentire di unire meno colocation in un solo pattern.

CONCLUSIONI

6

In questa tesi è stato trattato il problema del mining delle colocation, approfondendo innanzitutto i concetti teorici basilari e le strategie utilizzate in letteratura. È stato quindi sviluppato il nuovo concetto di condensed colocation pattern ed è stato fornito un algoritmo per effettuare il mining di questa tipologia di pattern. I vantaggi teorici attesi sono stati verificati tramite dei test. Tali verifiche hanno messo a confronto la soluzione proposta con altri due algoritmi esistenti per le colocation. Ne è risultato che i condensed colocation pattern consentono una rappresentazione compatta di numerose colocation tramite una tolleranza di errore massimo. Inoltre, l’algoritmo sviluppato risulta efficace nel fornire un insieme di risultati maggiormente compatto e rappresentativo.

43

Parte III APPENDICE

P O R Z I O N I S I G N I F I C AT I V E D I C O D I C E

A

In questa appendice vengono presentati le due parti più importanti della logica del programma, vale a dire il codice principale di TopKCondensed e l’implementazione di FP-Growth. Il codice sorgente dei software relativi a TopKCondensed e MAXColoc, come implementati per questa tesi, è disponibile all’indirizzo:
http://wwwstud.dsi.unive.it/alazzaro/BachelorThesis/

a.0.1

main.cpp

enum distanceType { euclidean, latlon }; static map<string, distanceType> mapDistanceTypes; void findStarInstances(map<Colocation, vector<Instance> >* results, vector<Colocation>& Cl, unsigned int l, vector<NeighborhoodTransaction>& nt) { NeighborhoodTransaction tmpNt; for(vector<Colocation>::iterator i = Cl.begin(); i != Cl.end(); i++) { Colocation& c = *i; (*results)[c] = vector<Instance>(); int head = *(c.Getitems()->begin()); MiniNode h; h.Settype(head); h.Setid(0); tmpNt.Setreference(h); vector<NeighborhoodTransaction>::iterator low; low = lower_bound(nt.begin(), nt.end(), tmpNt); for(vector<NeighborhoodTransaction>::iterator j = low; j != nt.end(); j++) { NeighborhoodTransaction& tra = *j; /* * We are interested only in transactions where the reference item * has the same type as the first element of c and we can exploit * the fact that nt is an ordered vector. */ if(tra.Getreference().Gettype() > head) break; if(tra.getLength() < l) continue; set<MiniNode>* traNodes = tra.Getitems(); vector<Instance> traInstances; // We manually insert the first element set<int>* elems = c.Getitems(); Instance first; first.addItem(tra.Getreference()); traInstances.push_back(first); set<int>::iterator k = elems->begin(); // Start from the second for(k++; k != elems->end(); k++) { // Search elements of this type set<MiniNode> results; /* * MiniNode h above already served it’s purpose, we can re-use * it here instead of creating a new one. */ h.Settype(*k); set<MiniNode>::iterator low; low = lower_bound(traNodes->begin(), traNodes->end(), h); for(set<MiniNode>::iterator r = low; r != traNodes->end(); r++) { MiniNode* current = (MiniNode*) &*r; if(current->Gettype() == *k) results.insert(*current);

47

48

porzioni significative di codice

else break; } if(results.size() == 0) { /* * This transaction does not match and we need to stop. * Since .clear() does not free memory, we use this instead. * See also: http://lazza.me/1aJnktV */ vector<Instance>().swap(traInstances); break; } else { vector<Instance> updatedInstances; /* * We need to make a copy of transaction instances FOR EACH * result and enqueue it. */ for(vector<Instance>::iterator ei = traInstances.begin(); ei != traInstances.end(); ei++) { Instance& current = *ei; for(set<MiniNode>::iterator ni = results.begin(); ni != results.end(); ni++) { Instance aCopy = current; MiniNode* newNode = (MiniNode*) &*ni; aCopy.addItem(*newNode); updatedInstances.push_back(aCopy); } } swap(traInstances, updatedInstances); } } for(vector<Instance>::iterator k = traInstances.begin(); k != traInstances.end(); k++) (*results)[c].push_back(*k); } } } void filterCliqueInstances(vector<Instance>* results, vector<Instance>& SIc, vector<Instance>& CIl1) { /* * SIc is the set of star instances of candidate c * CIl1 is the SORTED set of all the clique instances of length l-1 */ for(vector<Instance>::iterator i = SIc.begin(); i != SIc.end(); i++) { Instance* current = (Instance*) &*i; set<MiniNode>* els = current->Getitems(); MiniNode head = *(els->begin()); els->erase(els->begin()); bool push = binary_search(CIl1.begin(), CIl1.end(), *current); els->insert(head); // Revert the change! if(push) results->push_back(*current); } } double calculateTruePi(vector<Instance>& CIc, Colocation& c, unsigned int l, FreqTracker& ft) { /* This function is actually pretty simple. Given a colocation c and all of * * its true instances, we count for each node type the ratio: involved instances / total instances * * The true PI is the lowest ratio. */ double result = 1.0; // cannot be more than this set<int>* elements = c.Getitems(); unsigned int idx = 0; for(set<int>::iterator i = elements->begin(); i != elements->end(); i++) { set<unsigned int> different; for(vector<Instance>::iterator j = CIc.begin(); j != CIc.end(); j++) { Instance& current = *j; set<MiniNode>* nodes = current.Getitems(); set<MiniNode>::iterator elJ = nodes->begin(); // We use idx to fastly index the set as it was a vector advance(elJ, idx); MiniNode* sameType = (MiniNode*) &*elJ; different.insert(sameType->Getid()); } double fraction = ((double) different.size()) / ft.getFreq(*i); result = min(result, fraction); idx++;

porzioni significative di codice

49

} return result; } void findSubClosed(vector<Colocation>* results, vector<Colocation>& R, Colocation& c, double pi, double delta) { set<int>* items = c.Getitems(); for(vector<Colocation>::iterator i = R.begin(); i != R.end(); i++) { Colocation& current = *i; if((pi < (current.GethighFreq() - delta)) || (pi > current.GetlowFreq()) || (current.Getitems()->size() == c.Getitems()->size())) continue; set<int>* currItems = current.Getitems(); bool ok = includes(items->begin(), items->end(), currItems->begin(), currItems->end()); if(ok) results->push_back(current); } } void replaceSubsets(vector<Colocation>* R, vector<Colocation>* subsets, Colocation* c, double pi) { double lowFreq = pi; double highFreq = pi; double members = 1; for(vector<Colocation>::iterator ci = subsets->begin(); ci != subsets->end(); ci++) { Colocation& co = *ci; highFreq = max(highFreq, co.GethighFreq()); members += co.getmembers(); } c->SetlowFreq(lowFreq); c->SethighFreq(highFreq); c->Setmembers(members); sort(subsets->begin(), subsets->end()); R->erase( remove_if( R->begin(), R->end(), toBeReplaced(subsets) ), R->end() ); vector<Colocation>::iterator pos = upper_bound(R->begin(), R->end(), *c, Colocation::upperPIsort); R->insert(pos, *c); } int main(int argc, char *argv[]) { // Initialize the map for threshold types mapDistanceTypes["euclidean"] = euclidean; mapDistanceTypes["latlon"] = latlon; if(argc != 6) { cerr << "Usage: TopKColoc filename distance threshold k" << endl; cerr << "Parameters:" << endl; cerr << " filename - the dataset" << endl; cerr << " distance - ’euclidean’ or ’latlon’" << endl; cerr << " threshold - maximum allowed distance of neighbours" << endl; cerr << " (’latlon’ distance is in kilometers)" << endl; cerr << " delta - percent value of tolerance for support" << endl; cerr << " k - number of top closed colocations" << endl; cerr << "Example: TopKColoc data.txt latlon 5.34 0.015 10" << endl; exit(1); } string filename = argv[1]; string distance = argv[2]; std::stringstream sstm, sstm2, sstm3; sstm << argv[3]; double threshold; sstm >> threshold; sstm2 << argv[4]; double delta; sstm2 >> delta; sstm3 << argv[5]; unsigned int k; sstm3 >> k; cerr << "Importing data..." << endl; ifstream infile(filename.c_str()); if(!infile){ cerr << "ERROR: Data file not found" << endl; exit(1); }

50

porzioni significative di codice

DatasetImporter d(filename); Graph g; FreqTracker typeFrequencies = d.parseOn(g); set<int>& typesList = d.GetintTypes(); map<int, string>& typeMap = d.GettypeMap(); // Useful information cerr << "Filename: " << filename << endl; int size = g.Getnodes()->size(); cerr << "Number of nodes: " << size << endl; cerr << "Distance: " << distance << endl; cerr << "Threshold: " << threshold << endl; cerr << "Delta: " << delta << endl; cerr << "K: " << k << endl; cerr << "Computing pairs..." << endl; // See also: http://lazza.me/1d200Ys switch(mapDistanceTypes[distance]) { case euclidean: { EuclideanThreshold thr(threshold); thr.applyOn(g); break; } case latlon: { LatLonThreshold thr(threshold); thr.applyOn(g); break; } default: cerr << "ERROR: The specified distance type is not valid" << endl; exit(1); } cerr << "Forming transactions..." << endl; vector<NeighborhoodTransaction> nt; vector<EventTransaction> ent; set<Node>* nodes = g.Getnodes(); for (set<Node>::iterator i = nodes->begin(); i != nodes->end(); i++) { Node* n = (Node*) &*i; NeighborhoodTransaction tra = NeighborhoodTransaction(*n); nt.push_back(tra); ent.push_back(EventTransaction(tra)); } cerr << "Sorting transactions..." << endl; sort(nt.begin(), nt.end()); sort(ent.begin(), ent.end()); cerr << "Finding star candidates..." << endl; /* * In the following loop we build a FPTree for each node type and then we * perform the FP-Growth algorithm in order to extract the transactions for * building the colocation instances. */ map< int, set<Colocation> > transactionGroups; for(set<int>::iterator i = typesList.begin(); i != typesList.end(); i++) { FPTree fpt(*i, ent); set<StarCandidate> partial = fpt.FPGrowth(); transactionGroups[*i] = set<Colocation>(); for(set<StarCandidate>::iterator j = partial.begin(); j != partial.end(); j++) { StarCandidate* star = (StarCandidate*) &*j; Colocation c(*star); transactionGroups[*i].insert(c); } } cerr << "Finding colocation candidates..." << endl; /* * Due to the overly complicated syntax of a "for each" in C++ this looks * quite complicated. In reality, we just need to check that a transaction * is in every group (i.e. generated by every tree) before we can consider * it a candidate. */ set<Colocation> candidates; // This loop iterates over each node type for(map<int, set<Colocation> >::iterator i = transactionGroups.begin(); i != transactionGroups.end(); i++) { set<Colocation> current = i->second;

porzioni significative di codice

51

// This loop iterates over each set/transaction for(set<Colocation>::iterator j = current.begin(); j != current.end(); j++) { // This part is for checking if a set is a real colocation candidate bool ok = true; Colocation* c = (Colocation*) &*j; double minFreq = c->GetlowFreq(); set<int>* tra = c->Getitems(); for(set<int>::iterator k = tra->begin(); k != tra->end(); k++) { int el = *k; set<Colocation>::iterator r = transactionGroups[el].find(*c); if(r == transactionGroups[el].end()) { ok = false; break; } else { Colocation* other = (Colocation*) &*r; minFreq = min(minFreq, other->GetlowFreq()); } transactionGroups[el].erase(r); } if(ok) { c->SetlowFreq(minFreq); c->SethighFreq(minFreq); candidates.insert(*c); } } } cerr << "Building the candidates subset tree..." << endl; CSTree Cst(candidates); cerr << "Starting the search process..." << endl; vector<Colocation> R; unsigned int l = 2; vector<Instance> CIl1; double theta = 0; vector<Colocation> Cl; Cst.getCandidatesByLength(&Cl, l); while(Cl.size() != 0) { cerr << "Working for l = " << l << endl; sort(Cl.begin(), Cl.end(), Colocation::upperPIsort); if(R.size() == k) { // If the last element is of size l, we can prune a bit more double pruneLimit; Colocation& last = R.back(); if(last.Getitems()->size() < l) pruneLimit = theta; else pruneLimit = last.GetlowFreq(); Cst.pruneCandidates(l, pruneLimit); /* * Here we implement a simple binary search procedure, because the * one provided by the STL is not useful in this context. This is * why it’s better to use a vector instead of a list, otherwise the * indexing process is extremely complicated. */ unsigned int low = 0; unsigned int up = Cl.size() - 1; while(low < up) { unsigned int mid = (low+up)/2; if(Cl[mid].GetlowFreq() >= pruneLimit) low = mid + 1; else up = mid; } unsigned int res; if (!((low == up) && Cl[low].GetlowFreq() >= pruneLimit)) res = low; else res = min(low + 1, (unsigned int) Cl.size()); Cl.resize(res); if(Cl.size() == 0) break; } // end if |R|==k map<Colocation, vector<Instance> > SIl; findStarInstances(&SIl, Cl, l, nt); vector<Instance> CIl; for(vector<Colocation>::iterator it = Cl.begin(); it != Cl.end(); it++) {

52

porzioni significative di codice

Colocation& c = *it; if((R.size() == k) && c.GetlowFreq() < theta) { // If the last element is of size l, we can prune a bit more Colocation& last = R.back(); if(last.Getitems()->size() < l) Cst.pruneCandidates(l, theta); else Cst.pruneCandidates(l, last.GetlowFreq()); /* * The original pseudocode contains the word "continue" but the * text is quite clear to state that it is the OUTER loop to be * continue. For this reason, here is a break for the inner for. */ break; } vector<Instance>& SIc = SIl[c]; vector<Instance> CIc; // In the first step we don’t need to filter double pi; if(l > 2) { filterCliqueInstances(&CIc, SIc, CIl1); // Remember instances for next step CIl.insert(CIl.end(), CIc.begin(), CIc.end()); pi = calculateTruePi(CIc, c, l, typeFrequencies); } else { CIl.insert(CIl.end(), SIc.begin(), SIc.end()); pi = calculateTruePi(SIc, c, l, typeFrequencies); } c.SetlowFreq(pi); // Prepare for a possible insertion c.SethighFreq(pi); if(R.size() < k) { vector<Colocation> subsets; findSubClosed(&subsets, R, c, pi, delta); if(subsets.size() == 0) { vector<Colocation>::iterator pos = upper_bound(R.begin(), R.end(), c, Colocation::upperPIsort); R.insert(pos, c); } else { replaceSubsets(&R, &subsets, &c, pi); } // end if subsets is empty (else part) } // end if |R| < k (if part) else { if(theta < pi) { vector<Colocation> subsets; findSubClosed(&subsets, R, c, pi, delta); if(subsets.size() == 0) { R.pop_back(); vector<Colocation>::iterator pos = upper_bound(R.begin(), R.end(), c, Colocation::upperPIsort); R.insert(pos, c); } else { replaceSubsets(&R, &subsets, &c, pi); } } } // end if |R| < k (else part) theta = R.back().GethighFreq() - delta; } // end for each c in Cl l++; swap(CIl1, CIl); sort(CIl1.begin(), CIl1.end()); // We need it for fast filtering vector<Colocation>().swap(Cl); Cst.getCandidatesByLength(&Cl, l); } // end while Cl is not empty for(vector<Colocation>::iterator i = R.begin(); i != R.end(); i++) { Colocation& c = *i; cout << c.str(typeMap) << endl; } return 0; }

¥

porzioni significative di codice

53

a.0.2

Metodo FPGrowth da FPTree.cpp

set<StarCandidate> FPTree::FPGrowth(set<int> ending) { /* * FP-Growth is a recursive algorithm. The base case consists of a tree that * contains a single path. In this case the combinations are enumerated with * ease and the result is given. Otherwise, it’s necessary to recursively * call the procedure. */ set<StarCandidate> candidates; // Base case if(single) { vector<FPNode*>* current = root.Getchildren(); /* * In this part we don’t need to go bottom-up. We get the list of the * children, but we know there can be only one or none. So we use the * iterator to check if we have reached the bottom. */ StarCandidate first; first.Setitems(ending); first.Setreference(root.Gettype()); candidates.insert(first); while(current->begin() != current->end()) { FPNode* node = *(current->begin()); set<StarCandidate> newCandidates; int type = node->Gettype(); for (set<StarCandidate>::iterator i = candidates.begin(); i != candidates.end(); i++) { // Here we really need a copy of *i called c StarCandidate c = *i; set<int>* items = c.Getitems(); items->insert(type); c.Setfreq(((double) node->Getcount()) / root.Getcount()); newCandidates.insert(c); } candidates.insert(newCandidates.begin(), newCandidates.end()); current = node->Getchildren(); } candidates.erase(first); } // Recursive part else { vector<int> nodeTypes; for(map<int, FPNode*>::iterator i = headerTable.begin(); i != headerTable.end(); i++) { nodeTypes.push_back(i->first); } sort(nodeTypes.begin(), nodeTypes.end(), ft); reverse(nodeTypes.begin(), nodeTypes.end()); /* * The following loop is the iterator over the different types of nodes. * We need to construct an FP-Tree ending with each node type. */ for(vector<int>::iterator i = nodeTypes.begin(); i != nodeTypes.end(); i++) { int& type = *i; /* * For each node type, there could be more than one instance of it, * so more than one path ending with the same type. That’s why we * iterate through the different nodes of the same type. */ FPNode* current = headerTable[type]; // We need a copy of ending set<int> newEnding(ending.begin(), ending.end()); newEnding.insert(type); vector< set<StarCandidate> > typeCandidates; while(current != NULL) { vector<EventTransaction> tmpCandidates; set<int> ancestors; // Generate the transaction with all the ancestors FPNode* node = current; // Double check so we avoid the root while (node != NULL) { ancestors.insert(node->Gettype()); node = node->Getparent(); if(node->Getparent() == NULL) break; }

54

porzioni significative di codice

EventTransaction tra; tra.Setitems(ancestors); tra.Setreference(root.Gettype()); // We need to insert it the same number of times of current unsigned int times = current->Getcount(); for(unsigned int k = 0; k < times; k++) tmpCandidates.push_back(tra); FPTree typeTree(root.Gettype(), tmpCandidates); typeTree.Getroot().Setcount(root.Getcount()); set<StarCandidate> results = typeTree.FPGrowth(newEnding); // We also need to add the "empty" transaction StarCandidate star; star.Setreference(root.Gettype()); star.Setitems(newEnding); star.Setfreq(((double) current->Getcount()) / root.Getcount()); results.insert(star); typeCandidates.push_back(results); current = current->Getsibling(); } // end for each node of type T /* * In the following part we merge the partial results and then * add the current candidates to the global set of candidates. */ set<StarCandidate> partial; for(vector< set<StarCandidate> >::iterator i = typeCandidates.begin(); i != typeCandidates.end(); i++) { set<StarCandidate>& subset = *i; for(set<StarCandidate>::iterator j = subset.begin(); j != subset.end(); j++) { StarCandidate* current = (StarCandidate*) &*j; // Check if the candidate is already partial if(partial.find(*current) != partial.end()) continue; double freq = current->Getfreq(); // Search for it in the other subsets vector< set<StarCandidate> >::iterator o = i; for(o++; o != typeCandidates.end(); o++) { set<StarCandidate>& searchSubset = *o; set<StarCandidate>::iterator search = searchSubset.find(* current); if (search != searchSubset.end()) { StarCandidate* found = (StarCandidate*) &*search; freq += found->Getfreq(); } } current->Setfreq(freq); partial.insert(*current);

} } // Here we have finished merging the partial results candidates.insert(partial.begin(), partial.end()); } // end for each nodeType } return candidates; }

¥

BIBLIOGRAFIA

[1] Rakesh Agrawal and Ramakrishnan Srikant. Fast algorithms for mining association rules. Proc. 20th Int. Conf. Very Large Data Bases, VLDB, 1994. URL https://www.it.uu.se/edu/course/ homepage/infoutv/ht08/vldb94_rj.pdf. [2] Mark Bow. Compact Co-location Pattern Mining. 2011. URL http://opus.ipfw.edu/masters_theses/3. [3] Jiawei Han, Jian Pei, and Yiwen Yin. Mining frequent patterns without candidate generation. ACM SIGMOD Record, 29(2):1–12, June 2000. ISSN 01635808. doi: 10.1145/335191.335372. URL http://portal.acm.org/citation.cfm?doid=335191.335372. [4] Krzysztof Koperski and Jiawei Han. Discovery of spatial association rules in geographic information databases. Advances in spatial databases, 1995. URL http://link.springer.com/chapter/ 10.1007/3-540-60159-7_4. [5] Feifei Li, Dihan Cheng, and Marios Hadjieleftheriou. On trip planning queries in spatial databases. In Proceedings of the 9th International Symposium on Spatial and Temporal Databases (SSTD), 2005. URL http://www2.research.att.com/~marioh/papers/ sstd05-tpq.pdf. [6] Wing Ning Li and Ravi Kiran. An object-oriented design and implementation of reusable graph objects with C++: a case study. In Proceedings of the 1996 ACM symposium on Applied Computing, 1996. ISBN 0897918207. URL http://dl.acm.org/citation. cfm?id=331433. [7] Nikos Mamoulis. Co-location Patterns, Algorithms. Encyclopedia of GIS, pages 1–7, 2008. URL http://link.springer.com/ content/pdf/10.1007/978-0-387-35973-1_152.pdf. [8] Jian Pei, Guozhu Dong, Wei Zou, and Jiawei Han. Mining Condensed Frequent-Pattern Bases. Knowledge and Information Systems, 6(5):570–594, February 2004. ISSN 0219-1377. doi: 10.1007/s10115- 003- 0133- 6. URL http://link.springer.com/ 10.1007/s10115-003-0133-6. [9] Shashi Shekhar and Yan Huang. Discovering spatial co-location patterns: A summary of results. Advances in Spatial and Temporal Databases, 2001. URL http://link.springer.com/chapter/ 10.1007/3-540-47724-1_13.

55

56

bibliografia

[10] Jin Soung Yoo and Mark Bow. Mining top-k closed co-location patterns. In Spatial Data Mining and Geographical Knowledge Services (ICSDM), 2011 IEEE International Conference on, 2011. ISBN 9781424483518. URL http://ieeexplore.ieee.org/xpls/abs_ all.jsp?arnumber=5969013. [11] Jin Soung Yoo and Mark Bow. Mining maximal co-located event sets. Advances in Knowledge Discovery and Data Mining, pages 351– 362, 2011. doi: 10.1007/978- 3- 642- 20841- 6_29. URL http://link. springer.com/chapter/10.1007/978-3-642-20841-6_29. [12] Jin Soung Yoo and Shashi Shekhar. A joinless approach for mining spatial colocation patterns. Knowledge and Data Engineering, IEEE Transactions on, 2006. URL http://ieeexplore.ieee.org/ xpls/abs_all.jsp?arnumber=1683769.

colophon This document was typeset using the typographical look-and-feel classicthesis developed by André Miede. The style was inspired by Robert Bringhurst’s seminal book on typography “The Elements of A Typographic Style”. classicthesis is available for both L TEX and LYX:
http://code.google.com/p/classicthesis/

Happy users of classicthesis usually send a real postcard to the author, a collection of postcards received so far is featured at:
http://postcards.miede.de/