mercoledì 30 dicembre 2009

Mappa dei Social Networks per nazione in R

Come ultimo post dell'anno 2009, ho deciso di presentare alcune funzioni di R che finora non avevo mai trattato, e per fare pratica con i dataframe in R. L'argomento che ho scelto come esempio da analizzare è la popolarità dei Social Network, idea che mi è venuta leggendo questo articolo. Non voglio certo soffermarmi in pensieri e riflessioni su questo genere di siti, essendo l'obiettivo di questo blog l'analisi statistica.
Osservando tutti i grafici presenti nel sito che ho linkato, una domanda viene spontanea: ma in definitiva, qual è il social network più popolare per ciascuna nazione? La risposta a questa domanda è l'argomento di questo post.

Innanzitutto è molto interessante lo strumento messo a disposizione da Google: Google Insights for Search. Pur essendo ancora in versione beta, tramite la semplice interfaccia che da sempre caratterizza il marchio Google, possiamo ottenere molte informazioni riguardanti essenzialmente le query più cercate nel celebre motore di ricerca. Questi dati vengono presentati per nazione, ed ecco perchè questo strumento ci sarà molto utile.

Per prima cosa cerchiamo di ottenere i dati che ci servono: nella spazio di ricerca, scriviamo i nomi dei 12 principali social network che vogliamo confrontare: MySpace, Facebook, Hi5, Friendster, LinkedIn, Orkut, Last.fm, LiveJournal, Xanga, Bebo, Imeem e Twitter. Non dobbiamo far altro che clickare su Search, e quindi sul link Download as a CSV, per ottenere la tabella di dati che ci serve.
In che formato sono i dati relativi alle nazioni? I dati sono stardardizzati: fissato come valore 100 la nazione con più query, a tutte le altre viene assegnato un valore in proporzione (stesso metodo di standardizzazione visto in questo post). Ottenuto il file .CSV, possiamo caricarlo in R, utilizzando questo comando:


social <- read.csv("C:/~/Desktop/report-5.csv", header=T, skip=321, nrows=467-322, sep=";")


Studiamo la sintassi:
- read.csv: funzione adatta proprio per i file in formato .csv di Excel
- "C:/...": path dove è posizionato il file; ricordo che in R vanno usati i backslash (/) al posto degli slash (\) per individuare il percorso di cartelle
- header=T: viene specificato nel file il nome delle colonne
- skip=321: R non deve leggere le prime 321 righe, ma partire dalla 322esima (perchè da questa riga in poi sono posizionati i dati che ci servono
- nrows=467-322: il numero di righe che ci serve arriva fino a 467. Specifichiamo quindi il numero di righe da analizzare a partire dalla 322esima, con la semplice differenza
- sep=";": il simbolo usato per separare, in ogni riga, i valori delle colonne

Ecco come appare il file appena caricato (clickate su View Plain e ingrandite la finestra, per motivi di spazio non entra tutto qui):


social[1:6,]
Region facebook orkut twitter imeem bebo friendster hi5 myspace last.fm linkedin livejournal xanga
1 Turkey 100 0 14 1 0 0 4 3 6 3 0 0
2 Tunisia 97 0 20 1 0 0 4 3 0 16 0 0
3 Croatia 77 0 17 0 0 0 0 10 59 15 2 0
4 Italy 75 0 18 0 0 0 1 13 20 33 3 0
5 Colombia 65 0 15 0 0 0 19 13 14 2 1 0
6 Venezuela 64 0 35 0 0 0 10 6 9 2 1 0
...


A questo punto, caricato il dataframe di dati, dobbiamo individuare per ciascuna nazione (ciascuna riga) il social network principale. Lavorare con i dataframe in R è davvero difficoltoso; la mia soluzione a questo problema è la seguente: per ogni riga andiamo a cercare il valore massimo, e scriviamo tale valore in un'altra colonna aggiunta al dataframe. Quindi confrontiamo la colonna dei massimi con le colonne dei singoli Social Network: quando i due valori coincidono, facciamo scrivere in una seconda colonna aggiunta il nome del Social Network.
Sono sicuro che esistano soluzioni più lineari ed eleganti della mia, che tuttavia funziona a dovere. Per fare questo, dobbiamo utilizzare due funzioni finora mai viste: il ciclo for..to..do, e lo statement if..then..else.

Punto primo: creiamo la colonna max con i massimi valori di ogni riga:


for(i in 1:145){
social$max[i] <- max(social[i, 2:13])}


Studiamo la sintassi:
- for(i in x:y){ codice }: questo è il codice generale del ciclo for..to..do in R. Tra parentesi tonde si sceglie un contatore (i) che assumerà i valori compresi tra i valori specificati x e y. Ad ogni ciclo, i aumenta di una unità, e vengono eseguite le operazioni scritte tra le parentesi graffe. Quando i raggiungerà il valore y (quindi dopo n = y - x cicli), l'operazione si conclude.
- max: è la funzione che sceglie il valore massimo tra i valori scritti tra parentesi. Questi valori sono, per ogni ciclo, le colonne dalla e alla 13 della riga i (dalla riga 1 alla riga 145)
- social$max[i]: questa è la colonna aggiuntiva al nostro dataframe. Per ogni ciclo viene calcolato il valore massimo della riga, e scritto nella posizione i-esima della colonna max del dataframe.

A questo punto il dataframe è il seguente:


social[1:6,]
Region facebook orkut twitter imeem bebo friendster hi5 myspace last.fm linkedin livejournal xanga max
1 Turkey 100 0 14 1 0 0 4 3 6 3 0 0 100
2 Tunisia 97 0 20 1 0 0 4 3 0 16 0 0 97
3 Croatia 77 0 17 0 0 0 0 10 59 15 2 0 77
4 Italy 75 0 18 0 0 0 1 13 20 33 3 0 75
5 Colombia 65 0 15 0 0 0 19 13 14 2 1 0 65
6 Venezuela 64 0 35 0 0 0 10 6 9 2 1 0 64
...


Come vedete è comparsa l'ultima colonna max che riporta il valore massimo di ogni riga.

Punto secondo: adesso dobbiamo dare un nome a questo valore massimo, e queste deve essere scelto da uno dei nomi delle altre colonne (ossia uno dei Social Networks).
Ecco il codice:


for(i in 1:13){
for(k in 1:145){
if(social$max[k]==social[k,i]){social$MaxS[k]=names(social)[i]}
}
}


Il codice è reso un pò più complesso dal fatto che sono concatenati due cicli for e una scelta if. Analizziamo prima il codice if, che in generale si presenta così: if(condizione){ codice }.
Il contatore k è relativo alle righe, mentre il contatore i è relativo alle colonne. La condizione if dice la seguente cosa: considerata una riga k (da 1 a 145) e in particolare il valore della colonna max, quando questo valore è uguale a uno dei valori delle i colonne (confronto con la colonna dalla 2 alle 13), allora alla colonna aggiuntiva MaxS viene dato il nome che è uguale a quello della colonna individuata.
E' difficile da spiegare a parole, ma il risultato è il seguente:


social[1:10]
Region facebook orkut twitter imeem bebo friendster hi5 myspace last.fm linkedin livejournal xanga max MaxS
1 Turkey 100 0 14 1 0 0 4 3 6 3 0 0 100 facebook
2 Tunisia 97 0 20 1 0 0 4 3 0 16 0 0 97 facebook
3 Croatia 77 0 17 0 0 0 0 10 59 15 2 0 77 facebook
4 Italy 75 0 18 0 0 0 1 13 20 33 3 0 75 facebook
5 Colombia 65 0 15 0 0 0 19 13 14 2 1 0 65 facebook
6 Venezuela 64 0 35 0 0 0 10 6 9 2 1 0 64 facebook
7 Albania 52 0 11 0 0 0 11 5 0 0 0 0 52 facebook
8 Bosnia and Herzegovina 52 0 10 0 0 0 1 5 22 0 0 0 52 facebook
9 France 48 0 18 0 0 0 1 15 11 23 3 0 48 facebook
10 United Kingdom 48 3 82 1 23 0 2 35 41 45 12 2 82 twitter
...


E' stata aggiunta la colonna MaxS, con il nome della colonna con valore più alto nel dataframe importato in R.

A questo punto possiamo passare alla fase grafica. Abbiamo già visto in questo post come creare una mappa politica con le varie regioni colorate. Il procedimeto risulterebbe del tutto analogo; potremmo eventualmente utilizzare anche le library maps e maptools, che forniscono alcune mappe come il sito gadm.
Vediamo invece un metodo alternativo per ottenere una mappa delle nazioni, uscendo dal programma R, e utilizzando le Google Chart API.

Questo è uno strumento messo a disposizione da Google, che ci permette di ottenere dei grafici, semplicemente trasformando i nostri dati in un link.
Andiamo a vedere quali dati ci servono, dalla guida fornita da Google:
- elenco delle nazioni in formato ISO 3166-1
- scelta dei colori da utilizzare
- elenco di valori relativi alle nazioni

Cominciamo dall'ultimo punto. Da R a Google Chart non possiamo specificare il nome del Social Network per ciascuna nazione, ma dobbiamo indicarlo sotto forma di numero. Per far questo, estraiamo la colonna MaxS, trasformiamola in un fattore, e quindi nuovamente in un valore numerico relativo. Prima di far questo però, mettiamo il dataframe in ordine alfabetico in base alla colonna Region:


social <- social[order(social$Region),]

social[1:6,]
Region facebook orkut twitter imeem bebo friendster hi5 myspace last.fm linkedin livejournal xanga max MaxS
72 Afghanistan 8 1 0 0 0 0 1 9 0 0 0 0 9 myspace
7 Albania 52 0 11 0 0 0 11 5 0 0 0 0 52 facebook
65 Algeria 9 0 6 0 0 0 0 1 0 7 0 0 9 facebook
127 Angola 2 6 0 0 0 0 16 2 0 0 0 0 16 hi5
29 Argentina 21 1 13 0 0 0 1 2 11 17 2 0 21 facebook
129 Armenia 1 0 0 0 0 0 0 1 0 0 0 0 1 myspace
...

maxx <- social$MaxS
maxx <- factor(maxx)

maxx
...
Levels: bebo facebook friendster hi5 imeem last.fm linkedin livejournal myspace orkut twitter xanga

maxx <- as.numeric(maxx)

maxx[1:10]
[1] 9 2 2 4 2 9 9 6 11 11


All'interno del vettore maxx ciascun valore indica il livello, nell'ordine prima dichiarato. Ad esempio la prima nazione (Afghanistan) ha livello 9, ossia myspace; e così via.
Adesso dobbiamo rapportare a 100 i livelli, perchè nelle Chart di Google occorre specificare un gradiente di valori. Per far questo utilizziamo la funzione di standardizzazione già studiata in questo post:


library(vegan)
maxx <- decostand(maxx, "max")


Essendo rapportato a 1, moltiplichiamo per 100 e arrotondiamo all'unità; quindi trasformiamo in un vettore:


maxx <- maxx*100
maxx <- round(maxx)
maxx <- as.vector(maxx)
maxx[1:6]
[1] 75 17 17 33 17 75


Ovviamente tutti questi comandi possono essere scritti in un'unica riga. Per motivi "didattici", tendo sempre a separare le singole operazioni.

A questo punto abbiamo i valori da assegnare alle nazioni: sono valori numerici perchè come tali devono essere letti da Google, ma in realtà fanno riferimento ai livelli. Ossia abbiamo che i livelli standardizzati a 100 sono: 8 17 25 33 42 50 58 67 75 83 92 100, che si riferiscono, ciascuno, ai social networks nell'ordine che ho scritto prima.

Ora dobbiamo cercare i codice ISO 3166-1 per ciascuna nazione: ecco il link con la tabella. Trascriviamo ciascun codice per le nazioni che consideriamo, in ordine alfabetico.
Scegliam infine i colori: possiamo decidere di creare un gradiente di colori (Google calcola automaticamente quanti step inserire tra i colori specificati di inizio e fine, tanti quanti sono i livelli), oppure possiamo scegliere 12 colori diversi a nostro piacimento. Utilizziamo ad esempio la seguente sequenza di colori:
- F57DC3 (█ bebo ),
- 54F615 (█ facebook ),
- D14BC7 (█ friendster ),
- 3772E0 (█ hi5 ),
- CD012B (█ imeem ),
- F15239 (█ last.fm ),
- 06D197 (█ linkedin ),
- 7787F0 (█ livejournal ),
- 631E2A (█ myspace ),
- 8AAB5E (█ orkut ),
- C87E99 (█ twitter ),
- FF119B (█ xanga)

Siamo ora in possesso di tutte le informazioni necessarie per creare il grafico con le Google API Chart. Il codice è il seguente:


http://chart.apis.google.com/chart?
cht=t&
chs=440x220&
chtm=world&
chco=FFFFFF,F57DC3,54F615,D14BC7,3772E0,CD012B,F15239,06D197,7787F0,631E2A,8AAB5E,C87E99,FF119B&
chld=AFALDZAOARAMAUATAZBDBYBEBJBOBABWBRBGBFBIKHCMCATDCLCNCOCRCIHRCUCZDKDOECEGSVEREEETFJFIFRGAGMGEDEGHGRGTGNHTHNHKHUINIDIRIQIEILITJMJPJOKZKEKWKGLALVLBLSLYLTMKMGMWMYMLMRMUMXMDMNMAMZMMNANPNLNZNINENGNOOMPKPSPAPGPYPEPHPLPTPRRORURWSASNSLSGSKSIZAKPESLKSDSZSECHSYTWTZTHTGTTTNTRTMUGUAAEGBUSUYUZVEVNYEZMZW&
chd=t:75,17,17,33,17,75,75,50,92,92,67,58,33,17,17,92,92,50,33,17,17,33,92,33,17,92,17,33,17,17,92,50,58,33,33,17,33,17,50,92,8,50,17,17,17,75,50,92,17,33,33,83,33,100,50,58,25,92,92,8,58,17,92,92,17,67,92,92,17,33,50,92,17,17,50,17,17,17,25,17,17,17,92,67,33,17,33,92,17,92,58,92,33,33,92,50,58,58,17,17,17,83,33,25,50,33,75,33,67,17,58,92,17,67,50,50,92,92,50,17,17,17,50,50,92,92,92,42,17,92,17,17,17,92,67,58,92,75,17,17,17,92,17,92,92&
chf=bg,s,EAF7FE


Analizziamolo, come di consueto (ciascun parametro è separato dal successivo da una e-commerciale &):
- link alle API
- cht: tipo di grafico (in questo caso una mappa)
- chs: dimensioni (per questo tipo di grafico, purtroppo, le dimensioni massime sono quelle indicate)
- chtm: quale mappa visualizzare
- chco: sequenza di colori da utilizzare; il primo colore è il bianco, quello dei territori non scelti;
- chld: elenco senza spazi o separatori, dei codici ISO delle nazioni da colorare
- chd=t:: elenco dei livelli di colore. Ad esempio la prima nazione (AF, Afghanistan) ha livello 75, che è il nono tra i possibili valori; quindi verrà colorato col nono colore specificato; e così via
- chf: colore del mare e background

Il risultato è il seguente:



Mappa ingrandita con i comandi width e height del codice HTML:



La mappa è molto piccola, ma il formato che Google mette a disposizione è solo questo; nonostante ciò ho utilizzato questo strumento per "imparare qualcosa di nuovo". Possiamo verificare la corretteza dei colori, usando la legenda che ho scritto sopra e richiamando il dataframe social da leggere.
Se qualche lettore vuole divertirsi a ottenere questa stessa mappa con il metodo descritto nel mio post precedente, sarò ben felice di caricare qui la sua immagine :)

Spero di non aver fatto errori, ma stavolta il codice da usare era davvero tanto!!

Felice anno nuovo a tutti!!

EDIT: Google Chart interpreta male i colori. Sebbene siano correttamente posizionati, non rispettano quelli della legenda di sopra. Non appena riesco a individuare l'errore, correggerò il post.

EDIT n°2: Ho scoperto di recente un'altra fantastica api di google. Si tratta di Google Fusion Table. Accedendo con l'account Google, è possibile caricare i propri file Excel, e visualizzarli con i più comuni strumenti grafici, come istogrammi, grafici a torta, eccetera. Tra questi, è anche disponibile la visualizzazione della mappa, che potete vedere qui sotto.
A seguito dell'analisi che abbiamo fatto, ho creato una tabella contenente un numero corrispondente a ciascun social network in base all'ordine sempre utilizzato (quindi bebo ha valore 1, facebook ha valore 2, e così via). Spostandovi col mouse, potete vedere per ciascuna nazione qual è il social network più utilizzato.



P.S. Non chiedetemi come mai al posto di comparire "USA" a volte compaia "Georgia"!! :)


6 Commenti:

Anonimo ha detto...

Ciao,
Google Insights for Search non mi accetta più di 6 termini di ricerca, tu come hai fatto ad inserirne 12? grazie. ottimo blog ;)

Todos Logos ha detto...

Ciao,
io ho fatto così: primo file excel con i dettagli dei primi 6 siti (il primo campo era facebook); poi secondo file excel con altri 5 (più il primo campo sempre facebook, così da avere lo stesso ordine delle nazioni); poi un terzo file (mi pare fossero 3 in tutto), sempre con il primo campo uguale agli altri due file.
Poi da questi copi le colonne di tuo interesse in un unico file .csv, e cominci l'analisi
:)

Pino M ha detto...

ciao, mi sa che dal sito gadm.org sia possibile prendere le mappe in formato R solo per le nazioni e non per il mondo intero. peccato ci volevo provare.

Todos Logos ha detto...

Hai ragione Pino, ho appena controllato e non ci sono. E' un vero peccato!
Ad ogni modo, puoi comunque provare ad utilizzare la world map delle library maps e maptools (anche se sinceramente non mi piacciono come sono disegnate).

Oppure, altra soluzione, puoi importare in R una mappa in formato SVG come quelle usate su WikiPedia (su Google mi sembra di aver trovato una guida, prova a cercare "SVG in R"), anche se così la faccenda si complica un po'.
Se riesci a risolvere qualcosa, fammi sapere mi raccomando :D

Pino M ha detto...

grazie Todos vedrò di racapezzarci qualcosa, ti volevo poi chiedere ma su gadm le differenze tra level 1, level 2 e level 3 in cosa consistono? per caso suddivisione in regione, province e comuni? ciao

Todos Logos ha detto...

Esatto, Pino, è proprio quella la differenza tra le varie mappe :)

Posta un commento

Statistiche... del blog!

In questo blog ci sono posts e commenti.

Visualizzazioni totali (dal 01.06.2010)

Follow me on...