La scrittura di operazione complesse in R avviene utilizzando le parentesi per dare priorità ad alcune parti. Per il resto R segue quella che è la normale priorità delle operazioni matematiche. Prova a scrivere in R queste operazioni:
\(\frac{(45+21)^3+\frac{3}{4}}{\sqrt{32-\frac{12}{17}}}\)
\(\frac{\sqrt{7-\pi}}{3\ (45-34)}\)
\(\sqrt[3]{12-e^2}+\ln(10\pi)\)
\(\frac{\sin(\frac{3}{4}\pi)^2+\cos(\frac{3}{2}\pi)}{\log_7{e^{\frac{3}{2}}}}\)
\(\frac{\sum_{n=1}^{10} n}{10}\)
Note per la risoluzione degli esercizi:
sqrt()
mentre per radici di indici diversi si utilizza la notazione esponenziale (\(\sqrt[3]{x}\) è dato da x^(1/3)
).pi
.exp(1)
.log(x, base=a)
, di base viene considerato il logaritmo naturale.Definisci una proposizione che ti permetta di valutare se un numero è pari. Definisci un’altra proposizione per i numeri dispari (tip: cosa ti ricorda %%
?).
Definisci una proposizione per valutare la seguente condizione (ricordati di testare tutti i possibili scenari) “x è un numero compreso tra -4 e -2 oppure è un numero compreso tra 2 e 4”.
Esegui le seguenti operazioni 4 ^ 3 %in% c(2,3,4)
e 4 * 3 %in% c(2,3,4)
. Cosa osservi nell’ordine di esecuzione degli operatori?
Esegui le seguenti operazioni logiche tra stringhe e prova prevedere il risultato prima di eseguire il codice:
"ciao" == "ciao"
"R" == "r"
"SPSS" != "SpSS"
"1" == 1
"1" > "ciao"
"a" > "b"
"ciao" > "zebra"
Crea il vettore x
contenente i numeri 4, 6, 12, 34,
Crea il vettore y
contenente tutti i numeri pari compresi tra 1 e 25 (?seq()
)
Crea il vettore z
contenente tutti i primi 10 multipli di 7 partendo da 14 (?seq()
in particolare l’argomento length.out =
)
Crea il vettore s
in cui le lettere "A"
,"B"
e "C"
vengono ripetute nel medesimo ordine 4 volte (?rep()
)
Crea il vettore t
in cui le letter "A"
,"B"
e "C"
vengono ripetute ognuna 4 volte (?rep()
)
Genera il seguente output in modo pigro, ovvero scrivendo meno codice possibile ;)
## [1] "foo" "foo" "bar" "bar" "foo" "foo" "bar" "bar"
Del vettore x
seleziona il 2°, 3° e 5° elemento
Del vettore x
seleziona i valori 34 e 4
Dato il vettore my_vector = c(2,4,6,8)
commenta il risultato del comando my_vector[my_vector]
my_vector = c(2,4,6,8)
my_vector[my_vector]
Del vettore y
seleziona tutti i valori minori di 13 o maggiori di 19
Del vettore z
seleziona tutti i valori compresi tra 24 e 50
Del vettore s
seleziona tutti gli elementi uguali ad "A"
Del vettore t
seleziona tutti gli elementi diversi da "B"
Crea un nuovo vettore u
identico a s
ma dove le "A"
sono sostituite con la lettera "U"
Elimina dal vettore z
i valori 28 e 42
Spesso è necessario creare delle stringhe random per codificare un partecipante in modo univoco ma senza usare informazioni sensibili. Genera 1 codice univoco formati da id_string_num
dove:
id
è un numero casuale tra 1 e 10string
è una stringa formata da 5 lettere casualinums
è un numero casuale tra 100 e 999
Ad esempio 1_adrtv_100
è un id valido.Tips:
- vedi la funzione sample
o runif
e round
per generare i numeri
- vedi l’oggetto letters
già disponibile in R
- vedi la funzione paste0()
o sprintf()
genere
così definita:## [1] M F M F M F F F M
## Levels: F M
Rinomina i livelli della variabile genere
rispettivamente in "donne"
e "uomini"
.
Crea la variabile categoriale intervento
così definita:
## [1] CBT Psicanalisi CBT Psicanalisi CBT Psicanalisi
## [7] Controllo Controllo CBT
## Levels: CBT Controllo Psicanalisi
Correggi nella variabile intervento
la 7° e 8° osservazione con la voce Farmaci
. Notate qualcosa di strano?
Aggiungi alla variabile intervento
le seguenti nuove osservazioni:
c("Farmaci","Controllo","Farmaci")
## [1] "Farmaci" "Controllo" "Farmaci"
A
così definita:\[ \begin{matrix} 2 & 34 & 12 & 7\\ 46 & 93 & 27 & 99\\ 23 & 38 & 7 & 04 \end{matrix} \]
B
contenente tutti i primi 12 numeri dispari disposti su 4 righe e 3 colonne.C
contenente i primi 12 multipli di 9 disposti su 3 righe e 4 colonne.D
formata da 3 colonne in cui le lettere "A"
,"B"
e "C"
vengano ripetute 4 volte ciascuna rispettivamente nella prima, seconda e terza colonna.E
formata da 3 righe in cui le lettere "A"
,"B"
e "C"
vengano ripetute 4 volte ciascuna rispettivamente nella prima, seconda e terza riga.A
B
A
(Nota: utilizza l’operazione resto %%
)C
la terza riga e la terza colonnaB
D
G
unendo alla matrice A
le prime due colonne della matrice C
H
unendo alla matrice C
le prime due righe della matrice trasposta di B
A
eliminando la seconda colonna. Ridefinisci la matrice B
eliminando la prima riga. Verifica che le matrici così ottenute abbiano la stessa dimensione.A*B
, B*A
, A%*%B
e B%*%A
.C
: "col_1", "col_2", "col_3", "col_4", "row_1", "row_2", "row_3"
.x
) con i numeri da 1 a 100y
) con le prime 15 lettere dell’alfabeto (vedi l’oggetto letters
)B
creata nell’esercizio precedenteTRUE/FALSE
testando che il vettore numerico creato in precedenza abbia numeri pari (TRUE
) o dispari (FALSE
)x
y
con lo stesso vettore di caratteri ma ripetendo ogni elemento 4 voltex
all’interno della listax
divisibili per 3 (ricordi la funzione modulo %%
?)data_long<-data.frame(Id=rep(c("subj_1","subj_2","subj_3"),each=3),
age=rep(c(21,23,19),each=3),
gender=rep(c("F","M","F"),each=3),
item=rep(1:3,3),
response=c(2,1,1,0,2,1,2,0,1))
dataframe_example1.rds
esegui le seguenti operazioni:put_random_na(data, n)
dove data
è il dataframe e n
è il numero di NA
da generare. Ora:NA
per la colonna degree
e per la colonna età
NA
per la colonna email
e abitanti del veneto o campaniacomplete.cases()
)dataframe_example2.csv
csv
id
che identifichi in modo univoco ogni soggetto progressivamenteis.*
)nessuna
festa. Noti qualche problema?blu
e piace il natale
is.* family
)\[ Fahrenheit = Celsius * 1.8 + 32 \]
paste()
e print()
.n_and_media()
che, dato un vettore di valori numerici, calcoli il numero di elementi e la loro media e restituisca entrambe in una frase. Ad esempio n_and_media(x)
deve restituire “la media di x è … e la lunghezza di x è …”. Anche qui sono utili le funzioni paste()
/sprintf
e print()
.score <- runif(100, 0, 1)
La funzione quindi deve ricevere in input un valore e restituire la stringa corrispondente in base al valore stesso.
ifelse()
nested per creare una variabile score_chr
con le etichette corrispondenti all’esercizio precedente.Scrivi un loop che scorre le colonne del dataset iris
(lo trovate direttamente in R) e stampa il nome della colonna assieme al numero di caratteri che compone la stringa. Ad esempio Sepal.Length (12)
. Potete usare le funzioni print()
, paste()
and nchar()
.
Scrivi un loop che scorre le colonne del dataset iris
(lo trovate direttamente in R) e resituisce la media
se la colonna è numerica (ricordate le is.*
family) oppure la tabella di frequenza (comando table()
) se la colonna è stringa/fattore
*apply()
Usando la funzione più adatta dell*apply()
family, calcola la deviazione standard
di ogni colonna del dataset mtcars
(lo trovate direttamente in R)
for
Popoliamo una matrice usando il ciclo for
. La matrice ha un numero totale di elementi. Usando il vettore x
che contiene il numero di elementi totali della matrice come possiamo popolare la matrice partendo da una vuota matrix(NA, 10, 10)
. La matrice è quadrata di dimensione 10x10:
# matrice 10 x 10 quindi 100 elementi totali
my_mat <- matrix(NA, 10, 10) # matrice vuota 10x10
Suggerimento: puoi fare un doppio ciclo for
e generare un numero casuale da inserire con rnorm(1)
Un ottimo esercizio per affinare le nostre competenze di codice è quello di ricreare le funzioni di R che diamo per scontate diciamo. La funzione mean()
ad esempio si può facilmente create con un ciclo for e qualche altra aggiunta.
sum()
Ricrea la funzione sum()
e testala sul seguente vettore:
x <- rnorm(100)
sum(x)
## [1] -11.31083
mean()
Ricrea la funzione mean()
testala sul seguente vettore confrontando il risultato con la funzione interna (hint: puoi usare la funzione sum()
creata prima):
x <- rnorm(100)
mean(x)
## [1] 0.08861665
median()
La mediana è definita come il valore che divide a metà una distribuzione di valori. Ricreala in R facendo attenzione che la formula cambia a seconda che il vettore sia di lunghezza pari o dispari (hint: puoi usare un if
per controllare queste condizioni)
median(x)
## [1] -0.1333679
In R non è prevista una funzione per calcolare la moda. In statistica la moda è definita come il valore/i associato a maggiore frequenza. Ad esempio se abbiamo un vettore \(x\) come c(1,1,1,2,3,5)
la moda sarà 1.
sd()
La deviazione standard è facilmente implementata in R con la funzione sd()
. Prova a ricrearla con tutti gli strumenti che abbiamo imparato fino ad ora. La formula matematica è la seguente:
\[
SD = \sqrt{\frac{\sum_{i = 1}^{N} (x_i - \mu_x)^2}{N}}
\]
Attenzione che R utilizza un denominatore diverso per la funzione sd()
rispetto alla formula proposta. Cerca di capire cosa utilizza R aprendo la documentazione di sd()
e implementa la versione di R e quella della formula. Crea poi una terza versione della funzione my_sd(x, versione)
dove viene calcolata una o l’altra versione in base a cosa viene messo come argomento.
Scrivi una funzione che dato in input un vettore x
restituisca il numero di volte che compare il numero \(3\):
round(runif(20, 1, 10))
Scrivi una funzione che prenda in input un vettore x
e restituisca il numero di numeri pari all’interno del vettore. Scrivi una funzione che utilizzi un for loop
mentre un’altra che usi un’operazione vettorizzata.
%%
complete.cases()
Cerca di capire cosa fa la funzione complete.cases()
e di creare una funzione personalizzata my_complete_cases()
con cui ottenere lo stesso output.
complete.cases(iris[1:10, ])
## [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Suggerimenti:
any()
ciclo for
oppure una funzione dell’*apply
familyUno step importante quando si analizzano i dati è quello di cercare valori anomali (ad esempio che superano una certa soglia oppure che sono troppo oltre gli indici di tendenza centrale).
is_outlier(x)
che dato in input un vettore x
, restituisca un vettore logico dove TRUE
corrisponde ad un valore che è maggiore della media più una volta la deviazione standard di x
.has_outlier
che applichi is_outlier()
ad ogni colonna di un dataframe e restituisca i nomi delle colonne dove è presente almeno 1 outlier.
any()
mtcars
has_outliers()
per funzionare solo sulle colonne del dataframe che sono numeriche (no fattori o caratteri)Usa il dataframe my_mtcars
dove sono state aggiunte delle variabili non numeriche:
my_mtcars <- mtcars
my_mtcars$factor1 <- factor(rep(c("a", "b", "c"), c(10, 10, 12)))
my_mtcars$factor2 <- rep(c("d", "e", "f"), c(10, 10, 12))
Il bootstrapping è una tecnica statistica molto utilizzata. La logica della programmazione però è molto semplice ma interessante (e potrebbe esservi anche utile). Scrivete una funzione prepare_bootstrap(data, nrow, n)
che prenda in input un dataframe data
, il numero di righe da estrarre nrow
e quanti dataframe creare n
e che fornisca quindi n
dataframe dove n
righe sono estratte casualmente.
mtcars
sample()
Il leave-one-out è una procedura statistica usata in vari contesti. Ad esempio, per capire se ci sono delle osservazioni influenti in un certo modello statistico, si ripete l’analisi rimuovendo un’osservazione alla volta. Se abbiamo 100 osservazioni otteniamo 100 dataset ognuno formato da 99 osservazioni perchè una è stata rimossa.
Scrivete una funzione leave1out(data)
che riceve in input un dataset e restituisce una lista di dataset, ognuno dove è stata tolta un’osservazione. Usate un ciclo for
.
Scrivete una versione più compatta usando l’*apply
family.
Ampliate la funzione creata al punto 1 in modo che la funziona tolga ogni volta \(n\) osservazioni casuali, dove \(n\) è un parametro della funzione. Ad esempio, la funzione deve creare 100 dataset, dove ogni volta toglie 3 osservazioni.
Potete usare il dataset iris
Scrivi una funzione populate_matrix(matrix, data)
che presi in input i dei dati e una matrice vuota, popoli la matrice vuota usando un nested loop.
x <- rnorm(100)
mat <- matrix(nrow = 10, ncol = 10)
In questi esercizi vedremo come gestire un dataset più o meno complesso in modo da applicare le nozioni che abbiamo imparato. Gli obiettivi sono:
In questo corso non abbiamo visto aspetti di statistica o manipolazione dati in senso stretto, tuttavia i concetti che abbiamo imparato sono applicabili anche senza queste nozioni. Ad esempio non abbiamo affrontato nel dettaglio la pulizia dei dati, i pacchetti per gestire dataset complessi ma sappiamo che ad esempio un dataframe
è una lista, e se vogliamo applicare una funzione ad una lista possiamo usare l’*apply
family.
Proviamo a fare lo scoring di un questionario rappresentato in R come dataframe. Questo è un caso molto comune dove dobbiamo lavorare con indici di riga/colonna.
item_data.rds
NA
. Se un soggetto ha più di 1 NA
, eliminiamo il soggetto altrimenti mettiamo il valore 3 al posto degli NA
Prima di fare lo scoring dobbiamo invertire (ricodificare) alcuni item. In particolare dobbiamo invertire gli item 1, 10, 11, 13, 14, 15, 20. Per invertire semplicemente i punteggi 1 diventano 5, 2 –> 4 e così via.
Tips:
case_when()
) e poi applicarla a tutti gli itemQuesto questionario è formato da 30 item. Ci sono 5 sottoscale dove:
Per fare lo scoring dobbiamo:
sub1
, sub2
e sub3
sub4
, sub5
e sub6
In entrambi i casi creiamo delle nuove colonne che si chiamano come le sottoscale da attaccare al dataframe principale.
Questo dataset è stato preso dal sito Kaggle(un ottima risorsa per trovare datasets). E’ un dataset relativamente grande con 7787 righe e 12 colonne. Il dataset contiene informazioni su serie-tv e film presenti sulla piattaforma, in particolare:
show_id
: in indice numerico per ogni film/serie-tvtype
: identifica se il prodotto è una serie-tv o un filmtitle
: il titolocountry
: il paese di produzioneduration
: la duratausers_rating
: le valutazioni degli utenti netfliximdb_rating
: le valutazioni del portale imdbtotal_cost
: il costo di produzione in milionirelease_date
: la data di rilascio originale della serie o del filminsert_date
: la data di inserimento nel catalogo netflixhead(netflix)
## show_id type title director country duration users_rating
## 1 s1 TV Show 3% <NA> Brazil 4 Seasons 5
## 2 s2 Movie 7:19 Jorge Michel Grau Mexico 93 min 7
## 3 s3 Movie 23:59 Gilbert Chan Singapore 78 min 6
## 4 s4 Movie 9 Shane Acker United States 80 min 8
## 5 s5 Movie 21 Robert Luketic United States 123 min 1
## 6 s6 TV Show 46 Serdar Akar Turkey 1 Season 0
## imdb_rating total_cost duration_episode release_date insert_date
## 1 2 35 91 2019-05-07 2019-09-24
## 2 5 105 NA 2019-01-01 2019-03-31
## 3 3 127 NA 2019-10-23 2020-01-30
## 4 2 95 NA 2020-06-02 2020-06-09
## 5 5 39 NA 2019-07-26 2019-08-30
## 6 3 51 60 2019-11-09 2020-03-25
netflix.txt
capendo quale funzione utilizzare, come assegnare la prima riga come nomi e usando il separatore giustoNA
perc
che se inserita come TRUE
restituisce la percentuale di NA
release_date
e insert_date
. Per questo può essere utile cercare online come R gestisce le date.Solitamente le colonne di un dataset contengono informazioni rindondanti o non adeguatamente organizzate. Ad esempio la colonna duration
ha una duplice informazione: la durata in minuti (per i film) e la durata in stagioni per le serie. In un’altra colonna abbiamo invece la durata degli episodi chiaramente non rilevante per i film. In questo caso potrebbe essere utile:
durata
che contiene la durata in minuti per i film e la durata dell’episodio per le le serie-tvdurata_stagioni
che contenga il numero di stagioni per ogni serie-tv mentre il valore 0
per i film.Nonstante possano sembrare aspetti superficiali, la pulizia dei dataset è fondamentale. Nomi di colonne appropriati, rimuovere caratteri speciali, verificare la struttura e la tipologia delle colonne etc. Il dataframe inequality_sub.csv
è un esempio di un ottimo dataset di partenza ma con la possibilità di migliorare i nomi delle colonne e alcuni dettagli generali.
Vedi un esempio di pre-processing di un dataset a questo link.