INTRODUZIONE A R
Lezione 2
Silvia Bacci∗e Silvia Pandolfi†
1
Importare e esportare i dati
Quando la mole di dati è sostanziosa l’immissione da tastiera non è agevole. La situazione
più comune è che i dati vengano inseriti a partire da file esterni. R è in grado di leggere
dati in praticamente qualsiasi formato1 .
Per leggere dati da file R fornisce numerose funzioni, tra le quali read.table() e
read.csv() che permettono di caricare file di testo .txt e .csv (comma separated value).
Questi file possono utilizzare differenti separatori di colonna; i principali sono la virgola,
il punto e virgola e la tabulazione. Nel caricare i dati in R occorre prestare attenzione a
quale separatore viene utilizzato nel file.
> read.table("percorso/file.txt", header = TRUE, sep = " \t", dec = ".")
> read.table(file.choose())
Andiamo ad analizzarne gli argomenti:
• file.choose(): permette di aprire una finestra di navigazione in cui selezionare il
file d’interesse;
• header = TRUE: identifica la prima riga della matrice dei dati come quella contenente i nomi delle variabili;
• sep = "," specifica il tipo di separatore di colonna. Tra virgolette potremmo perciò
inserire la virgola, il punto e virgola e per la tabulazione \t .
> data = read.table("var_qualitative.txt",header=TRUE)
>#Visualizza in maniera compatta la struttura di un oggetto
> str(data)
’data.frame’: 500 obs. of 5 variables:
$ eta
: int 78 26 57 30 23 32 80 60 75 55 ...
$ sesso
: Factor w/ 2 levels "F","M": 1 1 1 1 2 1 2 1 1 2 ...
$ titolo_studio: Factor w/ 4 levels "Diploma","Laurea",..: 3 3 1 4 1 1 2 2 4 3 ...
$ reddito
: num 66.7 29.5 50.6 39.6 30.2 ...
∗
[email protected]
[email protected]
1
Tramite il pacchetto foreign, R è in grado di leggere e salvare dati in formati provenienti da altri
programmi di analisi statistica, come Stata, SPSS e SAS.
†
1
$ anni_lavoro
: int
15 6 15 10 3 11 19 14 17 15 ...
> #Mostra solo le prime sei righe della matrice dei dati
> head(data)
>#Restituisce il nome delle variabili della matrice
> names(data)
> sesso
Errore: oggetto "sesso" non trovato
> attach(data)
> sesso
> data$sesso
> data[ ,2]
I file con estensione .csv sono particolari tipi di documenti di testo che possono essere letti
e salvati con Excel.
> #Caricare il dataset DATI.csv
> data2 = read.csv(file.choose(), header = TRUE, sep = ",")
> head(data2)
Sesso Diploma Regione Libri Cellulare Fumatore Parrucchiere Caffe Famiglia Altezza
1
F
LS Umbria
3 Da 0 a 10
Si
0
8
5
165
2
M
LS Umbria
1 Da 20 a 50
No
20
1
3
178
3
F
COM Umbria
0 Da 0 a 10
No
40
0
5
165
4
M
LC Centro
2 Da 10 a 20
Si
20
3
3
183
5
M
LS Umbria
0 Da 20 a 50
Si
27
1
4
170
6
F
COM Umbria
2 Da 10 a 20
Si
30
4
4
170
> str(data2)
’data.frame’: 138 obs. of 10 variables:
$ Sesso
: Factor w/ 2 levels "F","M": 1 2 1 2 2 1 1 2 1 1 ...
$ Diploma
: Factor w/ 4 levels "Altro","COM",..: 4 4 2 3 4 2 4 2 2 1 ...
$ Regione
: Factor w/ 3 levels "Centro","Sud",..: 3 3 3 1 3 3 3 1 3 3 ...
$ Libri
: int 3 1 0 2 0 2 1 2 1 1 ...
$ Cellulare
: Factor w/ 5 levels "0","Da 0 a 10",..: 2 4 2 3 4 3 2 2 2 2 ...
$ Fumatore
: Factor w/ 2 levels "No","Si": 2 1 1 2 2 2 2 2 2 1 ...
$ Parrucchiere: int 0 20 40 20 27 30 15 18 50 0 ...
$ Caffe
: int 8 1 0 3 1 4 0 3 2 2 ...
$ Famiglia
: int 5 3 5 3 4 4 4 4 4 4 ...
$ Altezza
: int 165 178 165 183 170 170 160 172 155 160 ...
Per esportare un data frame o una matrice su un file in R è disponibile la funzione
> write.table(data2, file="prova.xls",sep="\t",dec=",", row.names = FALSE)
1.1
I pacchetti in R
Le funzioni di R sono organizzate in pacchetti, i più importanti dei quali sono già disponibili quando si accede al programma. Alcuni pacchetti, pur essendo presenti nella release
di base di R, devono essere caricati durante la sessione di lavoro, mediante il comando:
2
> require(nomepacchetto)
> library(nomepacchetto)
Per sapere quali sono i pacchetti già presenti nella release di R con cui si sta lavorando,
basta scrivere:
> library()
In alternativa, dal menu “Pacchetti” si sceglie l’opzione “Carica pacchetto”. In tal
caso apparirà una finestra con la lista dei pacchetti già installati. Sarà quindi sufficiente
selezionare il nome del pacchetto da caricare con il mouse e poi cliccare su ”OK”.
Per avere informazioni sul pacchetto e sulle funzioni in esso contenute:
> help(package = "nomepacchetto")
Alcuni pacchetti non sono invece presenti nella release di base di R. Per installare un
pacchetto non presente, è sufficiente scrivere:
> install.packages("nomepacchetto")
La prima volta che si usa questa funzione durante una sessione di lavoro si dovrà anche
selezionare da una lista il sito mirror da cui scaricare il pacchetto.
In alternativa, nel menu “Pacchetti” si seleziona “Installa pacchetti” e, successivamente, si seleziona il pacchetto dalla lista di tutti i pacchetti.
1.2
>
>
>
>
Importare i dati da un file di Excel
install.packages("gdata")
library(gdata)
# carica il pacchetto gdata
help(read.xls)
mydata = read.xls("sweat.xls", sheet=1) # legge dal primo foglio di lavoro
1.3
Esercizi
Dopo aver caricato il dataset DATI.csv:
• Estrarre l’altezza degli studenti umbri; qual è l’altezza dello studente più basso e
quella dello studente più alto?
• Calcolare la spesa complessiva per il parrucchiere degli studenti maschi provenienti
dal Sud Italia.
• Estrarre l’altezza degli studenti in base al sesso
• Estrarre il numero di libri letti dagli studenti dei licei
3
2
Introduzione all’analisi dei dati
Quando si svolge un’analisi statistica dei dati è necessario procedere prima con un’analisi
di tipo esplorativo per capire la struttura generale delle variabili che compongono l’insieme
di dati e successivamente con una serie di analisi di tipo descrittivo per la comprensione
dei fenomeni studiati. Solo dopo queste prime due fasi ha senso procedere ad analisi più
approfondite di natura inferenziale.
2.1
Manipolazione dei dati (etichette, ricodifiche, creazione nuove
variabili)
Per prima cosa carico i dati:
> # importo i dati
> dati <- read.table(famiglia2.txt, header = TRUE)
Come introdotto in precedenza, con la funzione dim ottengo la dimensione del mio dataset,
con il numero di righe corrispondente al numero di individui e il numero di colonne
corrispondente al numero di variabili:
> dim(dati)
[1] 100
5
Successivamente, posso utilizzare le due funzioni str e head per ottenere una descrizione delle variabili contenute in dati:
> # visualizzo le prime righe (= individui) del dataset
># e tutte le colonne (= variabili)
> head(dati)
X1
X2 X3 X4
X5
1 1 17.695 3 1 9.549
2 2 21.510 3 1 10.062
3 3 27.602 1 1 5.089
4 4 36.846 3 0 10.137
5 5 23.252 1 0 4.343
6 6 20.496 1 0 3.991
> # ottengo informazioni sulla natura delle variabili
> str(dati)
’data.frame’: 100 obs. of 5 variables:
$ X1: int 1 2 3 4 5 6 7 8 9 10 ...
$ X2: num 17.7 21.5 27.6 36.8 23.3 ...
$ X3: int 3 3 1 3 1 1 3 1 3 2 ...
$ X4: int 1 1 1 0 0 0 0 1 0 0 ...
$ X5: num 9.55 10.06 5.09 10.14 4.34 ...
I nomi delle variabili sono visualizzabili tramite:
> names(dati)
[1] "X1" "X2" "X3" "X4" "X5"
4
Spesso è utile modificare i nomi originari delle variabili:
> # cambio i nomi delle variabili
> names(dati) <- c("id","reddito","numcomp","sesso","spesaal")
> head(dati)
> # oppure, in fase di lettura dei dati:
> dati2 <- read.table(file.choose(), header = TRUE,
+ col.names=c("id","reddito","numcomp","sesso","spesaal"))
> attach(dati2)
> str(dati2)
’data.frame’: 100 obs. of 5 variables:
$ id
: int 1 2 3 4 5 6 7 8 9 10 ...
$ reddito: num 17.7 21.5 27.6 36.8 23.3 ...
$ numcomp: int 3 3 1 3 1 1 3 1 3 2 ...
$ sesso : int 1 1 1 0 0 0 0 1 0 0 ...
$ spesaal: num 9.55 10.06 5.09 10.14 4.34 ...
Non sempre le variabili originarie presenti nel dataset sono utili ai fini delle analisi che
vogliamo svolgere. Può essere necessario ricorrere a delle manipolazioni particolari, quali
ridefinizione della natura della variabile, creazione di nuove etichette per le modalità della
variabile, definizione di nuove variabili a partire da variabili già esistenti.
> ## Trasformo la variabile sesso, vista come intero, in un fattore
> is.factor(sesso)
[1] FALSE
> levels(sesso)
NULL
> sesso<-as.factor(sesso)
> levels(sesso)
[1] "0" "1"
> # creare le etichette per i livelli di sesso (0=maschio, 1=femmina)
> levels(sesso) <- c("maschio","femmina")
> is.numeric(reddito)
> # Indago sulla presenza di eventuali risposte mancanti:
> is.na(reddito)
> is.na(dati2)
>
>
>
>
>
# Creo una variabile aggregata da numcomp
# (max 1 componente oltre al capofamiglia, 2-3, almeno 4)
sort(numcomp)
numcomp2 = 0 + (numcomp>1) + (numcomp>3)
table(numcomp,numcomp2)
>
>
>
>
# Creo tre dummy dalla variabile numcomp2
n = nrow(dati2)
numcomp3 = matrix(0,n,3)
numcomp3[cbind(1:n, numcomp2+1)]=1
5
> cbind(numcomp2, numcomp2+1, numcomp3)
> # Alternativa (modo meno parsimonioso!!)
> numcomp4 = matrix(0,n,3)
> for (i in 1:n){
if (numcomp2[i]==0) {
numcomp4[i,1] = 1
}
if (numcomp2[i]==1) {
numcomp4[i,2] = 1
}
if (numcomp2[i]==2) {
numcomp4[i,3] = 1
}
}
> # Aggiungo le due nuove variabili ai dati
> dati2 = cbind(dati2, numcomp2, numcomp3)
> names(dati2)[7:9] <- c("0-1 comp", "2-3 comp", "almeno 4 comp")
> # ordinare i dati in senso ascendente per la variabile numcomp
> ?order
> dati2[order(numcomp), ]
2.2
Analisi descrittiva dei dati
In R ci sono diverse funzioni per l’analisi descrittiva dei dati. Tra le più utilizzate, alcune
sono state introdotte nelle precedenti sezioni (mean(), median(), sd(), length(), sum()).
Altre funzioni utili sono:
• var(): calcola la varianza di un vettore di dati, la covarianza tra due vettori, o la
matrice di varianze e covarianze di una matrice di dati
• cor(): calcola la correlazione tra due vettori, o la matrice di correlazione di una
matrice di dati
• summary(): riporta le principali statistiche descrittive di un vettore o di una matrice
di dati
• prod(): restituisce il prodotto tra gli elementi di un vettore o di una matrice
• cumsum(): restituisce la somma cumulata degli elementi di un vettore
• cumprod(): restituisce il prodotto cumulato degli elementi di un vettore
• quantile(): calcola i quantili di una distribuzione
• colMeans() - rowMeans(): calcola le medie di diverse variabili all’interno di un
dataset (per colonna o per riga)
6
Inoltre, la funzione sample() genera un vettore estraendo da un altro oggetto gli elementi
in ordine casuale.
> y=1:10
> sample(y)
[1] 5 9 2 7 3 1 10 8 6 4
> sample(1:90,size=1)
[1] 53
> sample(y,size=20,replace=TRUE)
[1] 8 1 6 1 6 8 9 4 2 6
5
2
7
9 10 10
7
3
7
5
Con riferimento alla variabile reddito dei dati famiglia2.txt, vediamo di seguito
alcune analisi descrittive base:
> summary(dati2)
id
reddito
numcomp
sesso
Min.
: 1.00
Min.
:10.89
Min.
:0.00
Min.
:0.00
1st Qu.: 25.75
1st Qu.:19.87
1st Qu.:1.00
1st Qu.:0.00
Median : 50.50
Median :25.59
Median :2.00
Median :0.00
Mean
: 50.50
Mean
:27.28
Mean
:1.97
Mean
:0.25
3rd Qu.: 75.25
3rd Qu.:34.43
3rd Qu.:3.00
3rd Qu.:0.25
Max.
:100.00
Max.
:54.78
Max.
:5.00
Max.
:1.00
> summary(reddito)
Min. 1st Qu. Median
Mean 3rd Qu.
Max.
10.89
19.87
25.60
27.28
34.43
54.78
> range(reddito)
[1] 10.890 54.781
> mean(reddito)
[1] 27.28431
> median(reddito)
[1] 25.595
> quantile(reddito, probs=c(0.10,0.25,0.75, 0.90))
10%
25%
75%
90%
14.47210 19.86625 34.43275 41.55800
> var(reddito)
[1] 101.4713
2.3
spesaal
Min.
: 1.366
1st Qu.: 5.680
Median : 7.915
Mean
: 8.016
3rd Qu.:10.113
Max.
:15.995
Distribuzioni di frequenza semplici e doppie
Uno strumento molto utile della statistica descrittiva è rappresentato dalle tabelle di
frequenza semplici e doppie. Nel caso delle frequenze assolute la funzione principale che
si utilizza è table.
> # Tabelle delle frequenze di una sola variabile
> table(sesso)
sesso
maschio femmina
75
25
> table(numcomp2)
7
numcomp2
0 1 2
37 57 6
> table(numcomp2)/nrow(dati2)
numcomp2
0
1
2
0.37 0.57 0.06
> # Tabelle doppie di frequenza
> tab1 <- table(sesso,numcomp2)
> tab1
numcomp2
sesso
0 1 2
maschio 25 45 5
femmina 12 12 1
# tabella delle frequenze assolute
> addmargins(tab1, FUN=sum) # aggiungo i totali di riga e colonna
Margins computed over dimensions
in the following order:
1: sesso
2: numcomp2
numcomp2
sesso
0
1
2 sum
maschio 25 45
5 75
femmina 12 12
1 25
sum
37 57
6 100
Le corrispondenti tabelle delle frequenze relative o proporzioni si ottengono tramite la
funzione prop.table.
> # tabelle delle frequenze relative congiunte
> tab2 <- prop.table(tab1, margin=NULL)
> addmargins(tab2, FUN=sum)
Margins computed over dimensions
in the following order:
1: sesso
2: numcomp2
numcomp2
sesso
0
1
2 sum
maschio 0.25 0.45 0.05 0.75
femmina 0.12 0.12 0.01 0.25
sum
0.37 0.57 0.06 1.00
> prop.table(tab1, margin=NULL)*100
numcomp2
sesso
0 1 2
maschio 25 45 5
femmina 12 12 1
# tabella delle frequenze percentuali
8
Per le tabelle a doppia entrate si possono definire anche le distribuzioni di frequenza
condizionate rispetto ad una variabile attraverso l’argomento margin. Se margin =1 si
ottiene la distribuzione condizionata rispetta alla variabile sulle righe, se margin=2 si
ottiene la condizionata rispetto alla variabile sulle colonne.
> # tabelle delle frequenze condizionate rispetto al sesso
> # (o frequenze relative di riga)
> prop.table(tab1, margin=1)
numcomp2
sesso
0
1
2
maschio 0.33333333 0.60000000 0.06666667
femmina 0.48000000 0.48000000 0.04000000
> # tabella delle frequenze condizionate rispetto al numero di
> #†componenti (o frequenze relative di colonna)
> prop.table(tab1, margin=2)
numcomp2
sesso
0
1
2
maschio 0.6756757 0.7894737 0.8333333
femmina 0.3243243 0.2105263 0.1666667
> # test di indipendenza Chi-quadrato (attenzione al Warning!)
> chisq.test(sesso,numcomp2)
Pearson’s Chi-squared test
data: sesso and numcomp2
X-squared = 1.786, df = 2, p-value = 0.4094
Warning message:
In chisq.test(sesso, numcomp2) : Chi-squared approximation may be incorrect
2.4
Le funzioni apply(), tapply(), e aggregate()
Nell’analisi descrittiva dei dati è spesso utile calcolare una o più misure di sintesi (media,
mediana, varianza, ecc.) in presenza di variabili classificazioni e organizzare i risultati in
una tabella doppia. A questo proposito non esiste un metodo intuitivo in R per questo
tipo di analisi, contrariamente ad altri software di analisi statistica dei dati. Le funzioni
maggiormente adatte a tale scopo sono le seguenti:
• apply(X,dim,FUN): permette di calcolare una generica funzione sulle righe o sulle
colonne di una matrice di dati (o su una combinazione di dimensioni di un array
multidimensionale)
• tapply(x,INDEX,FUN), aggregate(X,by,FUN) e by(X,INDICES,FUN): se nel data
frame sono presenti variabili di classificazione, permettono di calcolare una funzione
separatamente su ciascuna classe di unità. tapply si applica ad un singolo vettore,
aggregate ad una matrice di dati. In aggregate, by è una lista, anche composta
9
da un solo oggetto, di variabili di classificazione. Simile ad aggregate è la funzione
by.
> # Mediane di reddito e spesa alimentare
> valori=cbind(reddito,spesaal)
> apply(valori,2,median)
reddito spesaal
25.59500 -0.10055
> # Reddito medio per sesso del capofamiglia
> tapply(reddito,sesso,mean)
maschio femmina
27.85677 25.56692
> # oppure
> aggregate(reddito, by=list(sesso), FUN=mean)
Group.1
x
1 maschio 27.85677
2 femmina 25.56692
> # Reddito medio per sesso del capofamiglia e numero componenti famiglia
> aggregate(reddito, by=list(sesso, numcomp2), FUN=mean)
Group.1 Group.2
x
1 maschio
0 28.17836
2 femmina
0 26.02675
3 maschio
1 27.52622
4 femmina
1 23.79192
5 maschio
2 29.22380
6 femmina
2 41.34900
> # oppure
> tab3 <- by(reddito, INDICES=list(sesso, numcomp2), FUN=mean)
>
>
>
>
>
# Dispongo i dati di tab3 in una tabella
tab3_new<- cbind(tab3[1:2],tab3[3:4],tab3[5:6])
colnames(tab3_new)=c(0, 1, 2)
rownames(tab3_new)=c(’maschio’,’femmina’)
tab3_new
0
1
2
maschio 28.17836 27.52622 29.2238
femmina 26.02675 23.79192 41.3490
> # Mediana di reddito e spesa alimentare per sesso e numero di componenti
> aggregate(valori,by=list(sesso, numcomp2), FUN=median)
Group.1 Group.2 reddito spesaal
1 maschio
0 23.8090 -3.41655
2 femmina
0 25.8390 -2.92555
3 maschio
1 26.1780 1.37645
4 femmina
1 22.3325 1.57745
5 maschio
2 35.6590 6.70645
10
6 femmina
2.5
2 41.3490
7.11045
Variabili in classi
Caricare il file DATI.csv e nominarlo dati.studenti. Vogliamo costruire una variabile
contenente l’altezza degli studenti suddivisa in classi. Il comando da utilizzare è cut(),
che suddivide l’intero range della variabile quantitativa in base a dei breaking-point specificati dall’utente. Per tale motivo è utile conoscere il campo di variazione della variabile
(comando range()).
> dati.studenti=read.csv(file.choose(),header=T,sep=",")
> head(dati.studenti)
Sesso Diploma Regione Libri Cellulare Fumatore Parrucchiere Caffe Famiglia Altezza
1
F
LS Umbria
3 Da 0 a 10
Si
0
8
5
165
2
M
LS Umbria
1 Da 20 a 50
No
20
1
3
178
3
F
COM Umbria
0 Da 0 a 10
No
40
0
5
165
4
M
LC Centro
2 Da 10 a 20
Si
20
3
3
183
5
M
LS Umbria
0 Da 20 a 50
Si
27
1
4
170
6
F
COM Umbria
2 Da 10 a 20
Si
30
4
4
170
> alt.class=cut(dati.studenti$Altezza,breaks=c(150,165,170,175,180,190))
> alt.class
[1] (150,165] (175,180] (150,165] (180,190] (165,170] (165,170] (150,165]
[11] (165,170] (180,190] (150,165] (150,165] (165,170] (165,170] (165,170]
[21] (150,165] (175,180] (150,165] (150,165] (165,170] (165,170] (150,165]
[31] (180,190] (170,175] (175,180] (150,165] (150,165] (165,170] (150,165]
[41] (180,190] (150,165] (170,175] (180,190] (150,165] (170,175] (170,175]
[51] (150,165] (150,165] (150,165] (170,175] (170,175] (150,165] (180,190]
[61] (150,165] (150,165] (150,165] (170,175] (175,180] (165,170] (180,190]
[71] (165,170] (165,170] (150,165] (175,180] (170,175] (170,175] (180,190]
[81] (170,175] (150,165] (170,175] (175,180] (175,180] (180,190] (165,170]
[91] (170,175] (150,165] (150,165] (170,175] (150,165] (170,175] (165,170]
[101] (165,170] (165,170] (150,165] (150,165] (175,180] (170,175] (165,170]
[111] (170,175] (150,165] (150,165] (150,165] (150,165] (150,165] (180,190]
[121] (150,165] (165,170] (180,190] (175,180] (180,190] (165,170] (175,180]
[131] (165,170] (165,170] (165,170] (165,170] (150,165] (180,190] (150,165]
Levels: (150,165] (165,170] (170,175] (175,180] (180,190]
> table(dati.studenti$Sesso,alt.class)
Nell’argomento break si possono specificare gli estremi delle classi come sopra, (notare
che le classi non hanno ampiezze uguali), oppure il numero di classi desiderate. In questo
caso R produce classi equidistanti
> #5 classi di ampiezza uguale
> alt.class=cut(dati.studenti$Altezza,breaks=5)
11
...
...
...
...
...
...
...
...
...
...
...
...
...
...
Per default il comando cut() chiude le classi a destra; con right=FALSE si possono
chiudere le classi a sinistra.
2.6
Esercizi
Da dataset DATI.csv si costruisca la tabella di contingenza delle variabili Sesso e Parrucchiere,
dividendo la variabile Parrucchiere in classi [0 − 15), [15 − 20), [20 − 35), [35 − 150)
(chiusura a sinistra). Fra gli studenti che spendono [20 − 35) euro dal parrucchiere,
quant’è la percentuale dei maschi? Fra le femmine, qual’è la percentuale di quelle che
spendono più di 35 euro?
Quant’è la proporzione di studenti che prendono più di 4 caffè al giorno?
12