-
Notifications
You must be signed in to change notification settings - Fork 2
/
10-factors.Rmd
350 lines (231 loc) · 14.4 KB
/
10-factors.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# Fattori {#factor}
```{r settings, echo = FALSE}
knitr::opts_chunk$set(
echo = FALSE,
collapse=TRUE,
fig.align="center"
)
library(kableExtra)
```
In questo capitolo vedremo i *fattori*, una speciale tipologia di vettori utilizzata per salvare informazioni riguardanti una variabile categoriale (nominale o ordinale). Tuttavia, prima di introdurre i fattori, descriveremo che cosa sono gli attributi di un oggetto. Questi ci permetteranno successivamente di capire meglio il funzionamento dei fattori.
## Attributi di un Oggetto {#attributes}
In R, gli oggetti possiedono quelli che sono definiti *attributi*, ovvero delle utili informazioni riguardanti l'oggetto stesso, una sorta di *metadata*. Queste informazioni non interferiscono con i valori contenuti negli oggetti nè vengono normalmente mostrati nell'output di un oggetto. Tuttavia, si rivelano particolarmente utili in alcune circostanze e permettono di fornire speciali informazioni associate ad un determinato oggetto.
Gli oggetti possiedono diversi attributi a seconda della loro tipologia. Tuttavia, tra quelli principalmente usati troviamo:
- **Classe** (`class`) - la classe (o tipologia) di un oggetto. Ci permette di verificare la tipologia di struttura dati di un particolare oggetto.
- **Nomi** (`names`) - nomi degli elementi di un oggetto. Permette ad esempio di assegnare dei nomi agli elementi un vettore o alle righe e colonne di una matrice o dataframe.
- **Dimensione** (`dim`) - la dimensione dell'oggetto. Questo attributo non è disponibile per i vettori ma sarà particolarmente importante nel caso delle matrici e dataframe.
Per valutare ee eventualmente modifiacare gli attributi di un oggetto esistono delle specifiche funzioni dedicate. Ad esempio abbiamo:
- `attributes()` - elenca tutti gli attributi di un oggetto
- `class()` - accede all'attributo `class` di un oggetto
- `names()` - accede all'attributo `names` di un oggetto
- `dim()` - accede all'attributo `dim` di un oggetto
Vediamo ora alcuni utilizzi degli attributi con i vettori. Gli attributi nel caso delle altre tipologie di oggetti, invece, saranno trattati nei rispettivi capitoli.
### Attributi di un Vettore
Vediamo come inizialmente un generico vettore non possiede alcun attributo vettore.
```{r, echo = TRUE}
my_vector <- 1:10
attributes(my_vector)
```
#### Classe {-}
Eseguendo la funzione `class()`, tuttavia, otteniamo comunque la precisa tipologia di vettore, nel presente caso `"integer"`.
```{r, echo = TRUE}
class(my_vector)
```
#### Dimensione {-}
Abbiamo anticipato come l'attributo `dim` non sia disponibile per i vettori, mentre diverrà molo importante nel caso di matrici e dataframe. Tuttavia un analogo valore della dimensione di un vettore è dato dalla sua lunghezza, valutata con la funzione `length()`.
```{r}
dim(my_vector)
length(my_vector)
```
#### Nomi Elementi{-}
Inizialmente gli elementi di un vettore non possiedono nomi.
```{r, echo = TRUE}
names(my_vector)
```
Per impostare i nomi degli elementi, sarà quindi necessario assegnare a `names(nome_vettore)` un vettore di caratteri, contenente i nomi desiderati, della stessa lunghezza del vettore che stiamo rinominando.
```{r, echo = TRUE}
names(my_vector) <- paste0("Item_", 1:10)
my_vector
```
Questa procedura ci pemette di ottenere quello che viene definito un *named vector*. Possiamo vedere come i nomi degli elementi compaiano ora tra gli attributi dell'oggetto.
```{r}
attributes(my_vector)
```
:::{.trick title="Selezione Named Vectors" data-latex="[Selezione Named Vectors]"}
Una particolare utlizzo dei named vectors riguarda la selezione dei valori tramite i nomi degli elementi. Nota che per un corretto funzionameto è necessario che tutti gli elementi possiedano nomi differenti.
```{r, echo = TRUE}
my_vector[c("Item_3", "Item_5")]
```
Nel caso dei vettori questo approccio è raramente utilizzato mentre vedremo che sarà molto comune per la selezione delle variabili di un dataframe.
:::
## Fattori
I fattori sono quindi una speciale tipologia di vettori che, attraverso l'uso degli attributi, permettono di salvare in modo efficiente le variabili categoriali (nominali o ordinali). Il comando usato per creare un fattore in R è `factor()` e contiene diversi argomenti:
```{r, eval=FALSE, echo=TRUE}
nome_fattore <- factor(x, levels = , ordered = FALSE)
```
- `x` - i dati della nostra variabile categoriale
- `levels`- i possibili livelli della nostra variabile categoriale
- `ordered` - valore logico che indica se si tratta di una variabile nominale (`FALSE`) o ordinale (`TRUE`)
Ad esempio potremmo creare la variabile `colore_occhi` in cui registrare il colore degli occhi dei membri di una classe:
```{r, echo = TRUE}
# Creo i dati
my_values <- rep(c("verde", "marrone", "azzurro"), times = 3)
my_values
# Creo il fattore
my_factor <- factor(my_values)
my_factor
```
Nota come non sia necessario specificare l'argomento `levels`. I livelli della variabile, infatti, vengono determinati automaticamente a partire dai dati presenti e ordinati in ordine alfabetico. Tuttavia, specificare i livelli nella creazione di un fattore ci permette di definire a piacere l'ordine dei livelli ed anche includere eventuali livelli non presenti nei dati.
### Funzionamento Fatori
Cerchiamo ora di capire meglio la struttura dei fattori e l'utilizzo degli attributi.
```{r, echo = TRUE}
attributes(my_factor)
```
Vediamo come la classe dell'oggetto sia `factor` e abbiamo aunceh un ulteriore attributo `levels` dove sono salvati i posibili livelli della nostra variabile. Ma attenzione adesso a cosa otteniamo quando valutiamo la tipologia di dati contenuti nel fattore e la sua sruttura.
```{r, echo = TRUE}
# Tipologia dati
typeof(my_factor)
# Sstrutura
str(my_factor)
```
Ci saremmo aspettati di ottenere `character` pensando che all'interno del fattore fossero salvati vari valori della nostra variabile come stringhe. Invece il fattore è formato da `integer` e possimao osservare come effetivamente l'output del comando `str()` riporta dei valori numerici (oltre ai livelli della variabile). Come spiegarsi tutto questo?
La soluzione è molto semplice. Nel creare un fattore, R valuta i livelli presennti creando l'attributo `levels` e poi sostituisce ad ogni elemento un valore numerico che indica il livello della variabile. Pertanto nel nostro esempio avremmo che il valore `1` è associato al livello `"azzurro"`, il valore `2` a `"marrone"` e il valore `3` a `"verde"`. Questo approccio permette di ottimizzare l'uso della memoria tuttavia inizialmete potrebbe risultare poco intuitivo e causa di errori.
:::{.warning title="Attenti alla Conversione" data-latex="[Attenti alla Conversione]"}
Uno dei principali errori riguarda la conversione da un fattore ad un normale vettore. Nel caso volessimo ottenere un vettore di caratteri possimo usare la funzione `as.character()` ottenendo il risultato voluto.
```{r, echo = TRUE}
as.character(my_factor)
```
Tuttavia, se volessimo ottenere un vettore numerico, dobbiamo prestare particolare attenzione. Considera il seguente esempio dove abbiamo gli anni di istruzione di alcuni partecipanti ad uno studio. Potremmo eseguire alcune analissi considerando questa variable come categoriale per poi ritrasformarla in una variebile numerica per compiere altre analisi. Osserva cosa succede
```{r, echo = TRUE}
# Creo la mia variabile come fattore
school_years<-factor(c(11, 8, 4, 8, 11, 4, 11, 8))
school_years
# Trasformo in un vettore numerico
as.numeric(school_years)
```
In modo forse inaspettato non otteniamo i valori originali (i.e., 4, 8, 11) ma dei valori differenti. Questi in realtà sono i valori numerici che R ha usato per associare ogni elemento al corripondente livello. Per ottenre i valori corretti dobbiamo eseguire il seguente comando:
```{r, echo = TRUE}
as.numeric(as.character(school_years))
```
Questo ci permette di sostituire prime i valori con le giuste *etichette*, ovvero i livelli della variabile, e successivamente convertire il tutto in un vettore numerico.
E' importante prestare molta attenzione in questi casi poichè un eventuale errore potrebbe non risultare subito evidente.
:::
### Operazioni Fattori
Ora che abbiamo capito il funzionamento dei fattori vediamo alcune comuni operazioni.
#### Rinominare i Livelli {-}
E possibile rinominare i livelli di un fattore utilizzando la funzione `levels()` quesa ci permette di accedere agli attuali livelli ed eventualmente ssostituirli.
```{r, echo = TRUE}
my_factor
# Attuli livelli
levels(my_factor)
# Rinomino i livelli
levels(my_factor) <- c("brown", "blue", "green")
my_factor
```
#### Ordinare i Livelli {-}
E' importante non confondere l'ordinare i livelli con il rinominarli. Infatti, mentre nel primo caso viene solo modificato l'ordine dei livelli, nel secondo caso verrebbero modificati anche tutti gli effettivi valori degli elementi. In genere è preferibile quindi ridefinire il fattore specificando l'argomento `levels`.
Vediamo un esempio dove raccogliamo i dati riguardanti i dosaggi di un farmaco:
```{r, echo = TRUE}
dosage <- factor(rep(c("medium", "low", "high"), times = 2))
dosage
```
Non avendo specificato l'attributo `levels` i livelli siano stati definiti automaticamente in ordine alfabetico. Osserviamo cosa succede se per erroe rinominiamo i livelli invece di riordinarli correttamente.
```{r, echo = TRUE}
# Creo una copia
dosage_wrong <- dosage
# ERRORE: rinomino i livelli
levels(dosage_wrong) <- c("low", "medium", "high")
dosage_wrong
```
Nota come questo sia un grave errore poichè rinominado i livelli abbiamo modificato anche gli effettivi valori degli elementi. Adesso i valori sono tutti diversi e insensati.
Per riordinare corretamente i livelli riutilizziamo la funzione `factor()` specificando i livelli nell'ordine desiderato.
```{r, echo = TRUE}
dosage <- factor(dosage, levels = c("low", "medium", "high"))
dosage
```
Così facendo abbiamo riordinato i livelli a nostro piacimento senza modificare gli effettivi valori.
#### Extra {-}
Sono possibili diverse operazioni con i fattori. Ad esempio, possiamo essere interessati a eliminare un certo livello di un fattore:
- se facciamo un subset di un fattore e non abbiamo più valori associati a quel livello
- se vogliamo semplicemente rimuovere un livello e le rispettive osservazioni
In questi casi possiamo usare la funzione `droplevels(x, exclude = ...)` che permette di rimuovere determinati livelli:
```{r}
my_factor <- rep(c("a", "b", "c"), c(10, 5, 2))
my_factor <- factor(my_factor)
levels(my_factor)
# Teniamo solo i valori a e b
my_factor <- my_factor[my_factor %in% c("a", "b")]
levels(my_factor)
```
Come vedete nonostante non ci siano più valori `c`, abbiamo il fattore ha comunque associati tutti i valori iniziali:
```{r}
droplevels(my_factor)
```
Possiamo anche direttamente eliminare un livello ma in corrispondenza dei valori associati avremmo degli `NA`:
```{r}
my_factor <- rep(c("a", "b", "c"), c(10, 5, 2))
my_factor <- factor(my_factor)
my_factor <- droplevels(my_factor, exclude = "a")
my_factor[!is.na(my_factor)]
```
Come è possibile eliminare un livello, è anche possibile aggiungere un livello ad un fattore usando semplicemente il comando `factor()` e specificando tutti i livello più quello/i aggiuntivi:
```{r}
factor(my_factor, levels = c(levels(my_factor), "nuovolivello"))
```
In questo caso abbiamo usato la funzione `c(vecchi_livelli, nuovo_livello)` per creare un vettore di nuovi livelli da usare in questo caso. In alternativa possiamo anche usare il metodo di assegnazione `levels(x) <-` specificando ancora un vettore di livelli oppure specificando un singolo valore assegnando al nuovo indice:
```{r}
my_factor <- rep(c("a", "b", "c"), c(10, 5, 2))
my_factor <- factor(my_factor)
# aggiungo un nuovo livello con un vettore e l'assegnazione
levels(my_factor) <- c(levels(my_factor), "nuovolivello")
# aggiungo un nuovo livello specificando l'indice
levels(my_factor)[4] <- "nuovolivello"
# il fattore my_factor ha 3 livelli e quindi alla quarta posizione (vuota) aggiungo il nuov livello
```
E' possibile inoltre combinare due fattori in modo da ottenerne uno unico unendo quindi i livelli e i rispettivi valori numerici. Semplicemente usando il comando `c(fac1, fac2)`:
```{r}
fac1 <- factor(rep(c("a", "b", "c"), each = 5))
fac2 <- factor(rep(c("d"), each = 5))
c(fac1, fac2)
```
<!-- TODO rbind() con nuovi livelli -->
### Fattori Ordinali
Vediamo infine un esempio di variabile categoriale ordinale. Riprendendo l'esempio precedente rigurdo i dosaggio del farmaco, è chiaro che esiste una relazionee ordinale tra i veri livelli della variabile. Per creare una variabile ordinale possiamo specificare l'argomento `ordered = TRUE`:
```{r, echo = TRUE}
dosage_ord <- factor(dosage, levels = c("low", "medium", "high"), ordered = TRUE)
dosage_ord
```
Notiamo come la natura ordinale dei livelli sia specificata sia quando vengono riportati i livelli sia nella classe dell'oggetto
```{r, echo = TRUE}
# Categoriale nominale
class(dosage)
# Categoriale ordinale
class(dosage_ord)
```
:::{.tip title="Codifica Tipologia Variabli" data-latex="[Codifica Tipologia Variabli]"}
In R è importante codificare correttamente le differenii varibili specificando la loro tipologia. Distinnguendo appropriatamente le variabili categoriali (nominali e ordinali) rispetto alle varibili numeriche e alle semplici variabili di caratteri abbiamo numerosi vantaggi. In R, infatti, molti pacchetti e funzioni adottano particolari accorgimenti a seconda della tipologia di variabile fornendoci output e risultati coerenti alla natura della variabile.
Nota ad esempio comee l'output della funzione `summary()` cambi a seconda della tipologia di varibile.
```{r, echo = TRUE}
# Variabile numerica
summary(1:15)
# Variabile Categoriale
summary(dosage)
```
Questo risulterà particolarmente importante nell'esecuzione di analisi statistiche e nella creazione di grafici e tabelle.
:::
### Esercizi {-}
Esegui i seguenti esercizi ([soluzioni](https://github.com/psicostat/Introduction2R/blob/master/exercises/chapter-08-factors.R)):
1. Crea la variabile categoriale `genere` così definita:
```{r}
factor(c(rep(c("M","F"),3),"F","F","M"))
```
2. Rinomina i livelli della variabile `genere` rispettivamente in `"donne"` e `"uomini"`.
3. Crea la variabile categoriale `intervento` così definita:
```{r}
factor(c(rep(c("CBT","Psicanalisi"),3),"Controllo","Controllo","CBT"))
```
4. Correggi nella variabile `intervento` la 7° e 8° osservazione con la voce `Farmaci`.
5. Aggiungi alla variabile `intervento` le seguenti nuove osservazioni:
```{r}
c("Farmaci","Controllo","Farmaci")
```