Vettorizzazione per aumentare la velocità
Sostituisca i cicli espliciti con operazioni vettorializzate per ottenere notevoli incrementi di velocità
Vettorizzazione per aumentare la velocità è una lezione R Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento R Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso R Academy include 4 lezioni in totale.
Perché la vettorializzazione è importante
R è un linguaggio interpretato, quindi i cicli for comportano un sovraccarico a ogni iterazione: dispatch delle chiamate di funzione, controllo dei limiti e coercizione dei tipi. Le operazioni vettorializzate spostano questo lavoro nel codice C compilato, che viene eseguito molto più velocemente.
La vettorializzazione è l’ottimizzazione più efficace disponibile in R base.
Esempio di ciclo con cumsum()
Il confronto tra il calcolo di un totale progressivo con un ciclo for e la funzione integrata cumsum() mostra chiaramente la differenza. cumsum() richiama codice compilato a livello C ed elabora l’intero vettore in un’unica passata.
n <- 500000
x <- rnorm(n)
t_loop <- system.time({
result <- numeric(n)
result[1] <- x[1]
for (i in 2:n) result[i] <- result[i-1] + x[i]
})['elapsed']
t_vec <- system.time({
result2 <- cumsum(x)
})['elapsed']
cat('Loop :', t_loop, 's
')
cat('cumsum:', t_vec, 's
')ifelse() contro for + if
ifelse(condition, yes, no) è una condizione vettorializzata che valuta la condizione su un intero vettore in una sola volta. Sostituisce i cicli for + if elemento per elemento con un’unica passata a livello C.
n <- 300000
x <- rnorm(n)
t_loop <- system.time({
result <- numeric(n)
for (i in seq_len(n)) result[i] <- if (x[i] > 0) x[i] else -x[i]
})['elapsed']
t_vec <- system.time({
result2 <- ifelse(x > 0, x, -x)
})['elapsed']
cat('for+if :', t_loop, 's
')
cat('ifelse :', t_vec, 's
')Preallocare i vettori risultato
Quando un ciclo è inevitabile, preallochi il vettore risultato prima del ciclo. Far crescere un vettore con c(result, new_val) all’interno di un ciclo copia l’intero vettore a ogni iterazione: O(n^2) operazioni complessive sulla memoria.
n <- 20000
t_grow <- system.time({
result <- c()
for (i in seq_len(n)) result <- c(result, i^2)
})['elapsed']
t_prealloc <- system.time({
result2 <- numeric(n)
for (i in seq_len(n)) result2[i] <- i^2
})['elapsed']
cat('Growing vector:', t_grow, 's
')
cat('Pre-allocated :', t_prealloc, 's
')Tipi corretti per la preallocazione
Utilizzi il costruttore tipizzato corrispondente ai dati per evitare conversioni implicite durante la preallocazione:
numeric(n)— numeri in virgola mobile a doppia precisioneinteger(n)— numeri intericharacter(n)— stringhe vuotelogical(n)— valori FALSEvector('list', n)— lista di valori NULL
n <- 5
cat('numeric :', numeric(n), '
')
cat('integer :', integer(n), '
')
cat('logical :', logical(n), '
')
cat('character:', character(n), '
')
cat('list len :', length(vector('list', n)), '
')colSums() e rowSums() contro apply()
Per le operazioni sulle matrici, colSums(m), rowSums(m), colMeans(m) e rowMeans(m) sono routine C fortemente ottimizzate. Sono costantemente più veloci di apply(m, 1, sum), che richiama la funzione R sum una volta per riga.
m <- matrix(rnorm(1000 * 2000), nrow = 1000)
t_apply <- system.time(apply(m, 2, sum))['elapsed']
t_colsums <- system.time(colSums(m))['elapsed']
cat('apply(m,2,sum):', t_apply, 's
')
cat('colSums(m) :', t_colsums, 's
')L’aritmetica vettorializzata è sempre veloce
Le operazioni aritmetiche di base sui vettori — +, -, *, /, ^, sqrt(), log(), exp() — sono tutte vettorializzate. Operano elemento per elemento sull’intero vettore con un’unica chiamata C. Le preferisca sempre ai cicli.
x <- 1:1000000
t1 <- system.time(y <- x^2 + 2*x + 1)['elapsed']
t2 <- system.time({
y2 <- numeric(length(x))
for (i in seq_along(x)) y2[i] <- x[i]^2 + 2*x[i] + 1
})['elapsed']
cat('Vectorized:', t1, 's
')
cat('Loop :', t2, 's
')Subset logico invece dei cicli
Filtrare un vettore con una condizione logica è un'operazione vettorializzata. Invece di usare un ciclo e aggiungere elementi in base a una condizione, crei un indice logico ed esegui il subset una sola volta: il codice C sottostante effettua un'unica scansione.
x <- rnorm(500000)
t_loop <- system.time({
pos <- c()
for (v in x) if (v > 0) pos <- c(pos, v)
})['elapsed']
t_vec <- system.time({
pos2 <- x[x > 0]
})['elapsed']
cat('Loop filter:', t_loop, 's
')
cat('Logical idx:', t_vec, 's
')which() e tabulate() per lavorare con gli indici
Quando servono le posizioni dei valori TRUE, which(condition) è vettorializzato e veloce. tabulate(bin_vector) conta le occorrenze intere più velocemente di table() per intervalli di interi densi.
x <- sample(1:10, 100000, replace = TRUE)
t_table <- system.time(table(x))['elapsed']
t_tabulate <- system.time(tabulate(x, nbins = 10))['elapsed']
cat('table() :', t_table, 's
')
cat('tabulate():', t_tabulate, 's
')
idx <- which(x == 5)
cat('Positions of 5: first 5 =', head(idx, 5), '
')Quando i cicli sono ancora accettabili
Non tutti i cicli sono dannosi. I cicli sono accettabili quando:
- Ogni iterazione dipende dal risultato precedente (dipendenza sequenziale)
- Il numero di iterazioni è ridotto (< 1000)
- Il corpo del ciclo chiama una funzione complessa senza un equivalente vettorializzato
In questi casi, si concentri sulla preallocazione ed eviti di aumentare le strutture all'interno del ciclo.
# Sequential dependency -- loop is correct here
fib <- function(n) {
result <- integer(n)
result[1] <- 1L
if (n >= 2) result[2] <- 1L
for (i in seq_len(n)[-c(1,2)]) result[i] <- result[i-1] + result[i-2]
result
}
cat('Fibonacci:', fib(10), '
')Riepilogo della vettorializzazione
Regole fondamentali per ottenere codice R veloce tramite la vettorializzazione:
- Usi
cumsum/cumprod/diffper gli accumuli sequenziali - Usi
ifelse()per le condizioni elemento per elemento - Preallochi con
numeric(n)/vector('list',n) - Preferisca
colSums/rowSums/colMeans/rowMeansaapply() - Il subset logico è preferibile ai cicli di filtraggio
Controllo rapido: preallocazione
Perché aumentare un vettore con result <- c(result, new_val) all'interno di un ciclo è così lento per valori grandi di n?
Riepilogo della vettorializzazione
La vettorializzazione è il principale strumento di R per migliorare le prestazioni:
- Le funzioni vettorializzate (
cumsum,ifelse, gli operatori aritmetici) chiamano codice C compilato e sono da 10 a 100 volte più veloci degli equivalenti cicli R - Preallochi i contenitori dei risultati prima di qualsiasi ciclo inevitabile per evitare copie O(n^2)
colSums/rowSumssono più veloci diapply()per le aggregazioni sulle matrici- Il subset logico sostituisce i cicli di filtraggio in modo semplice e veloce
Domande Frequenti
La lezione «Vettorizzazione per aumentare la velocità» è gratuita?
Sì — il testo completo di «Vettorizzazione per aumentare la velocità» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso R Academy, passa a CoddyKit PRO. Il corso R Academy include 4 lezioni in totale.
Cosa imparerò in «Vettorizzazione per aumentare la velocità»?
Sostituisca i cicli espliciti con operazioni vettorializzate per ottenere notevoli incrementi di velocità Eserciti R Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare R Academy?
Non è richiesta alcuna esperienza precedente. R Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Vettorizzazione per aumentare la velocità»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione R Academy?
Sì. Ogni lezione R Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- system.time() e proc.time()
- Profilazione del codice con Rprof e profvis
- Vettorizzazione per aumentare la velocità
- Benchmark con microbenchmark