Filtrare le righe: la maschera logica
Per filtrare un data frame in R, metti una condizione nella posizione delle righe tra le parentesi quadre: df[condition, ]. La condizione produce un vettore di TRUE/FALSE, uno per riga, e R tiene le righe TRUE:
Leggi scores[scores$score > 80, ] dall'interno verso l'esterno: scores$score > 80 produce TRUE FALSE TRUE TRUE FALSE, e le parentesi tengono le righe 1, 3 e 4. La virgola finale non è facoltativa. Le parentesi su un data frame accettano [rows, columns]; lasciare vuota la posizione delle colonne significa "tutte le colonne". Dimentica la virgola e starai indicizzando le colonne: uno degli errori da principiante più comuni in R.
Nota che i numeri di riga stampati sono 1 3 4, non 1 2 3: il filtro conserva le etichette di riga originali. Innocuo, ma sorprende molte persone.
Più condizioni: & e | (non &&)
Combina le condizioni con & (AND) e | (OR). Ogni condizione ha il suo confronto completo:
La trappola: R ha anche && e ||, e qui non sono intercambiabili con & e |. Le forme doppie funzionano su valori singoli (esistono per le condizioni degli if); se ricevono colonne intere, le versioni moderne di R (4.3+) si fermano con un errore come 'length = 5' in coercion to 'logical(1)', mentre le versioni più vecchie confrontavano in silenzio solo la prima riga, il che è probabilmente peggio. Dentro le parentesi, sempre & e | singoli. La pagina sugli operatori tratta la distinzione per intero.
%in%: confrontare con un insieme di valori
Quando una colonna deve corrispondere a uno qualsiasi tra diversi valori, non concatenare == con |: usa %in%:
x %in% set restituisce TRUE ovunque x sia uno dei valori in set. Si legge meglio di status == "pending" | status == "shipped", funziona con qualsiasi numero di valori e si nega in modo pulito: !(orders$status %in% c("refunded")).
Selezionare le colonne
La posizione delle colonne tra le parentesi accetta nomi o posizioni:
Due note. La selezione per nome sopravvive al riordino delle colonne; la selezione per posizione (scores[, c(1, 3)]) si rompe il giorno in cui qualcuno inserisce una colonna. E chiedere una sola colonna restituisce un semplice vettore, non un data frame: ecco perché il secondo print() mostra 91 88 senza una tabella intorno. Quando devi mantenere la forma di data frame, aggiungi drop = FALSE: scores[, "score", drop = FALSE].
subset(): la riga singola amichevole di R base
R base include una funzione che gestisce righe e colonne in una chiamata leggibile, senza $ e senza contare le virgole:
Dentro subset() scrivi i nomi delle colonne nudi (score, non scores$score): la funzione li valuta rispetto al data frame. Questo si chiama valutazione non standard, e porta con sé un'avvertenza documentata: risolve i nomi al momento dell'esecuzione in modi che si comportano male dentro le tue funzioni (una variabile chiamata score nella tua funzione può essere oscurata da una colonna chiamata score). La regola pratica, presa direttamente da ?subset: ottima in console, da evitare quando programmi; lì usa l'indicizzazione con le parentesi.
La trappola di NA
Un confronto con NA dà NA, non FALSE, e il filtro con le parentesi tiene le righe con maschera NA come righe piene di NA:
Il primo risultato contiene una riga spazzatura di NA perché la condizione della riga 2 non era né TRUE né FALSE. La soluzione è richiedere esplicitamente !is.na(). Sia subset() sia filter() di dplyr eliminano in silenzio le righe con condizione NA: comodo, ma sappi che sta succedendo. La pagina sui valori mancanti spiega perché NA si propaga così.
Il modo dplyr: filter() e select()
Il pacchetto dplyr divide il lavoro in due verbi, filter() per le righe e select() per le colonne, con nomi di colonna nudi e senza ripetere df$ (frammento statico; la sandbox esegue solo R base):
library(dplyr)
scores |> filter(score > 80)
scores |> filter(score > 80, team == "red") # comma = AND
scores |> filter(status %in% c("pending", "shipped"))
scores |> select(name, score)
scores |> filter(team == "red") |> select(name, score)
filter() elimina automaticamente le righe con condizione NA e restituisce sempre un data frame (mai un vettore nudo), eliminando entrambe le trappole di R base viste sopra. Il prezzo è una dipendenza da un pacchetto e le stesse avvertenze sulla valutazione non standard di subset(): vedi l'introduzione a dplyr per il giro completo dei verbi.
Cosa ti porti a casa
df[condition, ]è l'idioma fondamentale, e la virgola è obbligatoria.- Combina le condizioni con
&e|singoli;&&dà errore sui vettori. %in%batte i==concatenati per il confronto con un insieme di valori.- Seleziona le colonne per nome, e ricorda che una colonna singola diventa un vettore a meno di usare
drop = FALSE. subset()è la comoda riga singola per la console; le parentesi quadre sono la versione adatta alla programmazione.- I confronti con
NAproducono righe fantasma con le parentesi: proteggiti con!is.na().
Prossimo passo: aggiungere e trasformare colonne con df$new <- ..., ifelse() e mutate() di dplyr.
Domande frequenti
Come si filtrano le righe di un data frame in R?
Metti una condizione logica nella posizione delle righe tra le parentesi quadre: df[df$score > 80, ]. La condizione produce un vettore di TRUE/FALSE e R tiene le righe TRUE. La virgola conta: separa il filtro sulle righe dal filtro (vuoto) sulle colonne. subset(df, score > 80) fa lo stesso scrivendo meno.
Come si filtra con più condizioni in R?
Combina le condizioni con & (AND) e | (OR): df[df$score > 80 & df$team == "red", ]. Usa la & singola, non &&: la forma doppia funziona solo su valori singoli e nelle versioni moderne di R dà errore sui vettori.
Qual è la differenza tra subset() e il filtro con le parentesi quadre in R?
Tengono le stesse righe, con due differenze: subset() elimina in silenzio le righe in cui la condizione è NA (le parentesi le tengono come righe piene di NA), e subset() usa la valutazione non standard: scrivi i nomi delle colonne nudi, il che è comodo in console ma inaffidabile dentro le tue funzioni.
Come si filtrano le righe in cui una colonna corrisponde a una lista di valori?
Usa %in%: df[df$team %in% c("red", "blue"), ] tiene le righe il cui team è uno qualsiasi dei valori elencati. Sostituisce una catena di confronti == uniti da | e, a differenza di ==, non restituisce mai NA.