Cos'è davvero un factor
Un factor è la risposta di R ai dati categoriali, cioè valori che provengono da un menu fisso di possibilità: gruppi di trattamento, risposte a un sondaggio, taglie di magliette. Quando lo stampi sembra un vettore character, ma non lo è. Internamente, un factor è un vettore di codici interi più una tabella di etichette chiamate livelli:
La stampa mostra le etichette, poi una riga Levels: che elenca il menu. as.integer() rivela il meccanismo: i codici tornano come 3 1 3 2, perché ogni valore è in realtà un indice nella tabella dei livelli, e i livelli sono ordinati alfabeticamente per impostazione predefinita (large, medium, small), non nell'ordine in cui sono arrivati i dati. Quindi small è il codice 3 e large è il codice 1, il che non è intuitivo per nessuno. Ricorda questo ordine alfabetico predefinito: sta dietro a due delle trappole più avanti.
Perché complicarsi la vita con questo design a due livelli invece di usare semplici stringhe? Perché la statistica ne ha bisogno. Un modello non può moltiplicare "small" per un coefficiente, ma può codificare tre livelli noti in colonne di 0 e 1. Funzioni come lm(), glm(), table() e il meccanismo dietro l'ANOVA si basano tutte sui factor per sapere che una variabile è categoriale, qual è l'insieme completo delle categorie (comprese quelle assenti dai dati) e quale categoria è la baseline. I semplici vettori character non portano nessuna di queste informazioni.
Creare factor: levels, labels e table()
Per impostazione predefinita factor() prende i valori distinti che trova e li ordina alfabeticamente come livelli. Spesso vorrai controllare sia l'insieme sia l'ordine: passa levels =:
Ora i livelli seguono il loro ordine naturale di taglia, e anche table(), il conteggio delle frequenze in una riga che userai continuamente con i factor, riporta i conteggi in quell'ordine. nlevels() conta le categorie.
levels = ti dà altre due cose. I valori nei dati che non sono nella tua lista di livelli diventano NA (bene: gli errori di battitura vengono a galla invece di diventare una categoria a sé). E i livelli con zero occorrenze esistono comunque, quindi un riepilogo delle risposte a un sondaggio mostra "per niente d'accordo: 0" invece di fingere che l'opzione non sia mai esistita.
labels = rinomina i livelli al momento della creazione, comodo quando i dati grezzi usano dei codici:
E as.factor(x) è il convertitore rapido per un vettore esistente quando le impostazioni predefinite vanno bene.
Factor ordinati per dati ordinali
I factor semplici trattano le categorie come non ordinate: "red" non è minore di "blue". Ma alcune scale categoriali hanno una vera gerarchia: basso/medio/alto, in disaccordo/neutrale/d'accordo. Dichiaralo con ordered = TRUE:
Ora la stampa mostra Levels: low < medium < high, e gli operatori di confronto funzionano: puoi chiedere se una valutazione supera un'altra, o filtrare tutto ciò che è pari o superiore a "medium", operazioni che su un factor non ordinato darebbero errore (anzi, warning e NA). I factor ordinati cambiano anche il modo in cui i modelli codificano la variabile (contrasti polinomiali invece di variabili dummy), che di solito è ciò che vuoi per i predittori ordinali.
Usa ordered = TRUE solo quando la gerarchia è reale. Codificare gruppi ordinari come ordinati cambia l'output dei modelli in modi facili da fraintendere.
Il livello di riferimento e relevel()
Il primo livello di un factor è speciale: le funzioni di modellazione lo trattano come categoria di riferimento, la baseline rispetto alla quale si misura il coefficiente di ogni altro livello. Siccome l'ordine predefinito dei livelli è alfabetico, la tua baseline viene scelta dall'alfabeto a meno che tu non intervenga, e "control" che perde contro "aspirin" in ordine alfabetico non è una decisione scientifica.
relevel() promuove un livello al primo posto:
Prima: control è primo solo per fortuna alfabetica. Dopo relevel(..., ref = "control") è primo di proposito. In una regressione lineare con questo predittore, il coefficiente di treatment ora risponde a "in cosa differisce il trattamento dal controllo?", la domanda che ti eri davvero posto. Ogni volta che i coefficienti categoriali di un modello ti confondono, controlla prima il livello di riferimento.
(Per un riordino completo, non solo del primo posto, passa di nuovo a factor() un vettore levels = completo.)
La trappola classica: convertire un factor in numero
A volte i numeri arrivano come factor, tipicamente una colonna di un CSV che conteneva un valore non numerico sparso. Riconvertirli sembra ovvio e va storto in modo memorabile:
as.numeric(f) restituisce 2 1 3. Non 20, 10, 30, ma i codici dei livelli. I livelli si ordinano alfabeticamente come "10", "20", "30", quindi "20" è il livello 2 e si converte in... 2. Nessun errore, nessun warning, piccoli interi dall'aspetto plausibile che sostituiscono in silenzio i tuoi dati. Per questo sono state ritirate delle analisi pubblicate.
La strada corretta passa per character: as.numeric(as.character(f)) prima recupera le etichette come testo, poi interpreta il testo come numeri: 20 10 30. Imprimiti bene questo idioma: da factor a numero si passa sempre per as.character().
droplevels() e la storia di stringsAsFactors
Il subsetting di un factor conserva l'insieme completo dei livelli, anche per le categorie che non compaiono più:
Dopo aver escluso large, table() la riporta ancora, con conteggio 0. A volte è esattamente giusto (vuoi che la categoria vuota sia visibile). Quando non lo è, perché i gruppi a conteggio zero ingombrano i grafici e possono rompere le analisi stratificate, droplevels() scarta i livelli senza osservazioni.
Una nota storica che ti servirà leggendo codice vecchio o risposte su Stack Overflow: prima di R 4.0 (2020), data.frame() e read.csv() convertivano automaticamente ogni colonna character in factor, perché stringsAsFactors = TRUE era il valore predefinito. Un decennio di tutorial è pieno di soluzioni per factor che nessuno aveva chiesto. Da R 4.0 il valore predefinito è FALSE: le stringhe restano stringhe, e crei i factor deliberatamente, dove una variabile del tuo data frame è davvero categoriale. È l'abitudine giusta: factor espliciti, di proposito, con livelli scelti da te.
Cosa ti porti a casa
- Un factor = codici interi + etichette dei livelli; è ciò che dice alle funzioni statistiche che una variabile è categoriale.
- Controlla l'insieme e l'ordine delle categorie con
levels =, rinominale conlabels =, contale contable(). ordered = TRUEabilita i confronti per le scale davvero ordinali.- Il primo livello è la baseline del modello: impostalo deliberatamente con
relevel(f, ref = ...). - Mai
as.numeric(f)direttamente: sempreas.numeric(as.character(f)). droplevels()elimina i livelli inutilizzati dopo il subsetting; da R 4.0 le stringhe restano stringhe a meno che tu non crei i factor.
Prossimo passo: i data frame, dove factor, numeri e testo convivono come colonne di un'unica tabella.
Domande frequenti
Cos'è un factor in R?
Un factor è il tipo di R per i dati categoriali, cioè valori presi da un insieme fisso di possibilità chiamate livelli. Internamente è un vettore di codici interi più una tabella di etichette dei livelli, ed è questo che permette alle funzioni statistiche di trattare correttamente le categorie (contarle, codificarle come variabili dummy nei modelli) invece di trattarle come testo libero.
Come si converte un factor in numerico in R?
Passa per character: as.numeric(as.character(f)). Chiamare direttamente as.numeric(f) restituisce i codici interni dei livelli (1, 2, 3, ...), non i valori mostrati dalle etichette, quindi un factor che mostra "20" può tornare come 2. È uno dei bug silenziosi più comuni in R.
Cosa fa relevel() in R?
Sposta un livello scelto in prima posizione: relevel(group, ref = "control"). Il primo livello è la categoria di riferimento (baseline) con cui funzioni di modellazione come lm() e glm() confrontano ogni altro livello, quindi sceglierlo deliberatamente fa sì che i coefficienti della regressione significhino ciò che intendi.
Perché il mio factor mostra ancora livelli che ho rimosso?
Fare il subsetting di un factor conserva l'insieme completo dei livelli anche quando alcuni non compaiono più, quindi table() mostra categorie con conteggio zero e i modelli riservano ancora spazio per loro. Esegui droplevels() sul sottoinsieme per scartare i livelli inutilizzati.