• Non ci sono risultati.

2.2 Apprendimento non supervisionato

4.1.1 Classi utilizzate

Dalle informazioni fornite precedentemente si evince che le dimensioni dei database sono abbastanza voluminose, per questo si è deciso di limitare l’analisi del consumo unicamen- te sul profilo dell’utente tralasciando dunque i valori forniti dai sensori interni che fornivano informazioni sull’umidità, la temperatura, la luminanza e la presenza di attività all’interno di una stanza. Anche le condizioni esterne, come per esempio il meteo, non sono state valu- tate. Inoltre, la maggior parte delle tabelle sono superflue allo scopo del progetto.

Eseguendo questo accorgimento il numero di tabelle si è ridotto a un totale di 10, come si può vedere dal diagramma delle classi in figura 4.2.

Di seguito un’analisi delle tabelle per capire più dettagliatamente il loro contenuto:

• User: contiene le informazioni sull’utente inerenti alla registrazione sull’app creata nel progetto enCOMPASS come per esempio l’username, l’e-mail, il giorno di nascita ecc.

• User_profile: contiene tutte le informazioni dell’utente che interesseranno in seguito l’analisi. Sono prensenti informazioni sugli elettrodomestici, sul numero di componenti del nucleo famigliare ecc.

• Heating_source_type: indica il tipo di fonte di riscaldamento, in questo caso può essere a olio, a elettricità, a gas oppure a legna.

• Heating_type: anche questa tabella è sul riscaldamento, qui le informazioni possono essere elementi radiatori, serpentina a pavimento oppure convezione d’aria

• Main_lighting_type: indica il tipo di illuminazione principale dove le lampadine posso- no essere alogene, led, a basso consumo o a incandescenza; c’è anche la possibilità che l’utente non sia a conoscenza di questa informazione.

• Dwelling: contiene le informazioni sull’abitazione a livello di nucleo familiare, indispen- sabile per la connessione tra l’utente e lo smart meter.

• Building: contiene le informazioni sul palazzo fisico.

• Building_type: procura le informazioni sul tipo di palazzo che potrebbe essere una casa indipendente, un appartamento, una casa bifamiliare, una villetta a schiera, un edificio pubblico, una scuola oppure degli edifici residenziali.

• Smart_meter: contiene le informazioni sul contatore intelligente installato nelle abita- zioni

• Meter_consumption: contiene i valori di consumo campionati dallo smart meter e l’istante di tempo a cui fa riferimento.

4.2

Pretrattamento dei dati

Ora che è stato ridotto il numero di tabelle e si è a conoscenza di dove si trovano le infor- mazioni necessarie, ci si può concentrare sulla loro analisi più approfondita.

Come già accennato in precedenza, le date di inizio e fine campionamento non sono uguali per i tre database, dunque si è scelto un arco di tempo della durata di un anno partendo dal’01/06/2018 fino al’31/05/2019.

Sempre sulla questione date, un ulteriore taglio è stato eseguito sulle festività: con un pic- colo script sono state calcolate tutte le domeniche presenti nelle dodici mensilità e per ogni nazione sono stati inseriti i giorni festivi di maggior importanza.

La lista di queste date viene esclusa dalla query finale e di conseguenza le informazioni del consumo di quelle giornate non saranno presenti nell’analisi, questa scelta è avvenuta in quanto durante le domeniche e i giorni festivi è molto più probabile consumare maggior- mente poiché è possibile che tutto il nucleo familiare si trovi nell’abitazione o viceversa. Inoltre, le festività variano a seconda della nazione e per tali giorni le informazioni, non es- sendo eque, avrebbero ’sporcato’ i risultati finali.

Il progetto si vuole concentrare sullo studio del profilo dei semplici utenti considerando un insieme di features e di valori equi, per questa motivazione si sono eliminati gli edifici che non erano abitazioni private come per esempio le scuole e i municipi.

All’interno dei database sono presenti degli utenti di test che devono essere rimossi. Dopo le rimozioni eseguite sulle date e sugli edifici, per alcuni utenti persistevano alcune infor- mazioni contrastanti. In accordo con il relatore si è deciso di non considerare gli utenti del database greco poiché nel corso del progetto enCOMPASS non ci sono stati più contatti con il rispettivo istituto di ricerca che gestisce il database e dunque le informazioni presenti non erano molto affidabili. Per quanto concerne il database tedesco, ci sono alcuni utenti che hanno abbandonato il progetto e altri i quali dati riportano dei buchi temporali significativi, anche questi utenti sono stati rimossi.

La query finale utilizzata per interrogare il database e creare i primi dataframe con le restrizioni sopraelencate è la seguente:

Figura 4.3: Query finale per interrogare i database

Dove con ’building’ si fa riferimento al tipo di edificio accettato, nel nostro caso quelli resi- denziali, ’final_string’ contiene tutta la lista delle date da non considerare e i numeri fanno riferimento agli id degli utenti che devono essere rimossi per un totale di 27 utenti.

Otteniamo due dataframe, uno utilizzando il database svizzero e l’altro usando quello tede- sco. Per delle analisi che vogliamo svolgere in seguito, a entrambi aggiungiamo due colonne nominate ’Switzerland’ e ’Germany’ che potranno assumere il valore 0 o 1 a seconda se il dato da analizzare proviene da uno piuttosto che dall’altro dataframe; in questo modo man- teniamo l’informazione sulla nazionalità. Questa modalità è denominata one-hot encoding e verrà spiegata successivamente.

Per ottenere un unico dataframe eseguiamo una semplice concatenazione dei due, purtrop- po questo dataframe contiene dei valori NaN (tramandati dai due dataframe iniziali) che non permettono l’avanzamento delle operazioni necessarie a realizzare i cluster e la classifica- zione.

Per sostituire questi valori è stata dapprima effettuata un’interpolazione lineare ma analiz- zando più approfonditamente i dati in possesso non è risultata la scelta più adatta in quanto potevano esserci molti NaN consecutivi o capitava che i valori scelti per interpolare non fossero adatti. Tenendo conto che i dati di campionamento non sono pochi, analizzando il problema con il relatore, si è deciso semplicemente di rimuoverli utilizzando la funzione dropna().

Ricapitolando, eliminando dall’analisi tutti gli utenti greci più quelli problematici, il numero di utenti è più che dimezzato passando da 448 a 179. Facendo un breve calcolo si può capire con quante informazioni si andrà a lavorare durante l’analisi. I campionamenti avvengono ogni 15 minuti, quindi nell’arco della giornata sono 96 in totale. L’analisi è stata delimitata a un anno di rilevamenti, quindi 365 giorni. Per ogni utente si hanno dunque 35’040 dati sul consumo, in totale moltiplicando questo numero per il numero di utenti analizzabili si arriva teoricamente a 6’272’160, andando però a controllare la dimensione del dataframe completo a cui sono stati rimossi i valori NaN otteniamo 5’058’941 che nonostante tutte le restrizioni è un ottimo numero per permettere la buona riuscita dell’analisi.

4.2.1

One-hot encoding

One-hot encoding è un processo mediante il quale le variabili categoriche1vengono conver- tite in una forma che permette agli algoritmi di machine learning di fare un lavoro migliore durante la previsione.

Si tratta semplicemente di creare delle nuove colonne corrispondenti ai valori che può as- sumere la variabile categorica, dopodiché verrà inserito il valore 1 se la condizione è soddi- sfatta oppure 0 in caso contrario.

Questo approccio, come anticipato prima, è stato utilizzato per inserire le informazioni sulla nazionalità ma anche per i tipi di riscaldamento, i tipi di luce e i tipi di edifici. Di seguito sono riportate alcune immagini esempio catturate dal dataframe.

Figura 4.6: One-hot encoding con building type

4.3

Creazione dataframes

Applicato il processo di one-hot encoding, un’ultima miglioria da applicare al dataframe è quella di eliminare le colonne non rilevanti al fine ultimo del progetto poiché per tutti gli utenti è presente lo stesso valore e di conseguenza la feature risulta inutile. Si pensi al frigo o alla televisione che possiedono tutti.

Si ottiene, finalmente, il dataframe unico e completo, con un totale di 44 colonne equivalenti alle features di interesse. Le informazioni sul consumo sono però abbastanza insignificanti in quanto sono presenti i campionamenti ogni quarto d’ora, di conseguenza si creano dei nuovi dataframes aggregando i dati del consumo, ottenendo in questa maniera i consumi medi per ogni utente.

Il primo dataframe creato contiene la media giornaliera mensile, per ottenere questa aggre- gazione si sono dapprima sommati i valori del consumo di un singolo giorno ottenendo così il consumo giornaliero, dopodiché dei valori trovati si è eseguita la media per ogni mese. Il problema principale nella creazione di questo dataframe nasce dai valori in cui l’ultimo giorno contiene la somma dei consumi di tutto il mese, per ovviare a questo il consumo indicato viene diviso per il numero di giorni di quello specifico mese in modo da ottenere approssimativamente il consumo medio giornaliero per quel mese.

Inoltre, per questo dataframe non si voleva perdere l’indicazione sulla mensilità a cui il va- lore medio trovato fa riferimento, per questo le informazioni sono state aggiunte in modalità one-hot encoding. (Figura 4.7)

La figura 4.8 mostra il codice d’esempio su un’aggregazione mensile dove si va a calcolare la media dei valori.

Figura 4.8: Aggregate method

Per utilizzare i metodi di aggregazione, l’indice del dataframe dev’essere di tipo DateTime, le prime due righe di codice servono per l’appunto a impostare come indice la colonna ’da- tetime’ che contiene le informazioni sull’istante di tempo in cui è stato campionato il valore del consumo.

Il groupby() è indispensabile per avere i dati raggruppati per ogni utente (si vuole la media di quel determinato mese per quel determinato utente e non la media di quel mese di tutti gli utenti), infine il resample con chiave ’M’ che identifica la mensilità non fa altro che aggregare i dati su base mensile eseguendo la media dei valori.

Tutte le funzioni di aggregazione sono impostate con la stessa metodologia.

Il secondo dataframe contiene la media mensile per ogni utente, è stato creato ottenendo dapprima il consumo totale per ogni mese, quindi facendo un’aggregazione su base mensile e sommando i valori, e infine si è calcolata la media dei valori trovati.

Il terzo dataframe è molto semplice: contiene il consumo di tutto l’anno per ogni utente. Nel quarto dataframe invece troviamo unicamente i consumi giornalieri.

Il quinto e il sesto contengono le media mensile stagionale, per crearli si sono dapprima calcolati i consumi per ogni mese e poi si è fatta la media dei mesi che compongono una determinata stagione. La differenza tra i due si consegue nella suddivisione delle stagiona- lità, il primo è basto su quattro stagione mentre il secondo su tre unendo assieme primavera e autunno.

Per entrambi i dataframe sono state aggiunte, in modalità one-hot encoding, le informazioni per tenere traccia della stagione a cui si fa riferimento.

Le tabelle delineano come sono stati assegnati i mesi a seconda delle stagioni. Estate Giugno, Luglio, Agosto

Autunno Settembre, Ottobre, Novembre Inverno Dicembre, Gennaio, Febbraio Primavera Marzo, Aprile, Maggio

Tabella 4.1: Mensilità per quattro stagioni

Estate Giugno, Luglio, Agosto Autunno_Primavera Settembre, Ottobre, Novembre

Marzo, Aprile, Maggio Inverno Dicembre, Gennaio, Febbraio

Tabella 4.2: Mensilità per tre stagioni

I restanti dataframe sono gli stessi elencati precedentemente ma privati degli outliers. Per individuarli si è applicato il metodo dello z-score2con una threshold pari a 3, il che vuol dire che un punto viene considerato outlier se dista dalla media± 3 deviazioni standard.

La prima parte molto significativa e a cui si è dedicato un lasso di tempo importante, in quanto è indispensabile che il pretrattamento dei dati sia eseguito correttamente per non avere informazioni inconsistenti, è terminata.

Riassumendo sono stati creati un totale di dodici dataframe, ognuno con le proprie caratte- ristiche.

1 Media giornaliera mensile 2 Media mensile 3 Consumo annuo 4 Consumi giornalieri

5 Media mensile stagionale (4 stagioni) 6 Media mensile stagionale (3 stagioni) 7-8-9-10-11-12 Dataframe replicati, senza outliers

Tabella 4.3: Dataframe creati

Capitolo 5

Analisi

Una volta portato a termine il primo compito, tutti i dataframe sono pronti per l’analisi. Ora ci dedicheremo alla seconda parte dei compiti dove, come ricordiamo, viene richiesto di identificare i principali fattori che influenzano il consumo e di utilizzare algoritmi di clustering per organizzare i gruppi di utenti, infine essere in grado di assegnare un nuovo utente al suo cluster di appartenenza.

Gli algoritmi scelti sono quelli già spiegati nel capitolo 2, se in quel contesto ci eravamo soffermati sui fondamenti teorici ora ci concentreremo sull’esecuzione.

5.1

Regressione lineare

La regressione lineare è implementata nella libreria Scikit-learn, tabella 3.3, per poterla utilizzare è necessario dapprima importare la relativa libreria:

from s k l e a r n . l i n e a r _ m o d e l import L i n e a r R e g r e s s i o n

no_of_adults_older_than_16 565.1427600357491 no_of_kids_younger_than_16 741.1684507714189 no_of_pets 202.546953791628 heat_pump 1391.1521885307036 electric_hot_plates 1052.4576008815611 hi_fi -142.00684889327124 Electricity 1052.8174405824907 Tabella 5.1: Alcuni esempi dei coefficienti

Questa valutazione dei coefficienti è stata eseguita per tutti i dataframe creati, quello più si- gnificativa è stato quello che contiene la somma dei consumi giornalieri in quanto possiede un maggior numero di righe rispetto agli altri, ma più o meno i valori dei coefficienti sono risultati equivalenti per ogni dataframe.

Ora che si conoscono i coefficienti più significativi, verifichiamo con una regressione lineare se sono effettivamente corretti e quanto veramente influenzano sul consumo.

Si realizza una funzione dove viene creato un array X che conterrà i valori delle features scelte e un ulteriore array y che sarà il nostro target, cioè il consumo. Dopodiché dobbiamo splittare questi array per ottenere la X e la y di train per allenare l’algoritmo e la X e la y di test per verificare se l’algoritmo ha lavorato correttamente.

X _ t r a i n , X _ t e s t , Y _ t r a i n , Y _ t e s t = t r a i n _ t e s t _ s p l i t ( X , Y ,

t e s t _ s i z e = 0 . 3 3 , random_state =5) Potrebbe essere che alcune features non siano binarie (es. numero di persone nel nucleo familiare) per questo è buona norma eseguire una standardizzazione1:

ss = S t a n d a r d S c a l e r ( )

X _ t r a i n _ s t d = ss . f i t _ t r a n s f o r m ( X _ t r a i n ) X _ t e s t _ s t d = ss . t r a n s f o r m ( X _ t e s t )

Ora è possibile allenare l’algoritmo e verificare come ha lavorato sul set di test: l l = L i n e a r R e g r e s s i o n ( )

l l . f i t ( X _ t r a i n _ s t d , Y _ t r a i n )

Y _ p r e d _ t e s t = l l . p r e d i c t ( X _ t e s t _ s t d )

Un metodo di valutazione dell’algoritmo è quello di calcolare l’R22che deve risultare almeno più dello 0.3, altrimenti il modello è inutile3.

Seguendo sempre questi passaggi si possono controllare singolarmente o prese in gruppo le features d’interesse, basta modificare l’array X.

Per il progetto sono state fatte sette funzioni per analizzare le features più significative trovate dopo l’analisi dei coefficienti:

regression_with_good_features ’number_of_rooms’, ’water_boiler’, ’heat_pump’, ’microwave’,’freezer’, ’AC’, ’dishwasher’,

’washing_machine_existence’, ’electric_kettle’, ’Electricity’, ’Independent_house’,’Switzerland’, ’Apartment’,

’Energy_saving_light_bulb’, ’gaming_set’, ’Oil’, ’laptop_computer’, ’hi_fi’, ’dehumidifier’,

’tumble_dryer_existence’

regression_with_good_season ’number_of_rooms’, ’water_boiler’, ’heat_pump’, ’microwave”freezer’, ’AC’, ’dishwasher’,

’washing_machine_existence’, ’electric_kettle’, ’Electricity’, ’Independent_house’,’Switzerland’, ’Apartment’,

’Energy_saving_light_bulb’, ’gaming_set’, ’Oil’, ’laptop_computer’, ’hi_fi’, ’dehumidifier’, ’tumble_dryer_existence’,’Summer’,’Winter’ regression_with_good_seasonmix ’number_of_rooms’, ’water_boiler’, ’heat_pump’,

’microwave”freezer’, ’AC’, ’dishwasher’,

’washing_machine_existence’, ’electric_kettle’, ’Electricity’, ’Independent_house’,’Switzerland’, ’Apartment’,

’Energy_saving_light_bulb’, ’gaming_set’, ’Oil’, ’laptop_computer’, ’hi_fi’, ’dehumidifier’,

’tumble_dryer_existence’,’Summer’,’Winter’,’SpringAutumn

regression_heating ’Electricity’, ’Oil’, ’Gas’ regression_building ’Apartment’, ’Independent_house’ regression_domestic ’laptop_computer’, ’hi_fi’, ’dehumidifier’,

’tumble_dryer_existence’, ’microwave’, ’freezer’, ’dishwasher’, ’washing_machine_existence’, ’electric_kettle’

5.2

K-means

Anche l’algoritmo di clustering K-means è già implementato in sklearn:

from s k l e a r n . c l u s t e r import KMeans

Con questo algoritmo si è provato un approccio orientato alla classificazione: conoscendo il target di appartenenza di una certa features, si è provato a vedere se il solo valore del consumo potesse bastare a classificarlo nella giusta categoria.

Per esempio, sono presenti le informazioni sulla nazionalità, quindi si è a conoscenza se quel determinato valore del consumo è di un utente svizzero oppure tedesco.

Con il K-Means si creano 2 cluster e si verifica se l’algoritmo è in grado di riconoscere gli utenti in base alla nazionalità. Lo stesso approccio si è sperimentato con i valori dell’heat pump, del riscaldamento elettrico e del tipo di edifici.

Una volta creati i cluster si è utilizzata una nuova metrica, differente da K-means, per identifi- care il cluster a cui assegnare il dato del nuovo utente. In questo caso si è deciso di utilizzare una Logistic Regression4ma la scelta può variare puntando anche a un più semplice K-NN5.

5.2.1

Creazione classi di consumo

Poiché all’interno dei nostri dataframe non c’è alcuna informazione riguardo la classe di appartenenza di un utente in base al suo profilo, ciò significa che manca il target necessario per la classificazione, bisogna creare questa indicazione.

Per farlo sono stati implementati tre approcci:

1. Creazione delle classi solo in base al consumo, dividendo in modo da avere lo stesso numero di utenti per ogni classe. Questo approccio è il più semplice e anche il più scorretto perché così facendo è molto probabile che gli intervalli dei consumi che dividono le classi siano molto squilibrati. Ad esempio, una classe potrebbe avere un intervallo che parte da 40 e finisce a 50 mentre quella successiva inizia con un consumo di 51 e finisce con un consumo di 210.

2. Creazioni delle classi solo in base al consumo, dividendo in base a un range prefis- sato. Questo approccio è meglio rispetto a quello appena visto ma ha il problema inverso, in una classe è molto probabile avere un numero più elevato di utenti rispetto alle altre. Si può intuire che le classi limiti come quelle con consumi troppo bassi o troppo alti siano le più coinvolte.

equivarranno al numero di cluster per l’algoritmo. Per ogni utente si salva la labels che lo colloca in un certo cluster e quella sarà la sua classe.

Per salvare le informazioni sulle classi appena calcolate sono stati creati altri dataframe, partendo da quelli già illustrati al capitolo 4.3 nella tabella 4.3, aggiungendo la colonna ’Classe’.

5.3

SVM

Come gli altri algoritmi già osservati, anche questo viene già fornito da sklearn:

from s k l e a r n . svm import SVC

Durante il progetto questo algoritmo è stato utilizzato per giungere al completamento del- l’ultimo compito richiesto, quello di classificare i nuovi utenti.

I dataframe da utilizzare sono quelli contenti le informazioni sulla classe, capitolo 5.2.1.

Per questo algoritmo il nostro array X conterrà tutte le informazioni sul profilo dell’utente scartando il consumo e la classe di appartenenza. L’array y, come al solito, sarà il target che in questo caso è la classe.

Il procedimento di split per creare i set di train e di test è il medesimo già illustrato al capitolo 5.1 per l’algoritmo di regressione lineare. L’unica differenza è, naturalmente, l’algoritmo applicato:

s v c l a s s i f i e r = SVC( k e r n e l = ’ l i n e a r ’ , p r o b a b i l i t y =True ) s v c l a s s i f i e r . f i t ( X _ t r a i n , y _ t r a i n )

proba = s v c l a s s i f i e r . p r e d i c t _ p r o b a ( X _ t e s t ) y_pred = s v c l a s s i f i e r . p r e d i c t ( X _ t e s t )

Si è aggiunto il calcolo della probabilità in modo tale da avere un’idea di quanto il classifica- tore si sia sbagliato nel caso di una catalogazione errata.

Per i risultati e i confronti tra le diverse metodologie di creazione delle classi si faccia riferimento al capitolo 6

Documenti correlati