Menu

Vettori in R: c(), seq(), indicizzazione e calcolo vettorizzato

I vettori sono l'unità fondamentale di R: anche un singolo numero è un vettore. Come crearli con c(), indicizzarli (da 1!), filtrarli con maschere logiche e fare calcoli su interi vettori in una volta.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

In R tutto è un vettore

La maggior parte dei linguaggi ha gli scalari, cioè valori singoli, e poi un tipo contenitore per tenerne diversi. R salta lo scalare. Un vettore è una raccolta ordinata di valori che condividono tutti lo stesso tipo, ed è l'unità su cui è costruito tutto il resto. Anche quello che sembra un numero isolato è un vettore di lunghezza 1:

c(), abbreviazione di combine, è il modo per costruire un vettore a mano. length() ti dice quanti elementi contiene. E 5 da solo risulta TRUE per is.vector, con lunghezza 1: R non smette mai di lavorare con i vettori, a volte lavora solo con vettori molto corti.

È per questo che il codice R ha un aspetto diverso da Python o JavaScript: le operazioni per cui altrove scriveresti un ciclo si applicano a interi vettori in un'unica espressione. Ci arriviamo più avanti.

Una regola da interiorizzare subito: tutti gli elementi di un vettore hanno lo stesso tipo. Se passi a c() un miscuglio, non si lamenta: converte tutto in silenzio nel tipo più flessibile presente:

Una stringa nel miscuglio trasforma tutto in stringhe ("1", "TRUE"). I valori logici in mezzo ai numeri diventano 1 e 0. Questa coercizione segue una gerarchia fissa, logical → integer → double → character, e avviene senza alcun avviso: ecco perché un "7" capitato per caso in una colonna di numeri può trasformare in silenzio l'intero dataset in testo. La gerarchia completa è spiegata in tipi di dati; se ti serve contenere valori davvero misti, a questo servono le liste.

Generare sequenze: :, seq() e rep()

Scrivere ogni elemento dentro c() stanca presto. R ha tre scorciatoie per gli schemi regolari:

  • 1:10 è quella di tutti i giorni: interi da un estremo all'altro, con passo 1.
  • seq() la generalizza: scegli il passo con by =, oppure indica quanti elementi vuoi con length.out = e lascia che R calcoli la spaziatura.
  • seq_len(n) produce i numeri da 1 a n ed è il modo sicuro di costruire gli indici di un ciclo: a differenza di 1:n, quando n è 0 dà correttamente un vettore vuoto invece di contare all'indietro 1 0.
  • rep() ripete: times = ripete l'intero vettore da capo a fondo (1 2 1 2 1 2), each = ripete ogni elemento al suo posto (1 1 1 2 2 2). È facile confonderli; esegui l'esempio e confronta.

Indicizzazione: R conta da 1

Le parentesi quadre estraggono gli elementi. Il primo elemento è [1], non [0]. Se arrivi da Python o JavaScript, questo è in assoluto l'inciampo iniziale più comune:

Tre cose su cui vale la pena fermarsi:

  • Puoi indicizzare con un vettore di posizioni: fruits[c(2, 4)] prende il secondo e il quarto in un colpo solo.
  • Gli indici negativi significano "tutto tranne". fruits[-1] è il vettore senza il primo elemento. È completamente diverso da Python, dove -1 indica l'ultimo elemento. Non puoi mescolare indici positivi e negativi nella stessa chiamata.
  • fruits[0] non è un errore: restituisce un character(0) vuoto. In R un errore di uno spesso produce risultati vuoti silenziosi invece di un crash, quindi conviene controllare length() quando qualcosa più avanti sembra misteriosamente vuoto.

Gli elementi possono anche avere dei nomi, e questo ti dà un terzo modo di indicizzare, per etichetta:

I vettori con nomi funzionano come una piccola tabella di ricerca e mantengono il codice leggibile: prices["tea"] dice quello che intende, prices[2] no.

Maschere logiche e which()

Il modo più potente di indicizzare è con un vettore logico, una maschera di valori TRUE/FALSE lunga quanto i dati. Qualsiasi confronto su un vettore produce esattamente questo:

temps > 24 non dà una risposta: ne dà cinque, una per elemento. Mettendo quella maschera dentro [ ] tieni gli elementi in cui la maschera è TRUE. Combina le condizioni con & (e) e | (o), spiegati insieme al resto degli operatori.

which() traduce una maschera in posizioni: qui 2 3 5, gli indici delle temperature alte. Usalo quando ti serve sapere dove sono le corrispondenze, per riportarle o per indicizzare un altro vettore negli stessi punti. Per filtrare e basta, temps[temps > 24] è più diretto di temps[which(temps > 24)].

Questo schema del filtro con una maschera è la spina dorsale di praticamente tutto il lavoro sui dati in R, e lo ritroverai subito quando filtrerai le righe di un data frame.

Calcolo vettorizzato e regola del riciclo

In R l'aritmetica si applica elemento per elemento su interi vettori, senza bisogno di cicli:

La prima riga è la caratteristica principale: prices * 2 raddoppia ogni elemento. Dove altri linguaggi hanno bisogno di un ciclo for, a R basta un operatore, e la forma vettorizzata è sia più breve sia più veloce, perché il ciclo avviene sotto, in C ottimizzato. Scrivi un ciclo for quando ogni passo dipende dal precedente; per i calcoli elemento per elemento, vettorizza.

La terza riga mostra la regola del riciclo: quando i vettori hanno lunghezze diverse, R ripete quello più corto per pareggiarli. c(10, 20) viene riciclato in 10 20 10 20, e il risultato è 11 22 13 24. Riciclare 2 su un vettore di lunghezza 3 è esattamente ciò che ha fatto funzionare prices * 2: uno scalare è solo un vettore di lunghezza 1 che viene riciclato.

Il riciclo è pulito quando la lunghezza maggiore è un multiplo esatto di quella minore. Quando non lo è, R calcola comunque un risultato, ma emette un avviso:

Ottieni 11 22 13 più un avviso che dice che la lunghezza dell'oggetto più lungo non è un multiplo della lunghezza di quello più corto. Considera quell'avviso una segnalazione di bug: un riciclo parziale non è quasi mai quello che intendevi, e di solito significa che due vettori che dovevano avere la stessa lunghezza non ce l'hanno.

Ordinare, invertire, togliere i duplicati

Tre piccole utilità che userai di continuo:

sort() ordina i valori, rev() inverte l'ordine esistente senza ordinare e unique() elimina i duplicati tenendo le prime occorrenze. Nessuna di queste modifica x: come quasi tutto in R, restituiscono un nuovo vettore e lasciano intatto l'originale.

Cosa ti porti a casa

  • Il vettore è l'unità fondamentale di R: ordinato, con un solo tipo per tutti gli elementi, e anche i valori singoli sono vettori di lunghezza 1.
  • Costruiscili con c(), genera schemi con :, seq() e rep(), e ricorda che c() converte in silenzio i tipi misti.
  • L'indicizzazione parte da 1; gli indici negativi tolgono elementi; i nomi ti permettono di indicizzare per etichetta.
  • Le maschere logiche (x[x > 5]) sono il modo di filtrare di tutto il linguaggio; which() trasforma una maschera in posizioni.
  • Il calcolo è vettorizzato, i vettori più corti vengono riciclati, e un avviso di riciclo parziale significa che hai un bug.

Prossimo passo: le liste, il contenitore per quando i tuoi valori non condividono tutti lo stesso tipo.

Domande frequenti

Come si crea un vettore in R?

Con la funzione c() (abbreviazione di combine): x <- c(10, 20, 30). Per le sequenze regolari usa 1:10, seq(0, 1, by = 0.25) o rep(0, 5). Tutti gli elementi devono finire per avere lo stesso tipo: se mescoli i tipi, R li converte tutti in silenzio in quello più flessibile.

In R l'indicizzazione parte da 0 o da 1?

Da 1. x[1] è il primo elemento, x[length(x)] è l'ultimo. Questo fa inciampare chiunque arrivi da Python, JavaScript o C: non esiste un elemento x[0] (chiederlo restituisce un vettore vuoto, non un errore, e così il bug resta silenzioso).

Cosa fa la regola del riciclo in R?

Quando fai calcoli su due vettori di lunghezza diversa, R ripete quello più corto finché non raggiunge la lunghezza di quello più lungo. c(1, 2, 3, 4) + c(10, 20) dà 11 22 13 24. Se la lunghezza maggiore non è un multiplo di quella minore, R calcola comunque un risultato ma emette un avviso: considera quell'avviso un bug.

Cosa fa which() in R?

Converte un vettore logico nelle posizioni dei suoi valori TRUE. Se x > 5 dà FALSE TRUE TRUE, allora which(x > 5) dà 2 3. Usalo quando ti servono proprio le posizioni; per filtrare e basta, indicizzare direttamente con il vettore logico (x[x > 5]) è più semplice.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA