###################################################### ################ CORSO LIVELLAMENTO R ################ ################# terza lezione #################### ###################################################### library(faraway) require(FlexDir) # The library() by default returns an error if the requested package does not exist. ######## Strutture di controllo # In R, cosi' come in molti altri linguaggi di programmazione, esistono numerose strutture di controllo # Noi vedremo le principali: # IF ed ELSE # if(condizione){ # se la condizione e' vera, fai tutto quello che e' dentro al blocco (tra parentesi graffe) # } else { # ALTRIMENTI fai tutto quello che e' presente dentro a QUESTO blocco # } # La clausula else puo' essere omessa, nel caso non si voglia compiere azioni in caso di condizione falsa data(gala) str(gala) x <- gala$Area if( mean(x) != 0){ # 1 - Valuta se la media della variabile x ? diversa a 0 print(mean(x)) # 2 - Se ? davvero diversa da 0, stampala a schermo (nella console) } else { print("La media e' nulla!") # 3 - Altrimenti, avvisami che ? 0 } # ESERCIZIO 1: Si consideri la variabile Area del dataset gala. # Scrivere, in un'unico blocco if/else, un codice che controlli se la variabile abbia media pari a 0 # e varianza pari a 1. Se cosi' non fosse, creare una nuova variabile Area standardizzata (con media 0 e varianza 1) # (hint: Z= (X - media)/sqrt(varianza) ? la versione standardizzata di X) if(round(mean(x),8) != 0 | var(x) != 1){ Area_std <- (x-mean(x))/sqrt(var(x)) } else print("La variabile è standardizzata") mean(Area_std) var(Area_std) x <- Area_std # In alcuni semplici casi, la struttura if/else pu? essere sostituita dalla funzione ifelse: help(ifelse) # ifelse(condizione, # cosa restituire se la condizione e' vera, # cosa restituire se la condizione e' falsa # ) x <- gala$Area ifelse(min(x) < 0, # Un'isola ha area negativa? print("E' presente un errore logico"), # Se si, stampa un messaggio di errore min(x) # Se no, mostra l'area minima ) ##### Ciclo for # un ciclo for ripete un blocco di istruzioni per un numero fissato di volte for(indice in 1:10){ # Per 'indice' che va da 1 a 10... print(indice) # ...stampa 'indice' } for(t in c("A", "B", "C")){ print(paste("La risposta giusta e' la", t)) } set.seed(42) nsim <- 1000 n <- 50 vettore.medie <- numeric(nsim) # Creo un vettore numerico vuoto (contenente 0) di ampiezza nsim for(i in 1:nsim){ dati.temp <- rpois(n, 15) vettore.medie[i] <- mean(dati.temp) } hist(vettore.medie, prob=T, main="Istogramma media campionaria", xlab="Stima") curve(dnorm(x, mean(vettore.medie), sd(vettore.medie)), add=T, col=2) ###### Ciclo while # un ciclo while ripete un blocco di istruzioni finche' la condizione e' vera i <- 10 while(i >= 0){ print(i) i <- i - 1 } i i <- 10 while(i >= 0){ i <- i - 1 print(i) } i ########################################################################### rm(list=ls()) # Finalmente possiamo costruire una nostra funzione. # Una funzione permette di ri-eseguire del codice scritto in precedenza # senza doverlo riscrevere interamente. Infatti, basterà richiamare il nome # della funzione definita in precedenza per ri-eseguire interamente il codice. # R tratta le funzioni come oggetti. Quindi e' possibile # - che una funzione sia argomento di un'altra funzione # - una funzione richiami un'altra funzione o sia definita all'interno di essa # nome.funzione <- function(argomenti1, argomento2,...){ # corpo della funzione # corpo della funzione # corpo della funzione # corpo della funzione # return(cosa deve restituire la funzione?) # } # Creiamo una funzione che ricrei la successione di Fibonacci, fermandosi al k-esimo termine (k >=2) my.fibonacci <- function(k){ x <- integer(k) x[1:2] <- 1 for(i in 3:k){ x[i] <- x[i-1]+x[i-2] } return(x) } my.fibonacci(10) f <- my.fibonacci(10) # Notare che tutti gli oggetti che vengono creati all'interno della funzione (x, i, k) non vengono # salvati nel workspace # Ma c'e' qualche problema.... my.fibonacci() my.fibonacci(1) my.fibonacci(-5) my.fibonacci2 <- function(k=3){ # Abbiamo inserito un default... vedi sotto if(k<2) stop("k deve essere un intero maggiore o uguale di 2") x <- integer(k) x[1:2] <- 1 for(i in 3:k){ x[i] <- x[i-1]+x[i-2] } return(x) } my.fibonacci2(1) my.fibonacci2(-5) # Cosa succede adesso se non scegliamo un argomento? R utilizza il default! my.fibonacci2() # ESERCIZIO 2: Creare una funzione che calcoli la media potenziata di ordine r di un vettore: # hint: http://www.treccani.it/enciclopedia/media-potenziata_%28altro%29/ # Se r = 0 allora la funzione deve restituire la media geometrica: # https://www.youmath.it/domande-a-risposte/view/2879-media-geometrica.html media.pot <- function(x, r){ n <- length(x) if(r==0) { mp <- prod(x)^(1/n)} else { mp <- (mean(x^r))^(1/r) } return(mp) } media.pot(f, -1) # Media armonica media.pot(f, 0) # Media geometrica media.pot(f, 1) # Media aritmetica media.pot(f, 2) # Media quadratica ######## Vediamo ora la vera potenzialita' di apply() # e' possibile definire una propria funzione all'interno di apply apply(gala, 2, function(x) mean(x^5)) #ogni colonna di gala viene passata alla funzione come argomento x apply(gala, 2, function(x) media.pot(x, 4)) apply(gala, 1, function(x) x[1] + x[2]) # gala$Species+gala$Endemics # Utilizziamo una funzione per verificare empiricamente il Teorema Centrale del Limite (TCL) tcl <- function(n, nsim=1000){ set.seed(42) vettore.medie <- numeric(nsim) # Creo un vettore numerico vuoto (contenente 0) di ampiezza nsim for(i in 1:nsim){ dati.temp <- rpois(n, 15) vettore.medie[i] <- mean(dati.temp) } hist(vettore.medie, prob=T) } par(mfrow=c(2,2)) for(n in c(10,100,1000,10000)){ tcl(n) curve(dnorm(x, mean=15, sqrt(15/n)), add=T, col=2) } par(mfrow=c(1,1)) ################################################### rm(list=ls()) data(gala) # Ma per accedere alle variabili e' davvero necessario scrivere gala$NOMEVARIABILE? # No, possiamo fare l'attach di un data frame: Area attach(gala) Area detach(gala) # per annullare l'effetto di attach, qualora ce ne dovesse essere bisogno Area Area <- "My Area" Area attach(gala) # Guardare cosa appare nella Console... Area getwd() setwd("NOME/PERCORSO") # Importare dati da file esterni. # RStudio presenta ormai una procedura guidata molto efficiente che permette di caricare # dati dei principali formati. # In alternativa, ci sono le "classiche" funzioni help("read.csv") read.csv2(file="Titanic.csv", sep=";", header=T) # I percorsi delle directory non devono contenere il simbolo \ (che ? per? il default di Windows) # Bisogna mettere \\ oppure / read.csv2(file="G:/Il mio Drive/Didattica/Livellamento R/2021-2022/Titanic.csv", sep=",", header=T) titanic <- read.csv2(file="G:\\Il mio Drive\\Didattica\\Livellamento R\\2021-2022\\Titanic.csv", sep=",", header=T) # Salvare i dati esternamente: x <- rep(c(2,4), 1000) save(x, file = "G:/Il mio Drive/Livellamento R/2021-2022/x.RData") save(x, file = "x.RData") y <- rnorm(3) z <- gala save(list=c("y","z"), file="file.RData") # Salva l'intero workspace save.image(file="TuttoIlWorkspace.RData") # Salvare con altri formati: write.csv(titanic, file = "MyData.csv") # GRAFICI rm(list=ls()) data("teengamb") help("teengamb") str(teengamb) teengamb$sex <- as.factor(teengamb$sex) str(teengamb) attach(teengamb) plot(teengamb) # Matrici di scatterplot/diagrammi a dispersione plot(gamble) # Personalizziamo un po' questo grafico: plot(gamble, # Variabile main="Grafico di gamble", # Titolo del grafico xlab="Soggetto", # Etichetta asse x pch=20, # Parametri grafici col="blue" ) # Ma siamo sicuri che questo grafico abbia un significato? hist(gamble) hist(gamble, prob=T) hist(gamble, freq=F) plot(as.numeric(sex)) plot(sex) # la funzione plot tratta diversamente i factor! pie(sex) #... table(sex) pie(table(sex), labels = c("Maschi", "Femmine")) income.round <- round(income) # income.round e' una variabile quantitativa discreta. Un istogramma non e' il modo migliore di rappresentarla. # e' meglio un grafico ad asticelle/barre barplot(table(income.round)) # Oppure plot(table(income.round)) # Scatterplot/diagrammi a dispersione plot(gamble ~ income, col=2, pch=20) plot(income, gamble, pch=20) # Inseriamo anche l'informazione relativa al genere: plot(gamble ~ income, col=sex, pch=20) # Aggiunge delle rette abline(h=100, # Aggiunge una retta orizzontale (v= per averne una verticale) col="red", # Colore lty=1, # Tipologia del tratteggio della retta lwd=1) # Spessore della retta abline(v=10, # Aggiunge una retta verticale col=3, # Colore lty=3, # Tipologia del tratteggio della retta lwd=4) # Spessore della retta # Aggiungiamo la retta generica y=a+bx abline(a=0, b=1, col=4, lty=2) plot(teengamb) boxplot(teengamb) # Molto poco informativo, dato che le variabili hanno diversa unit? di misura boxplot(gamble) boxplot(gamble ~ sex) # Nella prossima (ed ultima) lezione vedremo come usare R per fare una piccola analisi dei dati