R è un noto lin­guag­gio di pro­gram­ma­zio­ne, uti­liz­za­to prin­ci­pal­men­te per eseguire calcoli sta­ti­sti­ci nel campo delle scienze e della ma­te­ma­ti­ca. È un lin­guag­gio in­te­res­san­te con delle ca­rat­te­ri­sti­che molto peculiari. Una volta ac­qui­sta­ta fa­mi­lia­ri­tà con la sintassi, lavorarci diventa molto gradevole.

Quali sono le prin­ci­pa­li ca­rat­te­ri­sti­che del lin­guag­gio di pro­gram­ma­zio­ne R?

R non è un lin­guag­gio di pro­gram­ma­zio­ne “general-purpose” come possono essere Java o Python. Al contrario, viene usato nell’ambito dello sta­ti­sti­cal computing, in italiano “calcolo sta­ti­sti­co”. No­no­stan­te la massiccia con­cor­ren­za in questo settore, R si situa da anni fra i 20 linguaggi di pro­gram­ma­zio­ne più popolari.

A rendere R così speciale non è solo il lin­guag­gio in sé, ma tutto il contorno. Infatti, nor­mal­men­te la sua pro­gram­ma­zio­ne avviene in un ambiente in­te­rat­ti­vo, completo di Read-Eval-Print Loop (REPL) e di supporto integrato. Questo lin­guag­gio open source è sup­por­ta­to da un eco­si­ste­ma molto svi­lup­pa­to: il re­po­si­to­ry dei pacchetti “The Com­pre­hen­si­ve R Archive Network” (CRAN) è gestito dalla community. Inoltre, questa fornisce in modo con­ti­nua­ti­vo record di dati e white paper scien­ti­fi­ci che il­lu­stra­no nuovi approcci e mettono a di­spo­si­zio­ne nuovi pacchetti.

Insieme, queste ca­rat­te­ri­sti­che fanno di R l’ambiente di pro­gram­ma­zio­ne perfetto per il calcolo sta­ti­sti­co e la data science. Il suo carattere in­te­rat­ti­vo invita alla spe­ri­men­ta­zio­ne: consente un ap­pren­di­men­to giocoso del lin­guag­gio e dei calcoli ma­te­ma­ti­ci che ne stanno alla base.

R è un lin­guag­gio di pro­gram­ma­zio­ne specifico per la sta­ti­sti­ca e l’ela­bo­ra­zio­ne di dati

R è un lin­guag­gio di pro­gram­ma­zio­ne sta­ti­sti­ca e si basa su concetti come la di­stri­bu­zio­ne normale, i test sta­ti­sti­ci, i modelli e la re­gres­sio­ne. Esistono alcuni linguaggi scien­ti­fi­ci com­pa­ra­bi­li a R: oltre a Matlab ri­cor­dia­mo Julia, un lin­guag­gio ab­ba­stan­za giovane, ma comunque degno di nota.

Negli ultimi anni, in ambito sta­ti­sti­co si è affermato anche l’uso di Python. Ma, a dif­fe­ren­za di questo, R dispone di un supporto nativo per la pro­gram­ma­zio­ne sta­ti­sti­ca. Opera sui valori in modo diverso dagli altri linguaggi: è questa la sua ca­rat­te­ri­sti­ca di spicco. So­li­ta­men­te sono di­spo­ni­bi­li più valori con­tem­po­ra­nea­men­te, pertanto questo lin­guag­gio tende a elaborare più dati alla volta. In R il valore più semplice è raramente un singolo numero.

Di seguito pre­sen­tia­mo un facile esempio che ci per­met­te­rà di esaminare da vicino come avviene l’ela­bo­ra­zio­ne di dati in R. In ogni lin­guag­gio di pro­gram­ma­zio­ne è possibile eseguire ope­ra­zio­ni ma­te­ma­ti­che e lo stesso vale per R. Pro­ce­dia­mo a sommare due numeri:

# returns 15
10 + 5
R

Fin qui nulla di speciale. In R è possibile applicare questa stessa ope­ra­zio­ne (addizione) a una serie di numeri. Rag­grup­pia­mo quindi due numeri in un elenco e ag­giun­gia­mo un valore costante:

# returns 15, 25
c(10, 20) + 5
R

Per pro­gram­ma­to­ri e pro­gram­ma­tri­ci con una certa espe­rien­za si tratta senz’altro di un risultato sor­pren­den­te. Infatti, nemmeno Python in tutta la sua di­na­mi­ci­tà e modernità consente questo tipo di calcolo:

# throws an error
[10, 20] + 5
R

Con R è ad­di­rit­tu­ra possibile sommare due liste. A tal proposito gli elementi della lista non vengono uniti in una sola lista, ma si esegue l’ope­ra­zio­ne ma­te­ma­ti­ca ap­pro­pria­ta per ciascun elemento:

# returns 42, 69
c(40, 60) + c(2, 9)
R

Nei linguaggi più tra­di­zio­na­li come Java o C++, per elaborare più elementi di una lista è ne­ces­sa­rio usare un ciclo. Infatti, questi linguaggi operano una netta di­stin­zio­ne fra com­po­nen­ti singoli (gli scalari) e le strutture di dati compositi (i vettori). Nel lin­guag­gio di pro­gram­ma­zio­ne R, il vettore è con­si­de­ra­to l’unità di base, mentre lo scalare sotto forma di vettore, composto da un solo elemento, è con­si­de­ra­to un’eccezione.

Nella sta­ti­sti­ca la pro­ver­bia­le pre­ci­sio­ne ma­te­ma­ti­ca tende a venire meno. Infatti, la sta­ti­sti­ca tiene in con­si­de­ra­zio­ne in­cer­tez­ze e dati im­per­fet­ti ricavati da un contesto reale. C’è sempre la pos­si­bi­li­tà che qualcosa non vada secondo i piani. For­tu­na­ta­men­te, R presenta una certa tol­le­ran­za agli errori. Ad esempio, è in grado di gestire i valori mancanti senza causare il crash di uno script.

Ora di­mo­stria­mo la solidità di questo lin­guag­gio mediante un altro esempio. In linea di massima, dividendo un qualsiasi numero per zero in qualsiasi lin­guag­gio di pro­gram­ma­zio­ne, si genererà un’eccezione con con­se­guen­te crash. In R non è così: qui una divisione per zero genera il valore Inf, con­sen­ten­do in un secondo momento una facile pulizia dei dati, eseguita filtrando il valore.

# list of divisors, containing zero
divisors = c(2, 4, 0, 10)
# returns `c(50, 25, Inf, 10)`
quotients = 100 / divisors
# filter out Inf; returns `c(50, 25, 10)`
cleaned_quotients = quotients[quotients != Inf]
R

R supporta la pro­gram­ma­zio­ne orientata agli oggetti (OOP) e la pro­gram­ma­zio­ne fun­zio­na­le

La pro­gram­ma­zio­ne con R è alquanto fles­si­bi­le: risulta pertanto difficile inserire con chiarezza questo lin­guag­gio nella gerarchia dei paradigmi di pro­gram­ma­zio­ne. Infatti, pur esistendo un sistema di OOP a sostegno di questo lin­guag­gio, vengono com­ple­ta­men­te meno le classiche de­fi­ni­zio­ni delle classi. Nell’uso quo­ti­dia­no, in prima linea si usano approcci im­pe­ra­ti­vi e di tipo fun­zio­na­le. In par­ti­co­la­re risultano molto ben definite le ca­rat­te­ri­sti­che fun­zio­na­li adatte all’ela­bo­ra­zio­ne dei dati.

Come in Ja­va­Script, questo sistema a oggetti spicca per la sua fles­si­bi­li­tà. Le funzioni generiche sono com­pa­ra­bi­li a Python e possono essere applicate su oggetti di diverso tipo. Ad esempio, nella pro­gram­ma­zio­ne R esiste la funzione length(), simile a quella len() di Python.

Come funziona la pro­gram­ma­zio­ne R?

Nella pro­gram­ma­zio­ne R tutto ruota intorno ai dati poiché questi stanno alla base del calcolo sta­ti­sti­co. Per svi­lup­pa­re una soluzione a un problema in R, è ne­ces­sa­rio un record di dati. Purtroppo spesso tale record di dati non è ancora di­spo­ni­bi­le al momento dello sviluppo del codice. Pertanto, un progetto di pro­gram­ma­zio­ne in R spesso parte da una si­mu­la­zio­ne di dati. Scriviamo il codice, ne testiamo la fun­zio­na­li­tà e in un secondo momento so­sti­tuia­mo i dati di prova con dati reali.

Come si esegue il codice R?

Come Ruby o Python, R è un lin­guag­gio di scripting dinamico e in­ter­pre­ta­to. Qui non esiste alcuna di­stin­zio­ne fra codice sorgente e codice ese­gui­bi­le, a dif­fe­ren­za del lin­guag­gio di pro­gram­ma­zio­ne C. Lo sviluppo del codice avviene per la maggior parte in modo in­te­rat­ti­vo, ovvero l’in­ter­pre­te viene istruito, riga per riga, tramite il codice sorgente la cui ese­cu­zio­ne avviene im­me­dia­ta­men­te. Le variabili vengono create in au­to­ma­ti­co a seconda del bisogno, i nomi sono legati al tempo di ese­cu­zio­ne.

Usando questa pro­gram­ma­zio­ne in­te­rat­ti­va e dinamica è come se ci si trovasse all’interno di un programma in ese­cu­zio­ne. È possibile esaminare e mo­di­fi­ca­re gli oggetti già creati e allo stesso modo è possibile testare au­to­ma­ti­ca­men­te nuove idee. Il comando help consente l’accesso alla do­cu­men­ta­zio­ne di sintassi e funzioni:

# view help for `for` syntax
help('for')
# view help for `c()` function
help(c)
R

Dall’in­ter­pre­te è possibile caricare in modo dinamico file di script. Il comando source funziona allo stesso modo del comando shell, che si considera equi­va­len­te. Durante la chiamata si legge il contenuto del testo sorgente R, che viene inserito nella sessione in corso.

source('path/to/file.r')
R

Com’è la sintassi del lin­guag­gio R?

Il lin­guag­gio di scripting fa uso delle parentesi graffe usate in C e Java per de­li­mi­ta­re i corpi da funzioni e istru­zio­ni di controllo. Al contrario di Python, l’in­den­ta­zio­ne del codice non influisce sulla sua funzione. Come in Ruby e in Python, i commenti iniziano con un can­cel­let­to; alla fine di un’istru­zio­ne è ne­ces­sa­rio il punto e virgola.

Con un po’ di espe­rien­za è possibile ri­co­no­sce­re im­me­dia­ta­men­te il codice di R, perché il lin­guag­gio presenta alcune pe­cu­lia­ri­tà. Oltre a impiegare il segno uguale come operatore di as­se­gna­zio­ne, la pro­gram­ma­zio­ne R fa uso anche di due operatori simili a una freccia -> e <-. In questo modo è possibile invertire la direzione dell’as­se­gna­men­to:

# equivalent assignments
age <- 42
'Jack' -> name
person = c(age, name)
R

Un’ulteriore ca­rat­te­ri­sti­ca del codice R è l’an­no­ta­zio­ne pseudo-oggetto secondo lo schema object.method():

# test if argument is a number
is.numeric(42)
R

Ap­pa­ren­te­men­te, la funzione is.numeric sembra un metodo numeric() ap­par­te­nen­te a un oggetto di nome is. Ma le cose in realtà stanno di­ver­sa­men­te. Nella pro­gram­ma­zio­ne R, il punto è con­si­de­ra­to un carattere regolare; pertanto la funzione si potrebbe scrivere anche is_numeric invece di is.numeric.

Per generare i vettori, im­por­tan­tis­si­mi nella pro­gram­ma­zio­ne R, si fa ricorso alla funzione di con­ca­te­na­zio­ne c():

people.ages <- c(42, 51, 69)
R

Se si applica la funzione ai vettori, questi vengono uniti in un vettore continuo.

# yields `c(1, 2, 3, 4)`
c(c(1, 2), c(3, 4))
R

A dif­fe­ren­za della maggior parte dei linguaggi di pro­gram­ma­zio­ne, in R l’in­di­ciz­za­zio­ne degli elementi di un vettore inizia da 1. Ini­zial­men­te può essere ne­ces­sa­rio abituarsi a questa pe­cu­lia­ri­tà, ma questo aiuta a evitare i temuti errori logici di tipo off by one. L’indice più elevato di un vettore cor­ri­spon­de alla lunghezza del vettore stesso:

# create a vector of names
people <- c('Jack', 'Jim', 'John')
# access the first name
people[1] == 'Jack'
# access the last name
people[length(people)] == 'John'
R

Come in Python, anche nella pro­gram­ma­zio­ne R ri­tro­via­mo il concetto di slicing. Con una slice è possibile in­di­ciz­za­re una porzione di un vettore. Questa si basa su sequenze che in R vengono sup­por­ta­te in modo nativo. Generiamo una sequenza di numeri e ne se­le­zio­nia­mo una porzione:

# create vector of numbers between 42 and 69
nums = seq(42, 69)
# equivalent assignment using sequence notation
nums = 42:69
# using a sequence, slice elements 3 through 7
sliced = nums[3:7]
R

Come fun­zio­na­no le strutture di controllo nella pro­gram­ma­zio­ne R?

Le ope­ra­zio­ni di base nella pro­gram­ma­zio­ne R sono ap­po­si­ta­men­te definite per i vettori. In questo modo spesso non è ne­ces­sa­rio creare dei cicli, ma si esegue un’ope­ra­zio­ne di­ret­ta­men­te sull’intero vettore, mo­di­fi­can­do­ne però i singoli elementi. Di seguito facciamo quadrare i primi dieci numeri positivi senza ciclo:

nums <- seq(10)
squares <- nums ** 2
squares[3] == 9
R

Quando si usa il ciclo for in R è ne­ces­sa­rio tenere in con­si­de­ra­zio­ne che questo non funziona come in C, Java o Ja­va­Script. Infatti, l’ite­ra­zio­ne viene eseguita di­ret­ta­men­te sugli elementi come in Python, senza dover impiegare una variabile in sequenza:

people = c('Jim', 'Jack', 'John')
for (person in people) {
    print(paste('Here comes', person, sep = ' '))
}
R

Na­tu­ral­men­te la ra­mi­fi­ca­zio­ne if else in R esiste e viene usata come struttura di controllo di base. Tuttavia, in molti casi anche questa può essere so­sti­tui­ta da funzioni filtro o tramite l’in­di­ciz­za­zio­ne logica di vettori. Creiamo un vettore con in­for­ma­zio­ni ri­guar­dan­ti l’età e filtriamo ri­spet­ti­va­men­te le persone maggiori di 18 anni mediante due variabili, senza dover usare alcun ciclo o ra­mi­fi­ca­zio­ne:

# create 20 ages between 1 and 99
ages = as.integer(runif(20, 1, 99))
# filter adults
adults = ages[ages > 18]
# filter children
children = ages[ages < 18]
# make sure everyone is accounted for
length(adults) + length(children) == length(ages)
R

Ora vi pre­sen­tia­mo invece l’approccio equi­va­len­te tramite strutture di controllo:

# create 20 ages between 1 and 99
ages = as.integer(runif(20, 1, 99))
# start with empty vectors
adults = c()
children = c()
# populate vectors
for (age in ages) {
    if (age > 18) {
        adults = c(adults, age)
    }
    else {
        children = c(children, age)
    }
}
R

Cosa serve per iniziare a pro­gram­ma­re in R?

Per poter iniziare a pro­gram­ma­re in R, è suf­fi­cien­te in­stal­la­re l’apposito programma locale “installer”. Questo è di­spo­ni­bi­le gra­tui­ta­men­te e può essere scaricato nella maggior parte dei sistemi operativi. L’in­stal­la­zio­ne standard di R comprende un in­ter­pre­te GUI con REPL, il supporto integrato e l’editor. Affinché la pro­gram­ma­zio­ne risulti pro­dut­ti­va, con­si­glia­mo di scegliere fra gli editor di codice più co­no­sciu­ti. RStudio di Posit offre un’in­te­res­san­te al­ter­na­ti­va all’ambiente R.

Per quali tipi di progetto è adatto R?

Spesso, la pro­gram­ma­zio­ne R trova ampio impiego nelle scienze e nella ricerca, ad esempio nella bio­in­for­ma­ti­ca e nell’ap­pren­di­men­to au­to­ma­ti­co. Tuttavia, il lin­guag­gio è adatto per tutti i progetti che si servono della mo­del­la­zio­ne sta­ti­sti­ca o dei modelli ma­te­ma­ti­ci. È invece meno adatto per pro­ces­sa­re testi: in questo caso Python risulta net­ta­men­te più indicato.

R può essere usato per so­sti­tui­re i classici calcoli e le vi­sua­liz­za­zio­ni nor­mal­men­te contenute in fogli di calcolo. In questo modo i dati e il codice non vengono mescolati nelle celle, con­sen­ten­do una migliore or­ga­niz­za­zio­ne e una chiara se­pa­ra­zio­ne delle attività. Basta scrivere il codice una sola volta: questo verrà quindi applicato a più record. Inoltre, non vi è alcun rischio di so­vra­scri­ve­re la formula di una cella in caso di modifiche manuali.

Per le pub­bli­ca­zio­ni scien­ti­fi­che, R è con­si­de­ra­to il sistema aureo dei linguaggi macchina: è proprio la sud­di­vi­sio­ne del codice dai dati a con­sen­ti­re la ri­pro­du­ci­bi­li­tà scien­ti­fi­ca. Il so­fi­sti­ca­to sistema di strumenti e pacchetti offerti da R consente di creare delle pipeline di pub­bli­ca­zio­ne più ef­fi­cien­ti. Va­lu­ta­zio­ni e vi­sua­liz­za­zio­ni si generano au­to­ma­ti­ca­men­te da codice e dati, per poi essere integrate in documenti LaTeX o RMarkdown ben strut­tu­ra­ti.

Consiglio

Partite da una base solida per il vostro sito web: ac­qui­sta­te lo spazio web a un prezzo van­tag­gio­so su IONOS!

Vai al menu prin­ci­pa­le