Miscellanea: NA e dintorni e factor

Author

Domenico Vistocco

Alla fine di questa puntata…

  • dovreste riuscire a gestire “quello che manca”
  • dovreste riuscire a gestire i “non numeri”
  • dovreste riuscire a gestire le variabili qualitative (nominali ed ordinali)

non avete più scuse, che ne dite…

  • “fa veramente al caso mio?”

Cosa manca?

NA è utilizzato per indicare i valori mancanti (missing values).

La gestione dei missing richiede particolare attenzione. Creiamo un vettore con missing:

(vettoreMV <- c(1:3, NA, 5:10, NA))
 [1]  1  2  3 NA  5  6  7  8  9 10 NA

Quando si lavora con i missing questi rimangono tali qualunque operazione venga effettuata su di essi:

vettoreMV + 5
 [1]  6  7  8 NA 10 11 12 13 14 15 NA
vettoreMV < 5
 [1]  TRUE  TRUE  TRUE    NA FALSE FALSE FALSE FALSE FALSE FALSE    NA

Mentre è possibile usare l’operatore di confronto == per sapere se esiste un valore uguale a 5:

vettoreMV == 5
 [1] FALSE FALSE FALSE    NA  TRUE FALSE FALSE FALSE FALSE FALSE    NA

La stessa cosa non vale per il controllo dei missing:

vettoreMV == NA
 [1] NA NA NA NA NA NA NA NA NA NA NA

In questo caso esiste una funzione ad hoc:

is.na(vettoreMV)
 [1] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE

Per estrarre gli elementi non mancanti è quindi possibile usare l’operatore logico NOT (!) e la funzione is.na:

!is.na(vettoreMV)
 [1]  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
vettoreMV[!is.na(vettoreMV)]
[1]  1  2  3  5  6  7  8  9 10

Attenzione alla presenza dei missing nel caso di operazioni di sintesi:

sum(vettoreMV)
[1] NA
mean(vettoreMV)
[1] NA

E’ possibile calcolare la funzione di sintesi solo sugli elementi validi:

sum(vettoreMV[!is.na(vettoreMV)])
[1] 51
mean(vettoreMV[!is.na(vettoreMV)])
[1] 5.666667

Molte funzioni di sintesi hanno però un “flag” per escludere automaticamente i missing:

sum(vettoreMV, na.rm=TRUE)
[1] 51
mean(vettoreMV, na.rm=TRUE)
[1] 5.666667

In alternativa è possibile usare la funzione na.omit per escludere i missing

na.omit(vettoreMV)
[1]  1  2  3  5  6  7  8  9 10
attr(,"na.action")
[1]  4 11
attr(,"class")
[1] "omit"

Attenzione: se si vogliono escludere gli elementi, si deve riassegnare l’output di na.omit

vettoreMV
 [1]  1  2  3 NA  5  6  7  8  9 10 NA
vettoreMV <- na.omit(vettoreMV)
vettoreMV
[1]  1  2  3  5  6  7  8  9 10
attr(,"na.action")
[1]  4 11
attr(,"class")
[1] "omit"

na.omit (insieme alla funzioni complete.cases) è molto utile nel caso di dataframe.

Alcune funzioni utili per la gestione dei missing sui dataframe

Preparo un data.frame con NA sparsi

vettoreMV <- c(1:3, NA, 5:10, NA)
df <- data.frame(var1=vettoreMV, 
                 var2 = c(NA, 2:10, NA), 
                 var3=c(1, NA, 10:2))
df
   var1 var2 var3
1     1   NA    1
2     2    2   NA
3     3    3   10
4    NA    4    9
5     5    5    8
6     6    6    7
7     7    7    6
8     8    8    5
9     9    9    4
10   10   10    3
11   NA   NA    2

Benvenuti nella famiglia apply

Posso controllare il numero di missing value per colonna

sum(is.na(df$var1))
[1] 2
sum(is.na(df$var2))
[1] 2
sum(is.na(df$var3))
[1] 1

Il numero di missing per riga

is.na(df$var1) + is.na(df$var2) + is.na(df$var3)
 [1] 1 1 0 1 0 0 0 0 0 0 2

Posso però usare la funzione apply che permette di applicare una funzione su una delle due dimensioni di una tabella (1 per le righe e 2 per le colonne) NOTA: nel caso di array3d se si vuole per strati si usa il valore 3 per il secondo argomento e così via nel caso di array a più dimensioni

Si può definire una funzione e poi passarla alla funzione apply:

contaNA <- function(x){sum(is.na(x))}

Se passo alla funzione l’intero dataframe ottengo in risposta il numero complessivo di missing:

contaNA(df)
[1] 5

Se voglio sapere quanti NA ci sono per colonna

apply(df, 2, contaNA)
var1 var2 var3 
   2    2    1 

o per riga

apply(df, 1, contaNA)
 [1] 1 1 0 1 0 0 0 0 0 0 2

NOTA Si può definire una funzione “on the fly” come terzo argomento alla funzione: in questo secondo caso la funzione non è disponibile sul workspace per successivi utilizzi

apply(df, 2, function(x)sum(is.na(x)))
var1 var2 var3 
   2    2    1 

Il dataframe è una particolare lista per cui è possibile usare sia la funzione lapply che la funzione sapply:

lapply(df, function(x)sum(is.na(x))) #restituisce una lista
$var1
[1] 2

$var2
[1] 2

$var3
[1] 1
sapply(df, function(x)sum(is.na(x))) #semplifica la struttura di output laddove possibile
var1 var2 var3 
   2    2    1 

Cambiando il default del flag simplify ottengo una lista anche con la funzione sapply

sapply(df, function(x)sum(is.na(x)), simplify=FALSE)
$var1
[1] 2

$var2
[1] 2

$var3
[1] 1

Funzioni utili per la gestione dei missing su tabelle dati

Per estrarre solo le righe senza missing posso quindi procedere usando due alternativa:

df[is.na(df$var1) + is.na(df$var2) == 0 + is.na(df$var3),] #alternativa 1
   var1 var2 var3
3     3    3   10
5     5    5    8
6     6    6    7
7     7    7    6
8     8    8    5
9     9    9    4
10   10   10    3
df[apply(df,1,function(x)sum(is.na(x))) == 0,] #alternativa 2
   var1 var2 var3
3     3    3   10
5     5    5    8
6     6    6    7
7     7    7    6
8     8    8    5
9     9    9    4
10   10   10    3

La funzione complete.cases restituisce per ogni unità un FALSE se ci sono missing:

complete.cases(df)
 [1] FALSE FALSE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE

Posso quindi estrarre le sole unità senza missing usando l’output di complete.cases per indicizzare il dataframe:

df[complete.cases(df),]
   var1 var2 var3
3     3    3   10
5     5    5    8
6     6    6    7
7     7    7    6
8     8    8    5
9     9    9    4
10   10   10    3

La funzione na.omit scarta automaticamente i valori mancanti:

na.omit(df)
   var1 var2 var3
3     3    3   10
5     5    5    8
6     6    6    7
7     7    7    6
8     8    8    5
9     9    9    4
10   10   10    3

NOTA: se si vuole utilizzare in seguito la tabella dati senza missing è necessario assegnarla ad un oggetto

La funzione na.fail restituisce un messaggio di errore se nell’oggetto passatole come argomento sono presenti missing:

na.fail(df)

e restituisce l’oggetto nel caso in cui non sono presenti missing:

na.fail(na.omit(df))
   var1 var2 var3
3     3    3   10
5     5    5    8
6     6    6    7
7     7    7    6
8     8    8    5
9     9    9    4
10   10   10    3

NOTA: utile per escludere espressioni nel caso di presenza di missing

Numeri, non-numeri e infiniti numeri…

Altro valore particolare: il non-numero:

0/0
[1] NaN
?NaN

e la corrispondente funzione per controllarne la presenza:

is.nan(0/0)
[1] TRUE

Inf è la parola riservata per infinito:

is.finite(10)
[1] TRUE
is.finite(Inf)
[1] FALSE
is.infinite(Inf)
[1] TRUE

Variabili qualitative in R: i fattori

Un vettore di stringhe quando inserito in un dataframe viene automaticamente convertito in una variabile di tipo factor, utilizzata in R per la gestione di variabili qualitative.

NOTA: la funzione sample permette di estrarre un campione casuale

sample(letters, 10) #in questo caso estraggo 10 lettere dal vettore predefinito letters
sample(letters, 100) #se provo ad estrarne 100 ottengo un messaggio di errore
length(letters) #errore comprensibile se controllo la lunghezza del vettore letters

Per effettuare un campionamento con ripetizione posso impostare il flag replace a TRUE:

sample(letters, 10, replace=T)
 [1] "l" "a" "q" "j" "g" "l" "g" "u" "q" "b"
sample(letters, 100, replace=T)
  [1] "m" "n" "l" "x" "p" "b" "m" "r" "j" "p" "r" "m" "o" "f" "l" "a" "i" "z"
 [19] "w" "s" "y" "r" "p" "b" "s" "h" "c" "j" "e" "n" "c" "g" "p" "q" "f" "m"
 [37] "v" "l" "f" "q" "k" "b" "y" "i" "h" "m" "s" "q" "w" "v" "z" "i" "v" "s"
 [55] "m" "c" "t" "l" "m" "r" "h" "f" "v" "q" "u" "i" "s" "o" "u" "k" "h" "r"
 [73] "c" "s" "b" "a" "m" "l" "a" "n" "o" "w" "y" "e" "e" "b" "y" "e" "b" "i"
 [91] "f" "y" "a" "n" "b" "x" "z" "h" "g" "k"

Nel caso di esperimenti con numeri casuali per assicurarsi la riproducibilità dei risultati si può fissare il seme della generazione dei numeri casuali usando la funzione set.seed:

set.seed(17)

Variabile con 100 lettere estratte casualmente con ripetizione dal vettore letters:

var1 <- sample(letters, 100, replace=T)

Mi accorgo che si tratta di un oggetto character controllando la modalità dell’oggetto

mode(var1)
[1] "character"

Variabili nominali…

La funzione factor permette di creare una variabile di tipo factor (variabile qualitativa nominale):

fVar1 <- factor(var1)

La funzione di stampa per gli oggetti di tipo factor produce una diversa formattazione del contenuto dell’oggetto:

fVar1
  [1] r h a l o w g m g j v o a q j f x t e n d y u r y p p s h v c a g h d e z
 [38] u q s v k w v o i e h e w b r t m n k l j i h m k s n r u v a i t m j d c
 [75] s e i l r c d n m s a b h p m d d f j u u k w q u w
Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z
print(fVar1) #funzione generica
  [1] r h a l o w g m g j v o a q j f x t e n d y u r y p p s h v c a g h d e z
 [38] u q s v k w v o i e h e w b r t m n k l j i h m k s n r u v a i t m j d c
 [75] s e i l r c d n m s a b h p m d d f j u u k w q u w
Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z
print.factor(fVar1) #funzione specifica
  [1] r h a l o w g m g j v o a q j f x t e n d y u r y p p s h v c a g h d e z
 [38] u q s v k w v o i e h e w b r t m n k l j i h m k s n r u v a i t m j d c
 [75] s e i l r c d n m s a b h p m d d f j u u k w q u w
Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z

I fattori sono in realtà internamente codificati come numeri:

c(class(fVar1), mode(fVar1), typeof(fVar1))
[1] "factor"  "numeric" "integer"

E’ possibile estrarre i differenti livelli di un fattore usando la funzione levels:

levels(fVar1)
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x" "y" "z"

e sapere quanti sono calcolando la lunghezza dell’output restituito da levels:

length(levels(fVar1))
[1] 26

o la funzione nlevels che restituisce direttamente il numero di livelli di una variabile fattore:

nlevels(fVar1)
[1] 26

i livelli di un oggetto factor sono ordinati per default in senso crescente (se si tratta di caratteri in ordine alfabetico crescente):

set.seed(17)
factor(sample(1:3, 10, replace=TRUE))
 [1] 2 1 2 3 3 3 1 3 2 2
Levels: 1 2 3

La funzione factor ha un argomento levels che permette di impostare i livelli del fattore

set.seed(17)
factor(sample(1:3, 10, replace=TRUE), levels=c(1,2,3))
 [1] 2 1 2 3 3 3 1 3 2 2
Levels: 1 2 3

Impostando i livello con l’argomento levels l’ordine viene usato anche per la stampa del fattore

set.seed(17)
factor(sample(1:3, 10, replace=TRUE), levels=c(2, 3, 1))
 [1] 2 1 2 3 3 3 1 3 2 2
Levels: 2 3 1

Così come nelle tabelle:

set.seed(17)
table(factor(sample(1:3, 10, replace=TRUE), levels=c(2, 3, 1)))

2 3 1 
4 4 2 

e nei grafici:

set.seed(17)
barplot(table(factor(sample(1:3, 10, replace=TRUE), levels=c(2, 3, 1))))

E’ possibile impostare anche le etichette del fattore usando l’argomento labels:

set.seed(17)
factor(sample(1:3, 10, replace=TRUE))
 [1] 2 1 2 3 3 3 1 3 2 2
Levels: 1 2 3
set.seed(17)
factor(sample(1:3, 10, replace=TRUE), labels=c("uno","due","tre"))
 [1] due uno due tre tre tre uno tre due due
Levels: uno due tre

I livelli sono associati alle etichette:

set.seed(17)
factor(sample(1:3, 10, replace=TRUE), levels=c(2,3, 1), labels=c("due","tre","uno"))
 [1] due uno due tre tre tre uno tre due due
Levels: due tre uno

… e variabili ordinali

E’ possibile creare un fattore ordinato (variabile qualitativa ordinale) sia impostando il flag ordered a TRUE:

set.seed(17)
factor(sample(1:3, 10, replace=TRUE), levels=c(1,2,3), ordered=T)
 [1] 2 1 2 3 3 3 1 3 2 2
Levels: 1 < 2 < 3

che usando la funzione ordered:

set.seed(17)
ordered(sample(1:3, 10, replace=TRUE), levels=c(1,2,3))
 [1] 2 1 2 3 3 3 1 3 2 2
Levels: 1 < 2 < 3

L’oggetto ottenuto in entrambi i casi è un fattore ordinato:

class(factor(sample(1:3, 10, replace=TRUE), levels=c(1,2,3), ordered=T))
[1] "ordered" "factor" 
class(ordered(sample(1:3, 10, replace=TRUE), levels=c(1,2,3)))
[1] "ordered" "factor" 

Anche per i fattori ordinati è possibile usare sia l’argomento levels che l’argomento labels:

set.seed(17)
factor(sample(1:3, 10, replace=TRUE), levels=c(1, 2, 3), labels=c("a","b","c"), ordered=TRUE)
 [1] b a b c c c a c b b
Levels: a < b < c

Una nota sui livelli “inutili”

Se nell’oggetto factor non sono presenti dei livelli definiti nell’argomento levels l’informazione circa il livello non presente non viene persa:

set.seed(17)
factor(sample(1:3, 20, replace=TRUE), levels=1:4)
 [1] 2 1 2 3 3 3 1 3 2 2 3 1 1 2 2 2 1 2 3 1
Levels: 1 2 3 4

Come si può notare anche dalla tabella di frequenza associata:

set.seed(17)
table(factor(sample(1:3, 105, replace=TRUE), levels=1:4))

 1  2  3  4 
38 33 34  0 

Per escludere fattori non utilizzati da una variabile factor si può passare il fattore alla funzione factor ed utilizzare l’argomento exclude=NULL:

set.seed(17)
fUnusedLevel <- factor(sample(1:3, 105, replace=TRUE), levels=1:4)
factor(fUnusedLevel, exclude=NULL)
  [1] 2 1 2 3 3 3 1 3 2 2 3 1 1 2 2 2 1 2 3 1 1 2 1 3 3 2 1 3 1 3 1 2 1 1 1 3 2
 [38] 3 3 2 3 1 3 1 1 3 2 2 3 2 1 2 3 2 1 1 3 3 2 2 1 2 1 1 2 1 2 3 3 1 1 2 3 3
 [75] 2 1 3 1 2 1 3 2 2 1 3 1 3 3 1 1 3 3 3 1 1 1 3 3 2 2 1 2 2 1 2
Levels: 1 2 3
table(factor(fUnusedLevel, exclude=NULL))

 1  2  3 
38 33 34 

Un problema analogo si ha nel caso di estrazioni di un sottoinsieme di osservazioni a partire da una variabile di tipo factor: anche in questo caso i livelli definiti per la variabile di tipo factor rimangono invariati.

Creo una variabile di tipo factor contenente tre valori: a, b e c:

varCompleta <- factor(c(rep("a",2), rep("b", 5), rep("c", 3)))
varCompleta
 [1] a a b b b b b c c c
Levels: a b c

Estraggo dalla variabile completa un sottoinsieme:

(varRidotta <- varCompleta[varCompleta != "a"])
[1] b b b b b c c c
Levels: a b c

Il livello a è ancora presente nella definizione del fattore nonostante non sia presente nei dati:

levels(varRidotta)
[1] "a" "b" "c"
table(varRidotta)
varRidotta
a b c 
0 5 3 

Se provo a forzare i livelli della variabile ai soli fattori presenti ottengo un messaggio di errore:

levels(varRidotta) <- c("b","c")

In questo caso l’argomento exclude della funzione factor mi permette di “riadattare” il fattore usando solo i livelli presenti:

factor(varRidotta, exclude=NULL)
[1] b b b b b c c c
Levels: b c
table(factor(varRidotta, exclude=NULL))

b c 
5 3 

Nell’operazione di estrazione del sottoinsieme dal fattore posso anche utilizzare l’argomento drop=TRUE per eliminare dal fattore risultante eventuali livelli non utilizzati:

set.seed(17)
(varRidotta <- varCompleta[varCompleta != "a", drop=TRUE])
[1] b b b b b c c c
Levels: b c
levels(varRidotta)
[1] "b" "c"
table(varRidotta)
varRidotta
b c 
5 3 

In alcuni casi può essere utile cambiare il livello di riferimento in una variabile di tipo fattore: il livello di riferimento è il primo livello della variabile e assume un ruolo particolare nei modelli (vedi lezioni successive)

Se si considera ad esempio un modello di regressione lineare, inserendo una variabile dummy nel modello di regressione automaticamente il sistema inserisce un numero di dummy pari al nr. di modalità - 1 per evitare il problema di perfetta collinearità. Il livello escluso (rispetto al quale vanno interpretati i coefficienti di tutti gli altri livelli) è il primo

(variabile <- factor(sample(letters[1:5], 20, replace=TRUE)))
 [1] b a d e b a d a b d e c d a e b a c d e
Levels: a b c d e

La funzione relevel mi permette di cambiare il livello di riferimento di un fattore:

variabile <- relevel(variabile, "c")
variabile
 [1] b a d e b a d a b d e c d a e b a c d e
Levels: c a b d e

L’unione fa i livelli

Creo due variabili fattore che hanno un livello in comune e un livello non in comune:

fattore1 <- factor(c("a", "b", "b", "a", "b"))
fattore2 <- factor(c("b", "c", "b", "c","c"))
fattore1
[1] a b b a b
Levels: a b
fattore2
[1] b c b c c
Levels: b c

Se provo a combinare le due variabili in realtà il vattore che viene restituito è la combinazione dei valori numerici associati a ciascuna variabile, come posso verificare se semplifico gli oggetti usando la funzione unclass:

c(fattore1, fattore2)
 [1] a b b a b b c b c c
Levels: a b c
unclass(fattore1)
[1] 1 2 2 1 2
attr(,"levels")
[1] "a" "b"
unclass(fattore2)
[1] 1 2 1 2 2
attr(,"levels")
[1] "b" "c"
c(unclass(fattore1), unclass(fattore2))
 [1] 1 2 2 1 2 1 2 1 2 2

In questo caso posso puntare lavorare sui livelli e non sulla loro rappresentazione numerica usando la variabile fattore come vettore per l’operatore [ sul vettore dei livelli:

levels(fattore1)[fattore1]
[1] "a" "b" "b" "a" "b"

o in alternativa forzando una conversione al tipo character:

as.character(fattore1)
[1] "a" "b" "b" "a" "b"

Per combinare i due fattori posso quindi usare una sintassi analoga anche per l’altro fattore:

c(levels(fattore1)[fattore1], levels(fattore2)[fattore2])
 [1] "a" "b" "b" "a" "b" "b" "c" "b" "c" "c"

o, in alternativa, usando la conversione al tipo character:

c(as.character(fattore1), as.character(fattore2))
 [1] "a" "b" "b" "a" "b" "b" "c" "b" "c" "c"

Naturalmente per avere un variabile fattore posso passare il valore dell’ultima espressione alla funzione factor:

fattore1e2 <- factor(c(levels(fattore1)[fattore1], levels(fattore2)[fattore2]))
fattore1e2
 [1] a b b a b b c b c c
Levels: a b c

Una nota (squisitamente tecnica) sui livelli “mancanti”

Se commetto un errore nella definizione dei livelli (salto una modalità della variabile qualitativa) la funzione factor prova a sistemare le cose:

factor(c(2, 3, 1, 2, 1, 2), levels = c(1, 2))
[1] 2    <NA> 1    2    1    2   
Levels: 1 2

E’ come se nella creazione della variabile qualitativa (di cui si sottointende di conoscere l’elenco delle modalità) avessi un valore mancante:

factor(c(2, 3, 1, 2, 1, NA, 2))
[1] 2    3    1    2    1    <NA> 2   
Levels: 1 2 3

Potrei, in alcuni casi, usare “una modalità mancante”:

factor(c(2, 3, 1, 2, 1, NA, 2), exclude = NULL)
[1] 2    3    1    2    1    <NA> 2   
Levels: 1 2 3 <NA>

Una nota sulla funzione sample

La funzione sample effettua un campionamento casuale semplice attribuendo per default a ciascun valore del vettore da cui campionare la stessa probabilità di appartenere al campione estratto:

table(sample(1:4, 1000, replace=TRUE))

  1   2   3   4 
274 253 231 242 

E’ possibile specificare un vettore di probabilità da utilizzare per il processo di campionamento usando l’argomento prob:

table(sample(1:4, 1000, replace=TRUE, prob=c(0.1, 0.7, 0.1, 0.1)))

  1   2   3   4 
 83 713 125  79 

La funzione runif permette di generare numeri da una distribuzione uniforme continua: dall’help in linea è possibile vedere i vari argomenti e il loro significato.

NOTA: per ogni modello di variabile casuale esistono quattro tipo di funzione con nome prefissoNomeModello, dove il nomeModello mi permette di scegliere quale generatore di numeri casuali utilizzare e il prefisso è, per tutti i modelli una tra le seguenti quattro lettere: - rNomeModello (es. runif): il prefisso r indica che la funzione permette di generare numeri casuali dal modello in questione - dNomeModello (es. dunif): il prefisso d indica che la funzione permette di calcolare il valore della distribuzione di probabilità, nel caso di una variabile discreta, o della funzione di densità nel caso di una variabile continua - pNomeModello (es. punif): il prefisso p indica che la funzione permette di calcolare la probabilità in un punto o un intervallo, a seconda della tipologia di variabile (discreta o continua) - qNomeModello (es. qunif): il prefisso q indica che la funzione permette di calcolare il quantile della particolare variabile casuale

?runif

Genero un campione di 100 osservazione da un modello ~ U(0, 1):

set.seed(1); varUniforme <- runif(100)

La funzione cut permette di ricodificare una variabile quantitativa in classi:

?cut

L’argomento breaks della funzione cut permette di fissare il numero di classi della categorizzazione. Divido ad esempio in 3 classi:

cut(varUniforme, 3)
  [1] (0.0124,0.34] (0.34,0.666]  (0.34,0.666]  (0.666,0.993] (0.0124,0.34]
  [6] (0.666,0.993] (0.666,0.993] (0.34,0.666]  (0.34,0.666]  (0.0124,0.34]
 [11] (0.0124,0.34] (0.0124,0.34] (0.666,0.993] (0.34,0.666]  (0.666,0.993]
 [16] (0.34,0.666]  (0.666,0.993] (0.666,0.993] (0.34,0.666]  (0.666,0.993]
 [21] (0.666,0.993] (0.0124,0.34] (0.34,0.666]  (0.0124,0.34] (0.0124,0.34]
 [26] (0.34,0.666]  (0.0124,0.34] (0.34,0.666]  (0.666,0.993] (0.34,0.666] 
 [31] (0.34,0.666]  (0.34,0.666]  (0.34,0.666]  (0.0124,0.34] (0.666,0.993]
 [36] (0.666,0.993] (0.666,0.993] (0.0124,0.34] (0.666,0.993] (0.34,0.666] 
 [41] (0.666,0.993] (0.34,0.666]  (0.666,0.993] (0.34,0.666]  (0.34,0.666] 
 [46] (0.666,0.993] (0.0124,0.34] (0.34,0.666]  (0.666,0.993] (0.666,0.993]
 [51] (0.34,0.666]  (0.666,0.993] (0.34,0.666]  (0.0124,0.34] (0.0124,0.34]
 [56] (0.0124,0.34] (0.0124,0.34] (0.34,0.666]  (0.34,0.666]  (0.34,0.666] 
 [61] (0.666,0.993] (0.0124,0.34] (0.34,0.666]  (0.0124,0.34] (0.34,0.666] 
 [66] (0.0124,0.34] (0.34,0.666]  (0.666,0.993] (0.0124,0.34] (0.666,0.993]
 [71] (0.0124,0.34] (0.666,0.993] (0.34,0.666]  (0.0124,0.34] (0.34,0.666] 
 [76] (0.666,0.993] (0.666,0.993] (0.34,0.666]  (0.666,0.993] (0.666,0.993]
 [81] (0.34,0.666]  (0.666,0.993] (0.34,0.666]  (0.0124,0.34] (0.666,0.993]
 [86] (0.0124,0.34] (0.666,0.993] (0.0124,0.34] (0.0124,0.34] (0.0124,0.34]
 [91] (0.0124,0.34] (0.0124,0.34] (0.34,0.666]  (0.666,0.993] (0.666,0.993]
 [96] (0.666,0.993] (0.34,0.666]  (0.34,0.666]  (0.666,0.993] (0.34,0.666] 
Levels: (0.0124,0.34] (0.34,0.666] (0.666,0.993]

Posso cambiare il numero di cifre decimali usati per le etichette delle modalità:

cut(varUniforme, 3, dig.lab=1)
  [1] (0.01,0.3] (0.3,0.7]  (0.3,0.7]  (0.7,1]    (0.01,0.3] (0.7,1]   
  [7] (0.7,1]    (0.3,0.7]  (0.3,0.7]  (0.01,0.3] (0.01,0.3] (0.01,0.3]
 [13] (0.7,1]    (0.3,0.7]  (0.7,1]    (0.3,0.7]  (0.7,1]    (0.7,1]   
 [19] (0.3,0.7]  (0.7,1]    (0.7,1]    (0.01,0.3] (0.3,0.7]  (0.01,0.3]
 [25] (0.01,0.3] (0.3,0.7]  (0.01,0.3] (0.3,0.7]  (0.7,1]    (0.3,0.7] 
 [31] (0.3,0.7]  (0.3,0.7]  (0.3,0.7]  (0.01,0.3] (0.7,1]    (0.7,1]   
 [37] (0.7,1]    (0.01,0.3] (0.7,1]    (0.3,0.7]  (0.7,1]    (0.3,0.7] 
 [43] (0.7,1]    (0.3,0.7]  (0.3,0.7]  (0.7,1]    (0.01,0.3] (0.3,0.7] 
 [49] (0.7,1]    (0.7,1]    (0.3,0.7]  (0.7,1]    (0.3,0.7]  (0.01,0.3]
 [55] (0.01,0.3] (0.01,0.3] (0.01,0.3] (0.3,0.7]  (0.3,0.7]  (0.3,0.7] 
 [61] (0.7,1]    (0.01,0.3] (0.3,0.7]  (0.01,0.3] (0.3,0.7]  (0.01,0.3]
 [67] (0.3,0.7]  (0.7,1]    (0.01,0.3] (0.7,1]    (0.01,0.3] (0.7,1]   
 [73] (0.3,0.7]  (0.01,0.3] (0.3,0.7]  (0.7,1]    (0.7,1]    (0.3,0.7] 
 [79] (0.7,1]    (0.7,1]    (0.3,0.7]  (0.7,1]    (0.3,0.7]  (0.01,0.3]
 [85] (0.7,1]    (0.01,0.3] (0.7,1]    (0.01,0.3] (0.01,0.3] (0.01,0.3]
 [91] (0.01,0.3] (0.01,0.3] (0.3,0.7]  (0.7,1]    (0.7,1]    (0.7,1]   
 [97] (0.3,0.7]  (0.3,0.7]  (0.7,1]    (0.3,0.7] 
Levels: (0.01,0.3] (0.3,0.7] (0.7,1]

La variabile generata dalla funzione cut è una variabile di tipo fattore:

c(mode(cut(varUniforme, 3)), class(cut(varUniforme, 3)))
[1] "numeric" "factor" 

Per default le etichette sono associate agli intervalli usati per la categorizzazione:

table(cut(varUniforme, 3, dig.lab=1))

(0.01,0.3]  (0.3,0.7]    (0.7,1] 
        29         36         35 

L’argomento labels della funzione cut permette di impostare le etichette da utilizzare per la variabile factor:

table(cut(varUniforme, 3, dig.lab=1, labels=c("basso","medio","alto")))

basso medio  alto 
   29    36    35 

Invece del numero di classi da utilizzare, l’argomento break può essere utilizzato per specificare gli estremi delle classi:

table(cut(varUniforme, breaks=c(0, 0.2, 0.8,1)))

  (0,0.2] (0.2,0.8]   (0.8,1] 
       13        70        17 

NOTA: gli estremi devono comprendere sia l’estremo inferiore della prima classe che l’estremo superiore dell’ultima classe. Se ci sono valori a sinistra del primo valore dell’argomento breaks questi saranno sostituiti da NA nella categorizzazione:

cut(varUniforme, breaks=c(0.2, 0.8, 1))
  [1] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.8,1]   (0.8,1]  
  [8] (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8] <NA>      (0.2,0.8] (0.2,0.8]
 [15] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.8,1]  
 [22] (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8]
 [29] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] <NA>      (0.8,1]  
 [36] (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8]
 [43] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8] (0.2,0.8]
 [50] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] <NA>      <NA>     
 [57] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8]
 [64] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] <NA>      (0.8,1]  
 [71] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.8,1]  
 [78] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8]
 [85] (0.2,0.8] (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8] <NA>      (0.2,0.8]
 [92] <NA>      (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8]
 [99] (0.8,1]   (0.2,0.8]
Levels: (0.2,0.8] (0.8,1]

Lo stesso accade nel caso ci siano dati a destra dell’ultimo valore dell’argomento breaks:

cut(varUniforme, breaks=c(0, 0.2, 0.8))
  [1] (0.2,0.8] (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8] <NA>      <NA>     
  [8] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8] (0,0.2]   (0.2,0.8] (0.2,0.8]
 [15] (0.2,0.8] (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8] (0.2,0.8] <NA>     
 [22] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8]
 [29] <NA>      (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0,0.2]   <NA>     
 [36] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8]
 [43] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8] (0.2,0.8]
 [50] (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8] (0.2,0.8] (0,0.2]   (0,0.2]  
 [57] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8] (0.2,0.8]
 [64] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0,0.2]   <NA>     
 [71] (0.2,0.8] <NA>      (0.2,0.8] (0.2,0.8] (0.2,0.8] <NA>      <NA>     
 [78] (0.2,0.8] (0.2,0.8] <NA>      (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8]
 [85] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8] (0,0.2]   (0.2,0.8]
 [92] (0,0.2]   (0.2,0.8] <NA>      (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8]
 [99] <NA>      (0.2,0.8]
Levels: (0,0.2] (0.2,0.8]

L’argomento include.lowest permette di utilizzare la prima classe chiusa a sinistra:

cut(varUniforme, breaks=c(0, 0.2, 0.8, 1), include.lowest=T)
  [1] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.8,1]   (0.8,1]  
  [8] (0.2,0.8] (0.2,0.8] [0,0.2]   (0.2,0.8] [0,0.2]   (0.2,0.8] (0.2,0.8]
 [15] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.8,1]  
 [22] (0.2,0.8] (0.2,0.8] [0,0.2]   (0.2,0.8] (0.2,0.8] [0,0.2]   (0.2,0.8]
 [29] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] [0,0.2]   (0.8,1]  
 [36] (0.2,0.8] (0.2,0.8] [0,0.2]   (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8]
 [43] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] [0,0.2]   (0.2,0.8] (0.2,0.8]
 [50] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] [0,0.2]   [0,0.2]  
 [57] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8]
 [64] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] [0,0.2]   (0.8,1]  
 [71] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.8,1]  
 [78] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8]
 [85] (0.2,0.8] (0.2,0.8] (0.2,0.8] [0,0.2]   (0.2,0.8] [0,0.2]   (0.2,0.8]
 [92] [0,0.2]   (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8]
 [99] (0.8,1]   (0.2,0.8]
Levels: [0,0.2] (0.2,0.8] (0.8,1]

Posso decidere se le classi sono aperte a destra o a sinistra usando il flag right:

cut(varUniforme, breaks=c(0, 0.2, 0.8, 1), right=T)
  [1] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.8,1]   (0.8,1]  
  [8] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8] (0,0.2]   (0.2,0.8] (0.2,0.8]
 [15] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.8,1]  
 [22] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8]
 [29] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.8,1]  
 [36] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8]
 [43] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8] (0.2,0.8]
 [50] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0,0.2]   (0,0.2]  
 [57] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8]
 [64] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.8,1]  
 [71] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.8,1]  
 [78] (0.2,0.8] (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8]
 [85] (0.2,0.8] (0.2,0.8] (0.2,0.8] (0,0.2]   (0.2,0.8] (0,0.2]   (0.2,0.8]
 [92] (0,0.2]   (0.2,0.8] (0.8,1]   (0.2,0.8] (0.2,0.8] (0.2,0.8] (0.2,0.8]
 [99] (0.8,1]   (0.2,0.8]
Levels: (0,0.2] (0.2,0.8] (0.8,1]
cut(varUniforme, breaks=c(0, 0.2, 0.8, 1), right=F)
  [1] [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.8,1)   [0.2,0.8) [0.8,1)   [0.8,1)  
  [8] [0.2,0.8) [0.2,0.8) [0,0.2)   [0.2,0.8) [0,0.2)   [0.2,0.8) [0.2,0.8)
 [15] [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.8,1)   [0.2,0.8) [0.2,0.8) [0.8,1)  
 [22] [0.2,0.8) [0.2,0.8) [0,0.2)   [0.2,0.8) [0.2,0.8) [0,0.2)   [0.2,0.8)
 [29] [0.8,1)   [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.2,0.8) [0,0.2)   [0.8,1)  
 [36] [0.2,0.8) [0.2,0.8) [0,0.2)   [0.2,0.8) [0.2,0.8) [0.8,1)   [0.2,0.8)
 [43] [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.2,0.8) [0,0.2)   [0.2,0.8) [0.2,0.8)
 [50] [0.2,0.8) [0.2,0.8) [0.8,1)   [0.2,0.8) [0.2,0.8) [0,0.2)   [0,0.2)  
 [57] [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.8,1)   [0.2,0.8) [0.2,0.8)
 [64] [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.2,0.8) [0,0.2)   [0.8,1)  
 [71] [0.2,0.8) [0.8,1)   [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.8,1)   [0.8,1)  
 [78] [0.2,0.8) [0.2,0.8) [0.8,1)   [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.2,0.8)
 [85] [0.2,0.8) [0.2,0.8) [0.2,0.8) [0,0.2)   [0.2,0.8) [0,0.2)   [0.2,0.8)
 [92] [0,0.2)   [0.2,0.8) [0.8,1)   [0.2,0.8) [0.2,0.8) [0.2,0.8) [0.2,0.8)
 [99] [0.8,1)   [0.2,0.8)
Levels: [0,0.2) [0.2,0.8) [0.8,1)