--- title: "Programmazione" author: "Stefano Bussolon" date: "03/2019 - 01/2020" output: xaringan::moon_reader: lib_dir: libs nature: highlightStyle: github highlightLines: true countIncrementalSlides: false --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, comment = NA) ``` # Programmazione --- Nelle lezioni precedenti abbiamo utilizzato R come un ambiente statistico a linea di comando, dove far *girare* degli script, invocando delle funzioni. In questa lezione ci focalizzeremo sulla creazione di funzioni. --- ## Ciao Iniziamo con un esempio molto semplice: la creazione della funzione `ciao()`, il cui scopo è quello di salutare. ```{r prog_ciao} ciao <- function() { messaggio <- "ciao a tutti" return (messaggio) } ``` Invochiamo la funzione ```{r prog_ciao_call} ciao() ``` --- ### Passaggio di un argomento La versione seguente richiede un parametro (un nome) che verrà usato per personalizzare il saluto ```{r prog_ciaoNome} ciaoNome <- function (nome) { messaggio <- paste("ciao ", nome, ", come stai?", sep="" ) return (messaggio) } ``` Se invochiamo la funzione senza il parametro, R segnalerà un errore. ```{r prog_ciaoNome_i} ciaoNome("Francesco") # ciaoNome() # il parametro è obbligatorio ``` --- ### Valore di default In questa iterazione, assegnamo al parametro `nome` un valore di default, che verrà usato se, nell'invocazione, non verrà specificato alcun valore. ```{r prog_ciaoNomeAmico} ciaoNomeAmico <- function (nome="amico") { messaggio <- paste("ciao ", nome, ", come stai?", sep="" ) return (messaggio) } ``` ```{r prog_ciaoNomeAmico_i} ciaoNomeAmico("Marika") ciaoNomeAmico() ``` --- ### If In questa iterazione gestiamo la presenza o meno del parametro nell'invocazione. Se il parametro non c'è, salutiamo l'anonimo. ```{r prog_ciaoNomeForse} ciaoNomeForse <- function (nome=NULL) { messaggio <- "" if(!is.null(nome)) { messaggio <- paste("ciao ", nome, ", come stai?", sep="" ) } else { messaggio <- "Ciao anonimo ;)" } return (messaggio) } ``` ```{r prog_ciaoNomeForse_i} ciaoNomeForse("Matteo") ciaoNomeForse() ``` --- ### For In questa iterazione, gestiamo un vettore di più nomi, introducendo il ciclo `for`. ```{r prog_ciaoNomi} ciaoNomi <- function (nomi=c()) { # c() vettore vuoto messaggio <- "ciao " for (nome in nomi) { messaggio <- paste(messaggio, nome, ", ", sep="") } messaggio <- paste(messaggio, "come state?", sep="") return (messaggio) } ``` --- ```{r prog_ciaoNomi_i} nomi <- c("Mario", "Antonella", "Lucia") ciaoNomi(nomi) ciaoNomi() ``` --- ### If, else, for Una versione più complessa, che gestisce un parametro (con valore di default, ovvero il vettore vuoto), e 4 diversi scenari: vettore vuoto, vettore con un solo valore, vettore con meno di 4 valori (di fatto 2 o 3 nomi), vettore con almeno 4 valori. --- ```{r prog_ciaoDipende} ciaoDipende <- function (nomi=c()) { # c() vettore vuoto if (length(nomi)==0) { return ("ciao anonimo, come stai? Sei timido?") } if (length(nomi)==1) { messaggio <- paste ("ciao ", nomi[1], ", come stai?", sep="") return (messaggio) } messaggio <- "ciao " if (length(nomi)<4) { for (nome in nomi) { messaggio <- paste(messaggio, nome, ", ", sep="") } } else { messaggio <- paste(messaggio, "a tutti, ", sep="") } messaggio <- paste(messaggio, "come state?", sep="") return (messaggio) } ``` --- ```{r prog_ciaoDipende_i} ciaoDipende(c("Giovanna", "Barbara")) ciaoDipende(c("Giovanna", "Barbara", "Enrico", "Tommaso", "Gianluca")) ciaoDipende() ciaoDipende("Enrico") ``` --- ## Funzioni ```{r eval=FALSE} nomeFunzione <- function (argomento1, argomento2=default) { # corpo della funzione return(valore) # valore da sostituire } ``` --- ## Funzione, corpo, argomenti ```{r} # il corpo della funzione body(ciaoNomi) # gli argomenti della funzione formals(ciaoNomi) ``` --- ## If ```{r eval=FALSE} if (condizioneLogica) { # se la condizione è vera, # esegui il codice fra le parentesi } else if (secondaCondizione) { # facoltativo # se la prima è falsa ma la seconda è vera # esegui la seconda } else { # facoltativo # se le condizioni precedenti sono tutte false, # esegui invece questo codice } ``` --- ## For ```{r eval=FALSE} for (elemento in vettore) { # o sequenza # esegui questo codice # per ognuno degli elementi } ``` --- ## Altre strutture di controllo *while*: esegue un loop finché la condizione è vera *break*: interrompe un loop (for, while, repeat) *repeat*: loop infinito (è necessario interromperlo con un break) *next*: passa alla iterazione successiva del loop --- ## Esercizi --- ### La media Creare la funzione `media(vettore)` senza usare le funzioni `mean()` e `sum()`. ```{r prog_laMedia, echo=FALSE} media <- function (vettore) { somma <- 0 for (valore in vettore) { somma <- somma + valore } laMedia <- somma / length(vettore) return(laMedia) } ``` Test: ```{r prog_laMedia_test} vettore1 <- sample(1:10,20, replace = TRUE) media(vettore1) mean(vettore1) ``` --- ### Selezione Creare la funzione `seleziona(vettore, filtro)` senza usare il selettore `vettore[filtro]`. ```{r echo=FALSE} seleziona <- function(vettore, filtro) { ritorno <- c() for (i in 1:length(vettore)) { if (filtro[i]== TRUE) ritorno <- c(ritorno,vettore[i]) } return (ritorno) } ``` Test ```{r} vettore2 <- seq(10) vFiltro <- c(TRUE,FALSE,TRUE,FALSE,FALSE, FALSE,TRUE,TRUE,FALSE,FALSE) vettore2[vFiltro] seleziona(vettore2,vFiltro) ``` --- ### Sequenza Creare la funzione `sequenza(inizio,fine)` senza usare la funzione `seq()` né `inizio:fine`. ```{r echo=FALSE} sequenza <- function (inizio, fine) { conta <- inizio ritorno <- c() while (conta <= fine) { ritorno <- c(ritorno,conta) conta <- conta + 1 } return (ritorno) } ``` Test ```{r} seq(7,12) sequenza(7,12) ``` --- ### Lancio di dadi Creare la funzione lancio (numDadi) che simula il lancio di `numDadi` dadi e la somma del loro risultato ```{r prog_lancioDadi, echo=FALSE} lancio <- function (numDadi = 1) { somma <- sum(sample(1:6,numDadi,replace = TRUE)) return (somma) } ``` --- Test ```{r prog_lancioDadi_test} lancio(1) lancio(1) lancio(2) lancio(2) lancio(3) ``` --- Simulare mille lanci di un dado (salvando i risultati in `lanci1`), e mille lanci di due dadi (salvando i risultati in `lanci2`) ```{r prog_lancio1000Dadi, echo=FALSE} lanci1 <- rep(0,10000) for (i in 1:length(lanci1)) { lanci1[i] <- lancio(1) #print(lanci1[i]) } lanci2 <- rep(0,10000) for (i in 1:length(lanci2)) { lanci2[i] <- lancio(2) #print(lanci1[i]) } ``` -- Creare un file in rMarkdown (es dadi.Rmd), inserire i chunk relativi alla funzione dati e allo script dei lanci, con una breve descrizione dei due passaggi. -- Usando ggplot2, mostrare gli istogrammi dei due vettori `lanci1` e `lanci2` ed aggiungerli al file rMarkdown. --- ```{r cowplot, echo=FALSE, warning=FALSE} library(ggplot2) library(cowplot) ``` ```{r prog_lanci_his, echo=FALSE, warning=FALSE} farlocco <- data.frame(lanci1,lanci2) library(ggplot2) histLanci1 <- ggplot(data=farlocco,aes(lanci1)) + geom_histogram(bins = 6) + labs(title="", x="", y="", subtitle="", caption="") #plot(histLanci1) histLanci2 <- ggplot(data=farlocco,aes(lanci2)) + geom_histogram(bins = 11) + #geom_density() + labs(title="", x="", y="", subtitle="", caption="") #plot(histLanci2) plot_grid(histLanci1, histLanci2, labels = c("1 dado", "2 dadi"), ncol = 2, align = "v") ``` --- Creare la funzione `minmax` che restituisce un vettore con i valori minimo e massimo di un vettore, senza usare `min` e `max` ```{r prog_minmax, echo=FALSE, warning=FALSE} minmax <- function (vettore) { risultato <- c() if (length(vettore)<1) {return (risultato)} minimo <- vettore[1] massimo <- vettore[1] for (i in 1:length(vettore)) { if (vettore[i]< minimo) { minimo = vettore[i] } if (vettore[i]> massimo) { massimo = vettore[i] } } risultato <- c(minimo,massimo) return (risultato) } ``` ```{r prog_minmax_test} vettore3 <- sample(1:1000,20,TRUE) min(vettore3) max(vettore3) minmax(vettore3) ``` --- ### Rovesciare un vettore Creare la funzione `gira` che, dato un vettore, lo gira, senza usare la funzione `rev()`. ```{r prog_gira, echo=FALSE, warning=FALSE} gira <- function (vettore) { risultato <- c() if (length(vettore)<1) {return (risultato)} posizione <- length(vettore) while (posizione >0){ risultato <- c(risultato,vettore[posizione]) posizione <- posizione -1 } return (risultato) } ``` ```{r prog_gira_test} vettore4 <- sample(1:100,10,TRUE) vettore4 rev(vettore4) gira(vettore4) ``` --- ### Riprodurre la funzione any Creare la funzione `tutti(vettore)` la funzione `all()` senza, ovviamente, usare la funzione `all()` ```{r prog_any, echo=FALSE, warning=FALSE} tutti <- function (vettore) { if (length(vettore)<1) {return (NULL)} risposta <- TRUE for (i in length(vettore)) { if(vettore[i]==FALSE) return (FALSE) } return (TRUE) } ``` ```{r prog_any_test1} (vero <- rep(TRUE,5)) all(vero) tutti(vero) ``` --- ```{r prog_any_test2} (misto <- sample(c(TRUE,FALSE),5,replace = TRUE)) all(misto) tutti(misto) ```