2 + 2
[1] 4
4 * (3 + 5) # La somma entro parentesi viene eseguita per prima
[1] 32
/ 4 # Pi greco quarti pi
[1] 0.7853982
Unità A: calcolo scientifico ed algebra lineare
Anzitutto, R può essere usato come se fosse una calcolatrice scientifica:
2 + 2
[1] 4
4 * (3 + 5) # La somma entro parentesi viene eseguita per prima
[1] 32
/ 4 # Pi greco quarti pi
[1] 0.7853982
Per calcolare la potenza a^b si usa:
2^5 # Sintassi alternativa: 2**5
[1] 32
Le quantità \sqrt{2} e \sin(\pi/4) si ottengono invece con i comandi:
sqrt(2)
[1] 1.414214
sin(pi / 4)
[1] 0.7071068
È possibile salvare un valore assegnandolo ad un oggetto tramite il simbolo <-
.
# Assegna il valore 5 all'oggetto x
<- sqrt(5) # Sintassi alternativa (sconsigliata): x = sqrt(5) x
Il valore contenuto in x
può essere successivamente richiamato, modificato e salvato in un nuovo oggetto, chiamato ad esempio y
.
<- x + pi # ovvero pi greco + radice quadrata di 5
y y
[1] 5.377661
Per rimuovere un oggetto dalla memoria, si usa il comando rm
, ovvero remove.
rm(x) # x non è più presente nel "workspace"
È buona norma mantenere pulito il workspace, ovvero l’ambiente di lavoro.
Se un oggetto non è più necessario, è possibile eliminarlo tramite il comando rm
.
È possibile visualizzare la lista di oggetti salvati in memoria tramite il comando seguente:
ls() # Nel workspace è presente l'oggetto y
[1] "has_annotations" "y"
Pertanto, per eliminare tutti gli oggetti salvati, si può usare
rm(list = ls())
Supponiamo che x
sia un numero reale.
Ciò che seguono sono una lista di funzioni disponibili in R:
<- 1/2 # Esempio di numero reale x
exp(x) # Esponenziale e logaritmo naturale
[1] 1.648721
log(x)
[1] -0.6931472
abs(x) # Valore assoluto
[1] 0.5
sign(x) # Funzione segno
[1] 1
sin(x) # Funzioni trigonometriche (seno, coseno, tangente)
[1] 0.4794255
cos(x)
[1] 0.8775826
tan(x)
[1] 0.5463025
asin(x) # Funzioni trigonometriche inverse
[1] 0.5235988
acos(x)
[1] 1.047198
atan(x)
[1] 0.4636476
Supponiamo che x
e y
siano due numeri reali. Inoltre, siano n
e k
due numeri naturali.
Si noti l’uso del ;
che può essere usato per separare due comandi nella stessa riga.
<- 1 / 2; y <- 1 / 3 # Numeri reali
x <- 5; k <- 2 # Numeri naturali n
factorial(n) # n!
[1] 120
choose(n, k) # Coefficiente binomiale
[1] 10
round(x, digits = 2) # Arrotonda x usando 2 cifre decimali
[1] 0.5
floor(x) # Arrotonda x all'intero più vicino, per difetto
[1] 0
ceiling(x) # Arrotonda x all'intero più vicino, per eccesso
[1] 1
La funzione gamma \Gamma(x) = \int_0^\infty s^{x-1} e^{-s} d s si calcola in R come segue:
gamma(x) # Funzione gamma
[1] 1.772454
La funzione beta \mathcal{B}(x,y) = \int_0^1 s^{x-1}(1-s)^{y-1}ds si calcola in R come segue:
beta(x, y) # Funzione beta
[1] 4.206546
In R è possibile disegnare una qualsiasi funzione tramite il comando curve
.
Se ad esempio si considera la funzione f(x) = \frac{\sin(x)}{x}, allora possiamo disegnare f(x) nell’intervallo (0,15) come segue:
curve(sin(x) / x, from = 0, to = 15)
La documentazione di R è la principale fonte di informazioni.
A cosa serve una funzione? Qual è la definizione dei suoi argomenti? La risposta va sempre cercata nella documentazione ufficiale e non in queste slide.
Il comando ? funzione
apre una finestra in cui vengono descritta nel dettaglio una funzione. Esempio:
# Documentazione della funzione log ? log
Numeri molto grandi, come 10^{15}, e molto piccoli, come 10^{-15}, in R vengono rappresentati come segue:
10^15
[1] 1e+15
10^(-15)
[1] 1e-15
Per questioni di approssimazione numerica, quando un numero è troppo grande R riporta Inf
, ovvero infinito. Per esempio:
10^1000 # Numero molto grande, anche se finito
[1] Inf
Il simbolo NaN
significa invece Not a Number e si ottiene quando qualche funzione matematica non è stata usata nel modo corretto. Ad esempio:
log(-1) # Questo comando genera inoltre un avviso
Warning in log(-1): NaNs produced
[1] NaN
È ben noto che \sin(\pi) = 0. Tuttavia, in R si ottiene un numero molto vicino a 0, ma strettamente positivo. Infatti:
sin(pi)
[1] 1.224647e-16
R è uno strumento di calcolo numerico e pertanto sono sempre presenti errori di approssimazione numerica.
Fortunatamente, nella maggior parte dei casi pratici la differenza tra 0 e 10^{-16} è del tutto irrilevante.
In altre situazioni, errori di approssimazione numerica possono portare a conclusioni fuorvianti. Occorre quindi fare attenzione e valutare caso per caso.
Ad ogni modo, l’approssimazione numerica potrebbe anche migliorare. Ad esempio:
cos(pi)
[1] -1
In R è spesso necessario verificare se una o più condizioni sono verificate o meno.
<- 5
x < 0 # Il valore di x è minore di 0? x
[1] FALSE
<- (x == -3) # Il valore di x è uguale a -3?
a a
[1] FALSE
Il valore di a
è un indicatore binario o booleano, ovvero può essere vero (TRUE
) oppure falso (FALSE
).
Altre funzioni logiche disponibili (assumendo che y
sia un numero e b
un booleano) sono:
<- TRUE; b <- FALSE; x <- 5; y <- 7
a >= y # x è maggiore o uguale a y? (Si usa "<=" per minore uguale) x
[1] FALSE
!= y # x è diverso da y? x
[1] TRUE
& b # a AND b. I valori booleani a e b sono entrambi veri? a
[1] FALSE
| b # a OR b. Almeno uno tra a ed b è vero? a
[1] TRUE
Un vettore in R viene definito tramite la funzione c()
, come nel seguente esempio:
<- c(4, 2, 2, 8, 10)
x x
[1] 4 2 2 8 10
Il seguente oggetto è un vettore in R, nonostante l’oggetto x
sia composto sia numeri che da lettere
<- c("A", "B", 2, 8, 10)
x x
[1] "A" "B" "2" "8" "10"
Talvolta è comodo creare dei vettori i cui elementi sono dei numeri consecutivi
<- 5:10 # Equivalente a: x <- c(5, 6, 7, 8, 9, 10)
x x
[1] 5 6 7 8 9 10
Per creare una successione di numeri reali si usa il comando seq
:
<- seq(from = 0, to = 1, by = 0.1)
x x
[1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
Per creare un vettore di valori ripetuti si usa il comando rep
:
<- rep(10, 7) # Vettore in cui il numero 10 è ripetuto 7 volte
x x
[1] 10 10 10 10 10 10 10
La maggior parte delle funzioni matematiche di R sono vettorizzate. In altri termini, le funzioni agiscono su tutti gli elementi di un vettore.
exp(1:6) + (1:6) / 2 + 1 # Esempio 1
[1] 4.218282 9.389056 22.585537 57.598150 151.913159 407.428793
<- c(10, 10^2, 10^3, 10^4, 10^5, 10^6) # Esempio 2
x log(x, base = 10)
[1] 1 2 3 4 5 6
1:8 > 4 # Esempio 3
[1] FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE
Altre funzioni invece sono utili proprio nel caso in cui l’argomento sia un vettore:
<- c(2, 3, 1, 3, 10, 5)
x length(x) # Lunghezza del vettore
[1] 6
sum(x) # Somma degli elementi del vettore
[1] 24
cumsum(x) # Somme cumulate
[1] 2 5 6 9 19 24
Ulteriori semplici operazioni in cui l’argomento è un vettore sono elencate nel seguito:
<- c(2, 3, 1, 3, 10, 5)
x prod(x) # Prodotto degli elementi del vettore
[1] 900
cumprod(x) # Prodotti cumulati
[1] 2 6 6 18 180 900
sort(x, decreasing = FALSE) # Vettore ordinato in ordine crescente
[1] 1 2 3 3 5 10
min(x) # Valore minimo
[1] 1
which.min(x) # Posizione del valore corrispondente al minimo
[1] 3
Infine, il funzionamento delle seguenti funzioni dovrebbero essere intuibile da quanto visto finora:
max(x) # Valore massimo
[1] 10
which.max(x) # Posizione del valore corrispondente al massimo
[1] 5
range(x) # Equivalente a: c(min(x), max(x))
[1] 1 10
È possibile selezionare gli elementi di un vettore usando le parentesi quadrate, come nei seguenti esempi:
# Concatenazione di vettori
<- c(rep(pi, 2), sqrt(2), c(10, 7))
x 3] # Estrae il terzo elemento dal vettore x, ovvero sqrt(2) x[
[1] 1.414214
c(1, 3, 5)] # Estrae il primo, il terzo ed il quinto elemento x[
[1] 3.141593 1.414214 7.000000
-c(1, 3, 5)] # Elimina il primo, il terzo ed il quinto elemento x[
[1] 3.141593 10.000000
> 3.5] # Estrae gli elementi maggiori di 3.5 x[x
[1] 10 7
L’ultimo comando suggerisce che gli elementi di un vettore possono essere selezionati tramite una condizione relativa al vettore stesso.
Cosa succede quando vengono sommati due vettori di dimensioni diverse?
In questo primo esempio, quantomeno R restituisce un warning.
# Concatenazione di vettori
<- 1:5
x <- 1:6
y + y # Equivalente a: c(x, x[1]) + y x
Warning in x + y: longer object length is not a multiple of shorter object
length
[1] 2 4 6 8 10 7
In questo secondo esempio, invece, R non restituisce alcun avviso, rendendo la cosa particolarmente pericolosa
<- 1:3
x <- 1:6
y + y # Equivalente a: c(x, x) + y x
[1] 2 4 6 5 7 9
Una matrice {\bf A} è una collezione di elementi (a)_{ij} per i=1,\dots,n e j=1,\dots,m.
Per esempio, la matrice quadrata di dimensione 2 \times 2
{\bf A} = \begin{pmatrix}
5 & 2\\
1 & 4 \\
\end{pmatrix}, si può definire in R tramite il comando matrix
come segue:
<- matrix(c(5, 1, 2, 4), nrow = 2, ncol = 2)
A A
[,1] [,2]
[1,] 5 2
[2,] 1 4
È inoltre possibile elencare gli elementi riga per riga
# Definizione equivalente
<- matrix(c(5, 2, 1, 4), nrow = 2, ncol = 2, byrow = TRUE) A
Una matrice con una sola colonna è un vettore colonna:
<- matrix(c(1, 10, 3, 5), ncol = 1)
x_col x_col
[,1]
[1,] 1
[2,] 10
[3,] 3
[4,] 5
Una matrice con una sola colonna è un vettore riga:
<- matrix(c(1, 10, 3, 5), nrow = 1)
x_row x_row
[,1] [,2] [,3] [,4]
[1,] 1 10 3 5
Nella maggior parte dei casi, il vettore riga x_row
è intercambiabile col vettore x
.
<- matrix(c(1, 10, 3, 5), nrow = 1)
x_row <- c(1, 10, 3, 5) # Simile, ma non identico, a x_row x
Ad esempio, le funzioni sum(x_row)
e sum(x)
forniscono lo stesso risultato.
Ci sono tuttavia alcune lievi distinzioni. Ad esempio:
dim(x_row)
[1] 1 4
dim(x)
NULL
Il simbolo NULL
significa non definito, perché non esiste la nozione di dimensione per un generico vettore R.
È possibile selezionare gli elementi di una matrice in maniera analoga a quanto fatto con i vettori.
1, 2] # Estrazione di elemento in posizione (1,2) A[
[1] 2
2] # Estrazione seconda colonna A[,
[1] 2 4
1, ] # Estrazione prima riga A[
[1] 5 2
Alcuni comandi di base per manipolare le matrici sono i seguenti
dim(A) # Restituisce la dimensione della matrice
[1] 2 2
<- c(A) # Converte la matrice in un vettore
a a
[1] 5 1 2 4
diag(A) # Restituisce la diagonale della matrice
[1] 5 4
t(A) # Calcola la matrice trasposta A'
[,1] [,2]
[1,] 5 1
[2,] 2 4
sum(A) # Somma di tutti gli elementi di A
[1] 12
Come per i vettori, le operazioni elementari (somma, prodotto, log
, exp
, etc.) vengono eseguite elemento per elemento.
exp(A)
[,1] [,2]
[1,] 148.413159 7.389056
[2,] 2.718282 54.598150
Siano {\bf A} e {\bf B} due matrici aventi lo stesso numero di colonne e definiamo
{\bf C} = \begin{pmatrix}{\bf A} \\ {\bf B} \end{pmatrix}.
<- A # Creo una matrice B identica ad A, per semplicità
B <- rbind(A, B)
C C
[,1] [,2]
[1,] 5 2
[2,] 1 4
[3,] 5 2
[4,] 1 4
In maniera analoga, siano {\bf A} e {\bf B} due matrici aventi lo stesso numero di righe e definiamo {\bf C} = \begin{pmatrix}{\bf A} & {\bf B} \end{pmatrix}.
<- cbind(A, B)
C C
[,1] [,2] [,3] [,4]
[1,] 5 2 5 2
[2,] 1 4 1 4
Siano {\bf x} e {\bf y} due vettori colonna in \mathbb{R}^p. Allora, il loro prodotto incrociato è pari a
{\bf x}^\intercal {\bf y} = \sum_{i=1}^p x_i y_i.
In R possiamo usare il comando crossprod
<- matrix(c(-4, 2, 6, 10, 22), ncol = 1)
x <- matrix(c(3, 2, 2, 7, 9), ncol = 1)
y crossprod(x, y) # Equivalente a: sum(x * y)
[,1]
[1,] 272
Il comando crossprod
funziona correttamente anche con “vettori” R.
Il comando crossprod
può essere usato anche per calcolare il seguente prodotto tra matrici
{\bf A}^\intercal {\bf B},
dove {\bf A} e {\bf B} sono due matrici di dimensioni compatibili.
In algebra lineare il prodotto tra matrici compatibili {\bf A} {\bf B} è chiamato prodotto righe per colonne. In R si usa il comando seguente
<- rbind(c(1, 2, 3), c(4, 9, 2), c(2, 2, 2))
A <- rbind(c(5, 2, 5), c(3, 3, 7), c(-2, -8, 10))
B
%*% B # Prodotto righe per colonne AB A
[,1] [,2] [,3]
[1,] 5 -16 49
[2,] 43 19 103
[3,] 12 -6 44
Nota. Il comando A * B
indica il prodotto elemento per elemento e non il prodotto righe per colonne.
Se le matrici non sono compatibili R produce un errore (provateci per esercizio!)
Sia {\bf A} una matrice quadrata n \times n a valori reali. La sua matrice inversa {\bf A}^{-1}, quando esiste, è l’unica matrice tale per cui
{\bf A} {\bf A}^{-1} = {\bf A}^{-1} {\bf A} = I_n.
Per ottenere {\bf A}^{-1} si usa il comando solve
.
<- rbind(c(1, 2, 3), c(4, 9, 2), c(2, 2, 2))
A <- solve(A) # Matrice inversa di A
A1 A1
[,1] [,2] [,3]
[1,] -0.5833333 -0.08333333 0.95833333
[2,] 0.1666667 0.16666667 -0.41666667
[3,] 0.4166667 -0.08333333 -0.04166667
round(A %*% A1, digits = 5) # Operazione di controllo
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 1 0
[3,] 0 0 1
det(A) # Calcola il determinante della matrice A
[1] -24
Nel caso una matrice non sia invertibile, il determinante è pari a 0. Il comando solve
in quel caso produce un errore.
# Esempio di matrice NON invertibile
<- rbind(c(1, 2, 3), c(2, 4, 6), c(2, 2, 2))
A det(A) # Deteminante pari a 0, solve(A) produce un errore
[1] 0
Ci sono numerose funzioni per la scomposizione di matrici, il cui output è a volte una lista.
<- matrix(c(4, 1, 1, 8), ncol = 2)
A chol(A) # Scomposizione di Cholesky
[,1] [,2]
[1,] 2 0.500000
[2,] 0 2.783882
qr(A) # Scomposizione QR
$qr
[,1] [,2]
[1,] -4.1231056 -2.910428
[2,] 0.2425356 7.518604
$rank
[1] 2
$qraux
[1] 1.970143 7.518604
$pivot
[1] 1 2
attr(,"class")
[1] "qr"
eigen(A) # Scomposizione spettrale
eigen() decomposition
$values
[1] 8.236068 3.763932
$vectors
[,1] [,2]
[1,] 0.2297529 -0.9732490
[2,] 0.9732490 0.2297529
Una lista è una collezione di oggetti (numeri, vettori, matrici, etc).
Per salvare o per estrarre un oggetto da una lista si usa il simbolo del dollaro $
.
# Creazione di una lista
<- list(
new_list A = matrix(c(4, 1, 1, 8), ncol = 2),
x = c(1, 2, 6, 6, 9)
)
new_list
$A
[,1] [,2]
[1,] 4 1
[2,] 1 8
$x
[1] 1 2 6 6 9
Gli autovalori ed autovettori di una matrice \textbf{A} si ottengono tramite il comando eigen
.
Il risultato è una lista, contenente gli autovettori (vectors
) e autovalori (values
).
<- eigen(A) # Scomposizione spettrale della matrice A
Spec_A Spec_A
eigen() decomposition
$values
[1] 8.236068 3.763932
$vectors
[,1] [,2]
[1,] 0.2297529 -0.9732490
[2,] 0.9732490 0.2297529
$values # Estrazione degli autovalori Spec_A
[1] 8.236068 3.763932