Esercitazioni di programmazione in R del corso di "Laboratorio di
Transcript
Esercitazioni di programmazione in R del corso di "Laboratorio di
Laurea Magistrale in Biologia Sperimentale ed Applicata Esercitazioni di programmazione in R del corso di "Laboratorio di Statistica" Davide Guido Sara Sacco Riccardo Beltrami Unità di Statistica Medica e Genomica Dipartimento di Scienze del Sistema Nervoso e del Comportamento (Department of Brain and Behavioural Sciences) Università degli Studi di Pavia 1 Autori: Davide Guido Laboratorio di Statistica Multivariata Unità di Statistica Medica e Genomica Dipartimento di Scienze del Sistema Nervoso e del Comportamento Università degli Studi di Pavia e–mail: [email protected] Sara Sacco Laboratorio di Epidemiologia Clinica e Programmazione Sanitaria Unità di Statistica Medica e Genomica Dipartimento di Scienze del Sistema Nervoso e del Comportamento Università degli Studi di Pavia e–mail: [email protected] Riccardo Beltrami Laboratorio di Statistica Genetica ed Epidemiologia Genetica Unità di Statistica Medica e Genomica Dipartimento di Scienze del Sistema Nervoso e del Comportamento Università degli Studi di Pavia e–mail: [email protected] Software utilizzati: - Microsoft Office Excel 2010 in ambiente Windows 7 - R (versione 2.15.2) Sono gradite segnalazioni di eventuali refusi. 2 Indice 1. Cenni di analisi dei dati con Excel - Esercizi (per non soffrire Pag. troppo!) 1.1 1.2 Il Foglio Elettronico Excel L’inserimento dei dati “ “ 6 7 1.2.1 1.2.2 1.2.3 Inserimento di numeri e testo Riempimento automatico Esempio pratico “ “ “ 7 7 8 1.3 Le formule “ 10 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 Inserire una formula in una cella Formula semplice Arrotondamento decimale Separatore decimale e separatore delle migliaia Copia / Incolla speciale… Valori Formula complessa Formula con costante bloccata “ “ “ “ “ “ “ 10 10 12 13 14 16 18 1.4 La formattazione “ 20 1.4.1 1.4.2 Formattare la larghezza delle colonne Eliminare una colonna intera “ “ 20 21 1.5 L’ordinamento e il filtro dei dati “ 22 1.5.1 1.5.2 Ordinamento delle colonne dati Selezione (filtro) di alcuni dati “ “ 22 23 1.6 Le funzioni “ 27 1.6.1 1.6.2 1.6.3 Premessa Inserire una funzione Copiare una funzione “ “ “ 27 28 29 1.7 Lo strumento “Analisi dati” “ 31 1.7.1 1.7.2 Installazione Calcolo di misure di sintesi “ “ 31 33 1.8 1.9 Il grafico scatter plot e la linea di tendenza con R2 La distribuzione di frequenza “ “ 35 40 1.9.1 1.9.2 Tabella pivot Grafico pivot “ “ 40 43 1.10 Il salvataggio per l’importazione in R “ 47 1.10.1 1.10.2 Formato .csv Formato .txt “ “ 47 48 2. Utili nozioni di programmazione in R Pag. 49 2.1 2.2 2.3 2.4 2.5 Cos’è R e come utilizzarlo Come installare R e le funzioni di aiuto Gestione dei pacchetti Nomi e assegnazioni in R Operazioni elementari “ “ “ “ “ 49 50 52 53 54 2.5.1 2.5.2 Operatori aritmetici e relazionali Alcune funzioni notevoli “ “ 54 54 Esercizi “ 55 Vettori in R Alcune funzioni statistiche “ “ 56 58 3 2.6 2.7 6 “ “ Pag. “ 58 59 60 62 I comandi header, colnames(), $ e attach() Cenni di riordino dei dati “ “ 64 65 Come creare nuove funzioni in R Elementi di analisi esplorativa e nozioni elementari sulla gestione dei grafici La ricodifica di variabili in R “ “ “ 67 69 81 Esercitazione 1 Esercizi di “Elementi di programmazione in R e statistica descrittiva “ 86 2.8 2.9 2.10 2.11 Il ciclo for Matrici in R I data.frame in R Procedure di importazione ed esportazione dei dati 2.11.1 2.11.2 2.12 2.13 2.14 3. Principi di inferenza statistica 3.1 3.2 3.3 3.4 3.5 Distribuzioni di campionamento (teoriche) e variabili casuali Alcune variabili casuali notevoli Stime e stimatori Gli elementi e la filosofia dei test di significatività Test di significatività parametrici e intervalli di confidenza “ “ “ “ “ 101 103 106 109 110 3.5.1 3.5.2 3.5.3 Sulla media di una variabile casuale normale con 2 noto (Test Z a un campione) Sulla media di una variabile casuale normale con 2 ignoto (Test T a un campione) Sulla differenza tra medie di due variabili casuali normali con 2 noti e uguali (Test Z per due campioni indipendenti) Sulla differenza tra medie di due variabili casuali normali con 2 ignoti ma uguali (Test T per due campioni indipendenti) Sulla differenza tra medie di due variabili casuali normali con 2 ignoti e diversi (Test T per due campioni indipendenti) Sulla differenza tra medie di due variabili casuali normali con 2 ignoti ma uguali (Test T per due campioni appaiati) Sul rapporto di varianze di due variabili casuali normali (Test F per due campioni indipendenti) “ “ 110 122 “ 122 “ 123 “ 123 “ 124 “ 125 3.6 Test di significatività da modello probabilistico non Normale “ 125 3.6.1 3.6.2 3.6.3 3.6.4 Su una proporzione (Test Z su proporzione) Sulla differenza di due proporzioni (Test Z su differenza di proporzioni) Test di indipendenza Sull’uguaglianza di due variabili casuali (Test U di Mann-Whitney) attraverso le mediane (X0.5) Sulla normalità di una distribuzione (Test di Shapiro-Wilk) “ “ “ 125 126 128 “ “ 129 130 Esercitazione 2 Test di significatività e intervalli di confidenza “ 131 Esercitazione 3 Analisi della varianza (ANOVA), regressione lineare e correlazione “ 146 3.5.4 3.5.5 3.5.6 3.5.7 3.6.5 Pag. 101 4 5 1. Cenni di analisi dei dati con Excel - Esercizi (per non soffrire troppo!) 1.1 Il Foglio Elettronico Excel Un foglio elettronico, o foglio di calcolo, è costituito da una tabella in cui è possibile inserire testo, numeri e formule. Per aprire il foglio elettronico Excel, cliccare su: Pulsante Start Tutti i programmi Microsoft Office Microsoft Excel 2010 A questo punto, sullo schermo si aprirà il foglio elettronico Excel: esso viene presentato in una nuova cartella (Cartel1) con all’interno tre fogli di lavoro. Barra di accesso rapido Barra multifunzione Barra della formula Cella Casella del nome Colonna Riga Pulsanti di scorrimento Fogli di lavoro Come si vede, il foglio elettronico Excel è una griglia di rettangoli (celle), in cui le colonne sono denominate con lettere alfabetiche maiuscole (A, B, C, etc.) e le righe sono indicate da numeri arabi (1, 2, 3, etc.): ogni cella risulta quindi univocamente identificata dall’incrocio tra la lettera della colonna e il numero della riga corrispondenti (p.es. cella B1, cella C10, etc.). 6 1.2. L’inserimento dei dati 1.2.1 Inserimento di numeri e testo Per digitare i dati (numeri o testo) all'interno di una cella, bisogna procedere nel seguente modo: 1) posizionare il puntatore del mouse sulla cella in cui si vogliono inserire i dati, 2) cliccare con il tasto sinistro del mouse: in questo modo la cella viene evidenziata con un bordo nero per indicare che è attiva, cioè pronta per l’inserimento dei dati, 3) digitare sulla tastiera i numeri o il testo che si intendono inserire nella cella, 4) premere INVIO: in questo modo, il dato digitato viene inserito nella cella desiderata e la cella sottostante diventa automaticamente attiva. 1.2.2 Riempimento automatico Quando una cella è attiva, in corrispondenza del suo angolo inferiore destro compare un piccolo quadratino nero: posizionandovi sopra il puntatore del mouse, il quadratino assume la forma di piccola croce nera. Tenendo premuto il tasto sinistro del mouse sopra la croce nera e trascinando il mouse, è possibile duplicare il contenuto della cella (p.es. una parola), incrementare una serie riconosciuta (p.es. i mesi dell’anno) o duplicare la formula contenuta. E’ possibile incrementare anche una serie numerica: in questo caso bisogna scrivere i primi due numeri della serie, selezionare le celle (dal centro delle celle) ed infine trascinare il quadratino di riempimento. 7 1.2.3 Esempio pratico In un campione di 15 soggetti, sono stati raccolti i dati relativi alle seguenti variabili: - Sesso (variabile qualitativa, con due possibili modalità: maschio oppure femmina), - Colesterolemia Totale (variabile quantitativa continua, con modalità espresse in milligrammi per decilitro -mg/dl-), - Colesterolemia HDL (variabile quantitativa continua, con modalità espresse in mg/dl). I dati rilevati su ogni soggetto sono i seguenti (vedi File “Campione”): Soggetti 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Sesso Colesterolemia Totale (mg/dl) Colesterolemia HDL (mg/dl) femmina femmina femmina femmina femmina femmina femmina maschio maschio maschio femmina femmina maschio femmina femmina 166 184 151 236 169 202 177 215 174 214 151 204 166 182 224 79 56 58 60 67 50 71 72 37 57 48 68 59 66 62 Per inserire questi dati in un foglio elettronico Excel procediamo nel seguente modo: 1) 2) 3) 4) lasciamo vuota la colonna A: ci servirà in seguito, posizioniamo il puntatore del mouse sulla cella B1, clicchiamo con il tasto sinistro del mouse, stabiliamo un nome (label o etichetta) per la prima delle tre variabili raccolte, cioè la variabile Sesso, e lo digitiamo (label scelta: sesso), 5) premiamo INVIO, 6) ripetiamo l’intera procedura (punti 2, 3, 4 e 5) per le variabili Colesterolemia Totale (label scelta: coltot) e Colesterolemia HDL (label scelta: hdl), inserendo le rispettive labels nelle celle C1 e D1, 7) posizioniamo il puntatore del mouse sulla cella B2, 8) clicchiamo con il tasto sinistro del mouse, 9) digitiamo la modalità (femmina, codifica: f) che la variabile Sesso assume nel primo soggetto del campione (per i maschi usiamo la codifica m), 10) premiamo INVIO, 11) ripetiamo le operazioni indicate ai punti 9 e 10, fino ad inserire nella colonna B le modalità assunte dalla variabile Sesso in tutti i 15 soggetti del campione (ogni riga corrisponderà ad un soggetto), 12) ripetiamo l’intera procedura (punti 7, 8, 9, 10 e 11) per le variabili Colesterolemia Totale e Colesterolemia HDL, inserendo le rispettive modalità nella colonna C (a partire dalla C2) e nella colonna D (a partire dalla cella D2), 8 13) a questo punto, ci spostiamo nella colonna A e qui creiamo una nuova variabile (la variabile Identificativo, con label ID) che assume i valori numerici da 1 a 15 e serve ad identificare in maniera univoca ognuno dei 15 soggetti componenti il campione: a. posizioniamo il puntatore del mouse sulla cella A1, b. clicchiamo con il tasto sinistro del mouse, c. digitiamo la label ID, d. premiamo INVIO, e. posizioniamo il puntatore del mouse sulla cella A2, f. clicchiamo con il tasto sinistro del mouse, g. digitiamo la cifra 1, h. premiamo INVIO, i. digitiamo la cifra 2, j. premiamo INVIO, k. posizioniamo il puntatore del mouse sulla cella A2, l. premiamo il tasto sinistro del mouse e, senza rilasciarlo, trasciniamo il mouse verso il basso fino a selezionare le celle A2 e A3 che vengono così evidenziate in azzurro, m. rilasciamo il tasto sinistro del mouse, n. posizioniamo il puntatore del mouse sopra il quadratino nero presente in corrispondenza dell’angolo inferiore destro della cella A3: il quadratino assume così la forma di piccola croce nera, o. premiamo il tasto sinistro del mouse e, senza rilasciarlo, trasciniamo il mouse verso il basso: in questo modo compare un bordo nero ombreggiato che si espande ad evidenziare le celle sottostanti, p. continuiamo a trascinare il mouse verso il basso finché il bordo nero ombreggiato evidenzia tutte le celle della colonna A da A2 a A16 compresa, q. rilasciamo il tasto sinistro del mouse e vedremo comparire la serie numerica 1-15 nelle celle da A2 a A16, r. clicchiamo con il tasto sinistro del mouse su una cella qualunque del foglio elettronico per far scomparire la selezione. Ecco che a questo punto tutti i nostri dati risultano inseriti su quattro colonne del foglio elettronico: ciascuna colonna corrisponde a una variabile (da sinistra verso destra: Identificativo, Sesso, Colesterolemia Totale e Colesterolemia HDL) e ciascuna riga corrisponde a un soggetto del campione (dall’alto verso il basso da 1 a 15). 9 1.3 Le formule 1.3.1 Inserire una formula in una cella Una formula è un insieme di operazioni su numeri, funzioni e contenuti numerici di celle e fornisce in uscita un valore numerico. Le funzioni più importanti sono senza dubbio gli operatori aritmetici (+ - * /) di somma (addizione), differenza (sottrazione), prodotto (moltiplicazione) e quoziente (divisione) che permettono di costruire formule per tutte le esigenze. Una formula comincia sempre con il simbolo = (uguale) e può contenere costanti, riferimenti di celle e di intervalli, funzioni. Ad esempio =A1*A3 è una formula che moltiplica il contenuto della cella A1 per il contenuto della cella A3. E’ possibile inserire anche formule più articolate: ad esempio =A1*A3/B4 è una formula che moltiplica il contenuto della cella A1 per il contenuto della cella A3 e divide il tutto per il contenuto della cella B4. L’inserimento manuale di una formula avviene nel seguente modo: 1) selezionare la cella in cui si desidera immettere la formula, 2) digitare = (segno di uguale MAIUSC. + 0), 3) immettere il nome della prima cella (o selezionarla col click del mouse), 4) inserire l’operatore aritmetico (+ addizione; - sottrazione; * moltiplicazione; / divisione), 5) immettere il nome della seconda cella (o selezionarla col click del mouse), 6) premere INVIO. 1.3.2 Formula semplice L’Indice di rischio cardiovascolare è un numero puro o adimensionale, cioè senza unità di misura (valori normali: < 5 per i maschi e < 4,5 per le femmine), che risulta dal rapporto tra il valore di Colesterolemia Totale e il valore di Colesterolemia HDL di ciascun soggetto: Calcoliamo l’Indice di rischio cardiovascolare per ciascuno dei 15 soggetti di cui abbiamo inserito i dati nell’esempio pratico 1.2.3: 1) posizioniamo il puntatore del mouse sulla cella E1, 2) clicchiamo con il tasto sinistro del mouse, 3) digitiamo coltot/hdl (è la label scelta per la nuova variabile Indice di rischio cardiovascolare, variabile quantitativa continua con modalità adimensionali), 4) premiamo INVIO, 5) digitiamo il segno = (il segno comparirà ovviamente nella cella E2), 6) posizioniamo il puntatore del mouse sulla cella C2, 7) clicchiamo con il tasto sinistro del mouse (in questo modo la cella C2 assumerà un bordo blu e, nella cella E2, dopo il segno = comparirà la scritta C2 nello stesso colore), 8) digitiamo il segno / (la scritta appare sempre nella cella E2), 10 9) posizioniamo il puntatore del mouse sulla cella D2, 10) clicchiamo con il tasto sinistro del mouse (in questo modo la cella D2 assumerà un bordo verde e, nella cella E2, dopo il segno = comparirà la scritta D2 nello stesso colore), 11) premiamo INVIO: nella cella E2 compare il numero 2,101266, 12) posizioniamo il puntatore del mouse sulla cella E2 e clicchiamo con il tasto sinistro, 13) clicchiamo con il tasto destro del mouse, 14) con il tasto sinistro del mouse selezioniamo Copia, 15) posizioniamo il puntatore del mouse sulla cella E3, 16) premiamo il tasto sinistro del mouse e, senza rilasciarlo, trasciniamo il mouse verso il basso fino a selezionare tutte le celle da E3 e E16, che vengono così evidenziate in azzurro, 17) rilasciamo il tasto sinistro del mouse, 18) posizioniamo il puntatore del mouse all’interno dell’area selezionata, 19) clicchiamo con il tasto destro del mouse, 20) con il tasto sinistro del mouse selezioniamo Opzioni Incolla… Incolla (N): nella colonna E compaiono tutti i valori dell’Indice di rischio cardiovascolare calcolato per ciascun soggetto (le cifre decimali seguono il numero intero dopo la virgola), 21) clicchiamo con il tasto sinistro del mouse su una cella qualunque del foglio elettronico per far scomparire la selezione. 11 1.3.3 Arrotondamento decimale Se vogliamo arrotondare i valori dell’Indice di rischio cardiovascolare alla seconda cifra decimale, procediamo così: 1) posizioniamo il puntatore del mouse sulla cella E2, 2) premiamo il tasto sinistro del mouse e, senza rilasciarlo, trasciniamo il mouse verso il basso fino a selezionare tutte le celle da E2 e E16, che vengono così evidenziate in azzurro, 3) rilasciamo il tasto sinistro del mouse, 4) posizioniamo il puntatore del mouse all’interno dell’area selezionata, 5) clicchiamo con il tasto destro del mouse, 6) con il tasto sinistro del mouse selezioniamo Formato celle..., 7) si apre una finestra di dialogo: con il tasto sinistro del mouse selezioniamo Numero, agendo sui tasti freccia all’interno della finestra indichiamo quante Posizioni decimali vogliamo considerare (nel nostro caso: 2) e infine selezioniamo OK, 8) tutti i valori dell’Indice di rischio cardiovascolare risulteranno approssimati alla seconda cifra decimale: clicchiamo con il tasto sinistro del mouse su una cella qualunque del foglio elettronico per far scomparire la selezione. 12 1.3.4 Separatore decimale e separatore delle migliaia Excel utilizza di default la virgola (,) come separatore decimale e il punto (.) come separatore delle migliaia. A livello internazionale succede invece l’opposto: si usa il punto (.) come separatore decimale e la virgola (,) come separatore delle migliaia. Anche i più comuni programmi statistici (R compreso) utilizzano questo secondo sistema. Per far sì che anche Excel utilizzi i separatori internazionali, si procede così: 1) nella barra multifunzione selezionare la scheda File e quindi cliccare su Opzioni, 2) si apre una finestra di dialogo: selezionare Impostazioni avanzate, togliere la spunta a Utilizza separatori di sistema, quindi digitare i separatori desiderati: il punto (.) come Separatore decimale e la virgola (,) come Separatore delle migliaia, infine premere OK, 13 3) ora Excel utilizza i separatori internazionali ed ecco come appare il file cui abbiamo lavorato finora: 4) per tornare ai separatori utilizzati in precedenza, è sufficiente riaprire la finestra di cui al punto 2 e spuntare nuovamente la voce Utilizza separatori di sistema. 1.3.5 Copia / Incolla speciale… Valori I comandi Copia / Incolla speciale… Valori servono a copiare i valori (senza le formule con le quali sono stati calcolati) contenuti in alcune celle e a incollarli in altre celle. Supponiamo di voler in copiare i valori contenuti nella colonna E del file cui abbiamo lavorato finora (= i valori dell’Indice di rischio cardiovascolare) e di volerli poi incollare nel foglio di lavoro Foglio 2. Procediamo: 1) tenendo premuto il tasto sinistro e trascinando il mouse verso il basso, selezionare le celle dalla E1 alla E16 compresa, 2) mantenendo il puntatore del mouse all’interno dell’area selezionata, cliccare con il tasto destro del mouse e selezionare Copia, 3) passare al foglio di lavoro Foglio 2 (agire sui tasti in basso a sinistra nel foglio elettronico), 4) mantenendo il puntatore del mouse all’interno della cella A1 (che appare già attiva), cliccare con il tasto destro e selezionare Opzioni Incolla… Incolla (N): nella colonna A appariranno 15 messaggi di errore (perché questo comando ha incollato le formule presenti nelle celle di origine che qui però non trovano riferimenti numerici in altre celle e quindi non possono effettuare alcun calcolo per restituire i valori), 14 5) posizionare nuovamente il puntatore del mouse nella cella A1 e cliccare con il tasto sinistro per renderla attiva, 6) mantenendo il puntatore del mouse all’interno della cella A1, cliccare con il tasto destro e selezionare Incolla speciale…, 7) si apre una finestra di dialogo: spuntare la voce Valori e premere OK, 8) questa volta appaiono i valori desiderati: 15 1.3.6 Formula complessa La Formula di Friedewald permette di stimare il valore della Colesterolemia LDL (mg/dl) di un soggetto a partire dai suoi valori di Colesterolemia Totale (mg/dl), di Colesterolemia HDL (mg/dl) e di Trigliceridemia (mg/dl): Consideriamo un campione di 15 soggetti, in cui sono stati raccolti i dati relativi alle seguenti variabili (apri: File Excel “Dati”): - Sesso (variabile qualitativa, con due possibili modalità: maschio oppure femmina), - Età (variabile quantitativa discreta, con modalità espresse in anni), - Glicemia (variabile quantitativa continua, con modalità espresse in mg/dl), - Colesterolemia Totale (variabile quantitativa continua, con modalità espresse in mg/dl), - Colesterolemia HDL (variabile quantitativa continua, con modalità espresse in mg/dl), - Trigliceridemia (quantitativa continua, con modalità espresse in mg/dl). Per calcolare il valore di Colesterolemia LDL per ciascun soggetto mediante la formula di Friedewald, bisogna procedere così: 1) posizionare il puntatore del mouse sulla cella H1 e cliccare con il tasto sinistro per renderla attiva, 2) digitare ldl (è la label scelta per la nuova variabile Colesterolemia LDL, variabile quantitativa continua con modalità espresse in mg/dl), 3) premere INVIO, 4) digitare il segno = (il segno comparirà ovviamente nella cella H2), 5) posizionare il puntatore del mouse sulla cella E2 e cliccare con il tasto sinistro (in questo modo la cella E2 assumerà un bordo blu e, nella cella H2, dopo il segno = comparirà la scritta E2 nello stesso colore), 6) digitare il segno – e poi il segno ( (le scritte appaiono sempre nella cella H2), 16 7) posizionare il puntatore del mouse sulla cella F2 e cliccare con il tasto sinistro (in questo modo la cella F2 assumerà un bordo verde e, nella cella H2, dopo i segni –( comparirà la scritta F2 nello stesso colore), 8) digitare il segno + e poi il segno ( (le scritte appaiono sempre nella cella H2), 9) posizionare il puntatore del mouse sulla cella G2 e cliccare con il tasto sinistro (in questo modo la cella G2 assumerà un bordo viola e, nella cella H2, dopo i segni +( comparirà la scritta G2 nello stesso colore), 10) digitare il segno / e poi il numero 5 (le scritte appaiono sempre nella cella H2), quindi digitare due parentesi tonde in chiusura )) , 11) premere INVIO: nella cella H2 compare il numero 73.2, 12) posizionare il puntatore del mouse sulla cella H2 e cliccare con il tasto sinistro, 13) mantenendo il puntatore all’interno della cella H2, cliccare con il tasto destro del mouse e poi con il tasto sinistro selezionare Copia, 14) posizionare il puntatore del mouse sulla cella H3, 15) premere il tasto sinistro del mouse e, senza rilasciarlo, trascinare il mouse verso il basso fino a selezionare tutte le celle da H3 e H16 compresa, che vengono così evidenziate in azzurro, 16) rilasciare il tasto sinistro del mouse, 17) mantenendo il puntatore del mouse all’interno dell’area selezionata, cliccare con il tasto destro e poi con il tasto sinistro selezionare Opzioni Incolla… Incolla (N): nella colonna H compaiono tutti i valori della Colesterolemia LDL calcolata per ciascun soggetto con la Formula di Friedewald (le cifre decimali seguono il numero intero dopo il punto), 18) cliccare con il tasto sinistro del mouse su una cella qualunque del foglio elettronico per far scomparire la selezione. 17 1.3.7 Formula con costante bloccata I valori assunti dalla glicemia, come quelli di altri parametri ematochimici, sono tradizionalmente espressi in milligrammi per decilitro (mg/dl). Il SI (Sistema Internazionale) di Unità di Misura invece esprime la glicemia in millimoli per litro (mmol/l). Il passaggio dai mg/dl alle mmol/l (o viceversa) avviene semplicemente dividendo (o moltiplicando) il valore della glicemia per 18 (cioè per una costante): Proviamo a convertire in mmol/l i valori di glicemia (espressi in mg/dl) relativi al campione di 15 soggetti su cui abbiamo lavorato con la formula di Friedewald: 1) 2) 3) 4) 5) posizionare il puntatore del mouse sulla cella I1 e cliccare con il tasto sinistro, digitare costante e premere INVIO, digitare il numero 18 (che verrà a questo punto scritto nella cella I2) e premere INVIO, posizionare il puntatore del mouse sulla cella J1 e cliccare con il tasto sinistro, digitare glicemiaSI (è la label scelta per la nuova variabile Glicemia, variabile quantitativa continua con modalità espresse in mmol/l) e premere INVIO, 6) digitare il segno = (il segno comparirà ovviamente nella cella J2), 7) posizionare il puntatore del mouse sulla cella D2 e cliccare con il tasto sinistro (in questo modo la cella D2 assumerà un bordo blu e, nella cella J2, dopo il segno = comparirà la scritta D2 nello stesso colore), 8) digitare in sequenza (senza spaziature) i segni / $ I $ 2 (le scritte appaiono sempre nella cella J2 e notiamo che la cella I2 assume un bordo verde. Il simbolo del dollaro $ serve a bloccare colonna e riga.), 9) premere INVIO: nella cella J2 compare il numero 5.722222, 10) posizionare il puntatore del mouse sulla cella J2 e cliccare con il tasto sinistro, 11) mantenendo il puntatore del mouse all’interno della cella J2, cliccare con il tasto destro e poi con il tasto sinistro selezionare Copia, 12) posizionare il puntatore del mouse sulla cella J3, 18 13) premere il tasto sinistro del mouse e, senza rilasciarlo, trascinare il mouse verso il basso fino a selezionare tutte le celle da J3 e J16 compresa, che vengono così evidenziate in azzurro, 14) rilasciare il tasto sinistro del mouse, 15) mantenendo il puntatore del mouse all’interno dell’area selezionata, cliccare con il tasto destro del mouse e poi con il tasto sinistro selezionare Opzioni Incolla… Incolla (N): nella colonna J compaiono i valori di glicemia di ciascun soggetto espressi in mmol/l (le cifre decimali seguono il numero intero dopo il punto), 16) cliccare con il tasto sinistro del mouse su una cella qualunque del foglio elettronico per far scomparire la selezione. 19 1.4 La formattazione 1.4.1 Formattare la larghezza delle colonne Per adattare le dimensioni delle colonne del foglio elettronico al loro contenuto, in modo che la matrice dei dati risulti nel suo complesso meno larga, bisogna procedere così (continuiamo a lavorare sempre sullo stesso file): 1) posizionare il puntatore del mouse in corrispondenza della lettera A che individua la prima colonna del foglio elettronico, 2) premere il tasto sinistro del mouse e, senza rilasciarlo, trascinare il mouse verso destra fino a selezionare tutte le colonne in cui sono presenti dati (nel nostro caso le colonne dalla A alla J): le colonne selezionate verranno ombreggiate in azzurro, 3) rilasciare il tasto sinistro del mouse, 4) nella scheda Home della barra multifunzione, selezionare Formato e quindi Adatta larghezza colonne, 5) cliccare con il tasto sinistro del mouse su una cella qualunque del foglio elettronico per far scomparire la selezione: a questo punto la larghezza delle colonne del foglio elettronico sarà adattata al loro contenuto. 20 1.4.2 Eliminare una colonna intera Immaginiamo di avere un foglio elettronico in cui per sbaglio è stata lasciata una colonna vuota (la colonna E). Per eliminarla, si procede nel seguente modo: 1) posizionare il puntatore del mouse in corrispondenza della lettera E che individua la colonna vuota da eliminare, 2) cliccare con il tasto sinistro del mouse e così evidenziare l’intera colonna E (che apparirà ombreggiata in azzurro), 3) mantenendo il puntatore del mouse all’interno dell’area selezionata, cliccare con il tasto destro e poi con il tasto sinistro selezionare Elimina, 4) cliccare con il tasto sinistro del mouse su una cella qualunque del foglio elettronico per far scomparire la selezione: a questo punto la colonna vuota risulterà eliminata. 21 1.5 L’ordinamento e il filtro dei dati 1.5.1 Ordinamento delle colonne dati Supponiamo di voler disporre in ordine di età crescente i soggetti del nostro campione (continuiamo a lavorare sullo stesso file che abbiamo utilizzato finora), in modo che sul foglio elettronico essi appaiano (con le relative misurazioni) ordinati dall’alto verso il basso dal più giovane al più anziano. Si procede così: 1) tenendo premuto il tasto sinistro e trascinando il mouse verso destra e verso il basso, selezionare tutte le celle comprese nell’area del rettangolo avente per base le celle A2-J2 e per altezza le celle A2-A16 (escludiamo quindi soltanto le celle contenenti le labels delle variabili), 2) nella scheda Dati della barra multifunzione, selezionare Ordina, 3) si apre una finestra di dialogo: nel primo menu a tendina a sinistra, selezionare età (negli altri due menu a tendina compariranno automaticamente Valori e Dal più piccolo al più grande) e premere OK, 22 4) i dati appaiono ordinati per età crescente, ma nella colonna glicemiaSI compaiono messaggi di errore in quanto la formula in essa presente non trova più il riferimento per eseguire il calcolo: digitiamo 18 nella cella A2, premiamo INVIO e i dati appariranno come segue, 5) è possibile ripetere il comando con opzioni di ordinamento sequenziali: questa procedura serve a ordinare valori che in origine non sono in sequenza e permette applicazioni successive per la selezione, l’eliminazione o l’elaborazione. 1.5.2 Selezione (filtro) di alcuni dati Supponiamo di voler selezionare solo alcuni soggetti del nostro campione (continuiamo a lavorare sullo stesso file che abbiamo utilizzato finora), p.es. solo le femmine, poi solo i maschi e infine solo i soggetti che hanno un’età compresa tra i 30 e i 35 anni. Si procede così: 1) tenendo premuto il tasto sinistro e trascinando il mouse verso destra e verso il basso, selezionare tutte le celle comprese nell’area del rettangolo avente per base le celle A1-J1 e per altezza le celle A1-A16 (cioè selezioniamo anche le celle contenenti le labels delle variabili), 2) nella scheda Dati della barra multifunzione, selezionare Filtro: a destra della label di ogni variabile comparirà un triangolino, 23 3) cliccare sul triangolino posto alla destra della label sesso e, nel menu conseguentemente apertosi, togliere la spunta vicino alla lettera m (maschio), quindi premere OK. I dati appariranno come segue: accanto alla label sesso compare il simbolo di un piccolo imbuto per indicare che i dati sono filtrati per sesso, nello specifico sono riportati soltanto i dati relativi alle femmine componenti il nostro campione di 15 soggetti. 4) cliccare sull’imbuto a destra della label sesso e, nel menu conseguentemente apertosi, togliere la spunta vicino alla lettera f (femmina) e metterla vicino alla lettera m, quindi premere OK 24 Ora appariranno soltanto i dati relativi ai maschi componenti il campione di 15 soggetti: se lo si desidera, è possibile copiare questi valori, incollarli su un altro foglio di lavoro e quindi eventualmente inserire formule e funzioni. 5) nella scheda Dati della barra multifunzione, selezionare nuovamente Filtro: in questo modo, il filtro viene tolto e appaiono i dati relativi a tutti i soggetti, 6) ripetere le operazioni descritte ai punti 1 e 2, 7) cliccare sul triangolino posto alla destra della label età e, nel menu conseguentemente apertosi, cliccare su Filtri per numeri e poi su Filtro personalizzato, 8) si apre una finestra di dialogo: nel menu a tendina in alto a sinistra selezionare è maggiore o uguale a, nella casella in alto a destra digitare 30, quindi nel menu a tendina in basso a sinistra selezionare è minore o uguale a, nella casella in basso a destra digitare 35 e infine premere OK. 25 I dati appariranno come segue: accanto alla label età compare il simbolo di un piccolo imbuto per indicare che i dati sono filtrati per età, nello specifico sono riportati soltanto i dati relativi ai soggetti di età compresa tra i 30 e i 35 anni. 9) nella scheda Dati della barra multifunzione, selezionare nuovamente Filtro: in questo modo, il filtro viene tolto e appaiono i dati relativi a tutti i soggetti. 26 1.6 Le funzioni 1.6.1 Premessa In Excel sono presenti centinaia di formule, dalle più semplici alle più complesse, divise per categorie. Nella scheda Formule della barra multifunzione, è possibile accedere all’elenco di tutte le funzioni dal pulsante oppure scegliere direttamente la categoria interessata dai relativi pulsanti. Per le funzioni principali indicate di seguito, è possibile utilizzare anche il pulsante presente nella scheda Home della barra multifunzione: Funzione SOMMA Somma tutti i numeri presenti in un intervallo di celle. P.es. =SOMMA(A1:A10) eseguirà la somma automatica dei numeri presenti nell’intervallo dalla cella A1 alla cella A10. Funzione MEDIA Essa restituisce la media aritmetica degli argomenti. P.es. =MEDIA(A1:A10) eseguirà la media dei numeri presenti nell’intervallo dalla cella A1 alla cella A10. Funzione CONTA.NUMERI Conta quanti valori numerici sono presenti in un intervallo di celle. P.es. =CONTA.NUMERI(A1:A10) conta quanti numeri sono presenti nell’intervallo dalla cella A1 alla cella A10. Funzione MAX Essa restituisce il valore più alto di una serie di celle. P.es. =MAX(A1:A10) visualizzerà il numero più alto tra quelli presenti nell’intervallo dalla cella A1 alla cella A10. Funzione MIN Essa restituisce il valore più basso di una serie di celle. P.es. =MIN(A1:A10) visualizzerà il numero più basso tra quelli presenti nell’intervallo dalla cella A1 alla cella A10. 27 1.6.2 Inserire una funzione Proviamo ad inserire alcune funzioni nel file su cui abbiamo lavorato finora. Procediamo così: 1) posizionare il puntatore del mouse in corrispondenza della prima cella libera al di sotto dei dati inseriti nella colonna A (cella A17) e cliccare con il tasto sinistro per renderla attiva, 2) digitare sommatoria e premere INVIO, 3) digitare media e premere INVIO, 4) digitare deviazione standard e premere INVIO, 5) digitare mediana e premere INVIO, 6) le parole inserite eccedono la larghezza della colonna precedentemente adattata: ripetiamo quindi le operazioni descritte nel paragrafo 1.4.1 “Formattare la larghezza delle colonne” in modo da ottenere una larghezza ottimale, 7) posizionare il mouse in corrispondenza della cella B17 e cliccare con il tasto sinistro, 8) nella scheda Formule della barra multifunzione, selezionare Inserisci funzione, 9) si aprirà una finestra di dialogo: selezionare la categoria Tutte nel menu a tendina, nell’elenco selezionare la funzione SOMMA e infine premere OK, 28 10) si aprirà un’altra finestra di dialogo: cliccare sul quadratino indicato dalla freccia nella figura qui sotto (la finestra di dialogo diventerà più piccola), 11) selezionare, sul foglio elettronico, le celle alle quali si vuole applicare la funzione: nel nostro caso, selezionare le celle da B2 a B16 inclusa, 12) cliccare nuovamente sul quadratino specificato al punto 10 (la finestra di dialogo tornerà alle dimensioni originali), 13) premere OK: nella cella B17 appare il valore assunto dalla somma di tutti i dati numerici contenuti nelle celle dalla B2 alla B16 inclusa (il valore è ovviamente zero, perché la colonna B nel nostro caso non contiene dati numerici), 14) posizionare il mouse in corrispondenza della cella B18 e cliccare con il tasto sinistro, 15) ripetere la procedura descritta dal punto 8 al punto 13, selezionando però la funzione MEDIA e facendo poi attenzione a selezionare sempre le celle dalla B2 alla B16, 16) posizionare il mouse in corrispondenza della cella B19 e cliccare con il tasto sinistro, 17) ripetere la procedura descritta dal punto 8 al punto 13, selezionando però la funzione DEV.ST e facendo poi attenzione a selezionare sempre le celle dalla B2 alla B16, 18) posizionare il mouse in corrispondenza della cella B20 e cliccare con il tasto sinistro, 19) ripetere la procedura descritta dal punto 8 al punto 13, selezionando però la funzione MEDIANA e facendo poi attenzione a selezionare sempre le celle dalla B2 alla B16 (compaiono messaggi di errore, in quanto queste funzioni non possono essere calcolate per la variabile qualitativa Sesso). 1.6.3 Copiare una funzione A questo punto, per inserire le medesime funzioni anche nelle altre colonne contenenti dati, si procede così: 1) posizionare il puntatore del mouse in corrispondenza della cella contenente il risultato calcolato dalla funzione SOMMA nella colonna B (cella B17) e cliccare con il tasto sinistro, 2) tenendo premuto il tasto sinistro e trascinando il mouse verso il basso, selezionare le celle dalla B17 alla B20 compresa, 3) mantenendo il puntatore del mouse all’interno dell’area selezionata, cliccare con il tasto destro e selezionare Copia, 4) tenendo premuto il tasto sinistro e trascinando il mouse dapprima verso il basso e poi verso destra, selezionare tutte le celle comprese nell’area del rettangolo avente altezza corrispondente alle celle C17-C20 e base corrispondente alle celle C20-J20, 29 5) mantenendo il puntatore del mouse all’interno dell’area selezionata, cliccare con il tasto destro e selezionare Opzioni Incolla… Incolla (N): appariranno i valori calcolati dalle funzioni per tutte le variabili e i soggetti del campione, 6) nelle colonne B e I compaiono messaggi di errore o valori insensati: è possibile cancellarli e lasciare vuote le celle, in quanto non ha senso calcolare le funzioni descritte per la variabile Sesso (variabile qualitativa) e per la costante di conversione delle unità di misura della glicemia, 7) nella cella B17 compaiono i segni #: indicano che la larghezza della cella è insufficiente per visualizzare il numero in essa contenuto, per cui ripetiamo ancora una volta la procedura per adattare la larghezza delle colonne, 8) a questo punto, per meglio visualizzare e diversificare i valori delle funzioni, è possibile dare un colore diverso alle celle nel seguente modo: tenendo premuto il tasto sinistro e trascinando il mouse dapprima verso il basso e poi verso destra, selezionare tutte le celle comprese nell’area del rettangolo avente altezza corrispondente alle celle A17-A20 e base corrispondente alle celle A20-J20, selezionare la scheda Home nella barra multifunzione, nel menu Carattere, scegliere un colore di riempimento (p.es. verde chiaro). Ecco come appare ora il nostro insieme di dati (dataset): 30 1.7 Lo strumento “Analisi dati” 1.7.1 Installazione Innanzitutto bisogna aggiungere lo strumento all’interno di Excel, in quanto non viene fornito di base dal programma. Per fare ciò, procediamo nel seguente modo: 1) nella scheda File della barra multifunzione, selezionare Opzioni, 2) si apre una finestra di dialogo: selezionare Componenti aggiuntivi, poi Strumenti di analisi VBA e quindi premere Vai, 31 3) si apre un’ulteriore finestra di dialogo, in cui è necessario selezionare Strumenti di analisi e poi OK, 4) si apre un’ultima finestra di dialogo che richiede una conferma prima di procedere all’installazione: selezioniamo OK e si avvierà l’installazione, 5) terminata l’installazione, il menu della barra multifunzione apparirà aggiornato: nella scheda Dati, comparirà infatti la nuova funzione Analisi dati. 32 1.7.2 Calcolo di misure di sintesi Per calcolare alcune misure di sintesi sul nostro dataset (continuiamo a lavorare sullo stesso file che abbiamo usato finora), si procede così: 1) sulla barra multifunzione selezionare la scheda Dati e quindi cliccare su Analisi dati, 2) si apre una finestra di dialogo: selezionare Statistica descrittiva e quindi OK, 3) si apre un’altra finestra di dialogo: cliccare sul quadratino indicato dalla freccia nella figura qui sotto (la finestra di dialogo diventerà più piccola), 4) selezionare, sul foglio elettronico, le celle corrispondenti alla variabile per la quale si vogliono calcolare le misure di sintesi: p.es., se scegliamo la variabile Età (colonna C), selezioniamo le celle da C1 a C16 inclusa, 5) cliccare nuovamente sul quadratino specificato al punto 3 (la finestra di dialogo tornerà alle dimensioni originali e il campo Intervallo di input riporterà l’indicazione delle celle che abbiamo selezionato), 6) spuntare le voci Etichette nella prima riga (perché, tra le celle selezionate al punto precedente, è presente anche la cella C1 che contiene la label della variabile Età) e Riepilogo statistiche, selezionare Nuovo foglio di lavoro e quindi cliccare su OK, 33 7) si apre un nuovo foglio di lavoro (Foglio 4), su cui possiamo applicare la procedura per adattare la larghezza delle colonne al loro contenuto: vedremo quindi riportati i valori delle statistiche descrittive relative alla variabile Età, che possiamo confrontare con quelli ottenuti precedentemente con l’impostazione manuale delle funzioni. 34 1.8 Il grafico scatter plot e la linea di tendenza con R2 Per disegnare un grafico scatter plot e una linea di tendenza con R2, procedere come segue (continuiamo a lavorare sullo stesso file che abbiamo usato finora): 1) tornare al foglio di lavoro precedente (Foglio 1), 2) selezionare le celle contenenti i valori delle variabili Età e Glicemia (comprese le celle contenenti le rispettive labels, ma escluse le celle con i valori delle statistiche descrittive), 3) all’interno dell’area selezionata, cliccare con il tasto destro del mouse e selezionare Copia, 4) tornare al foglio di lavoro Foglio 4, 5) posizionare il puntatore del mouse in corrispondenza della cella D1 e cliccare con il tasto sinistro per renderla attiva, 6) mantenendo il puntatore del mouse all’interno della cella D1, cliccare con il tasto destro e selezionare Opzioni Incolla… Incolla (N), 7) assicurarsi che le celle contenenti le labels e i valori delle due variabili Età e Glicemia siano selezionate (se non lo sono, selezionarle), 8) nella barra multifunzione, selezionare la scheda Inserisci, 9) all’interno del menu Grafici, cliccare su Grafico a dispersione e quindi, nel menu a tendina apertosi, cliccare sulla prima figura in alto a sinistra (Dispersione con solo indicatori), 10) nel Foglio 4 apparirà ora un grafico che illustra come, nel nostro campione di 15 soggetti, la Glicemia (riportata sull’asse y) varia in funzione dell’Età (riportata sull’asse x): 35 11) occorre però apportare alcune migliorie al suddetto grafico: posizionare il puntatore del mouse in corrispondenza del contorno del grafico (il puntatore assume la forma di quattro piccole frecce ortogonali tra loro), tenendo premuto il tasto sinistro e trascinando il mouse, spostare il grafico in modo che non copra le colonne contenenti dati, cliccare con il tasto sinistro del mouse all’interno della casella di testo posizionata al disopra del grafico e contenente la scritta glicemia (è il titolo del grafico scelto automaticamente da Excel): cancellare il testo presente e digitare La Glicemia in funzione dell’Età, posizionare il puntatore del mouse in corrispondenza di uno qualsiasi dei valori riportati sull’asse x del grafico, cliccare con il tasto destro e selezionare Formato asse, si apre una finestra di dialogo mediante la quale è possibile stabilire il valore minimo e il valore massimo da rappresentare sull’asse x del grafico: visto che la variabile Età varia da un minimo di 28 anni a un massimo di 53 anni, spuntiamo la voce Fissa in corrispondenza di Valore minimo e digitiamo 25 nel rettangolo bianco immediatamente a destra, poi spuntiamo la voce Fissa in corrispondenza di Valore massimo e digitiamo 55 nel rettangolo bianco immediatamente a destra, infine clicchiamo su Chiudi, 36 ripetere l’operazione per l’asse y, fissando 65 come Valore minimo e 105 come Valore massimo (poiché la variabile Glicemia varia da un minimo di 70 mg/dl a un massimo di 103 mg/dl), nel menu Strumenti grafico (che compare solo quando il grafico è selezionato), selezionare la scheda Layout: nel menu Etichette, cliccare su Titoli degli assi, poi su Titolo asse orizzontale principale e infine su Titolo sotto l’asse, sotto l’asse x del grafico, compare una casella di testo con la scritta Titolo asse: cliccarvi all’interno con il tasto sinistro del mouse, cancellare il testo presente e digitare Età (anni), ripetere la procedura scegliendo Titolo asse verticale principale, poi Titolo ruotato e quindi digitando Glicemia (mg/dl), a questo punto, il nostro grafico appare come segue: 37 12) nel menu Strumenti grafico (che compare solo quando il grafico è selezionato), selezionare la scheda Layout: nel menu Analisi, cliccare su Linea di tendenza e poi su Altre opzioni linea di tendenza, 13) si apre una finestra di dialogo: selezionare Lineare, spuntare Visualizza l’equazione sul grafico e Visualizza il valore R al quadrato sul grafico, quindi cliccare su Chiudi, 14) sul grafico, compare una casella di testo contenente l’equazione e il valore di R al quadrato: se si sovrappone ai dati, spostarla vicino alla legenda. 38 A questo punto il grafico appare come segue: 39 1.9 La distribuzione di frequenza Una distribuzione di frequenza rappresenta, mediante una tabella o un grafico, il numero di soggetti (frequenza assoluta) sui quali viene rilevata ciascuna modalità di una variabile. 1.9.1 Tabella pivot Per costruire la distribuzione di frequenza della variabile Età nel nostro campione di 15 soggetti tramite una tabella pivot, procedere nel seguente modo (continuare ad utilizzare il file su cui abbiamo lavorato finora): 1) portarsi nel foglio di lavoro Foglio 1, 2) sulla barra multifunzione selezionare la scheda Inserisci, quindi cliccare sulla metà inferiore del pulsante Tabella pivot e selezionare Tabella pivot, 3) si apre una finestra di dialogo: cliccare sul quadratino indicato dalla freccia nella figura qui sotto (la finestra di dialogo diventerà più piccola), 4) selezionare, sul foglio elettronico, le celle (label + valori) corrispondenti alla variabile di cui si vuole costruire la distribuzione di frequenza: nel nostro caso, selezionare le celle da C1 a C16 inclusa, 40 5) cliccare nuovamente sul quadratino specificato al punto 3 (la finestra di dialogo tornerà alle dimensioni originali e, vicino alla dicitura Tabella/Intervallo, riporterà l’indicazione delle celle appena selezionate), 6) a questo punto spuntare la voce Nuovo foglio di lavoro e premere OK, 7) si apre un nuovo foglio di lavoro (Foglio 5), che riporta nella parte destra l’Elenco campi tabella pivot e nella parte sinistra un’anteprima della tabella pivot da costruire: nell’Elenco campi tabella pivot, sotto la dicitura Selezionare i campi da aggiungere al rapporto, cliccare con il tasto sinistro del mouse sulla variabile età: tenendo premuto il tasto sinistro e trascinando il mouse verso il basso, “portare” la variabile età nel riquadro Etichette di riga e rilasciare il tasto sinistro del mouse, ripetere la medesima operazione, trascinando la variabile età nel riquadro Valori, nella parte sinistra del foglio di lavoro, si crea sotto i nostri occhi una tabella pivot, che però non è quella che ci interessa: Excel infatti utilizza di default la funzione somma per riepilogare i dati e questa funzione non è adatta per costruire la distribuzione di frequenza della variabile Età (variabile quantitativa continua), 41 8) per ottenere la distribuzione di frequenza della variabile Età, nella parte inferiore destra del foglio di lavoro cliccare sulla freccia immediatamente a destra della dicitura Somma di età e quindi selezionare Impostazioni campo valore, 9) si apre una finestra di dialogo: selezionare Conteggio e quindi premere OK, 42 10) la tabella pivot cambia e diventa la seguente (cioè la distribuzione di frequenza della variabile Età nel nostro campione di 15 soggetti: nella colonna sinistra sono presentate le modalità assunte dalla variabile Età nel nostro campione e nella colonna destra è specificato il numero di soggetti che presenta quella modalità): 1.9.2 Grafico pivot Per visualizzare la distribuzione di frequenza della variabile Età nel nostro campione di 15 soggetti tramite un grafico pivot, procedere nel seguente modo (continuare ad utilizzare il file su cui abbiamo lavorato finora): 1) portarsi nel foglio di lavoro Foglio 1, 2) sulla barra multifunzione selezionare la scheda Inserisci, quindi cliccare sulla metà inferiore del pulsante Tabella pivot e selezionare Grafico pivot, 43 3) si apre una finestra di dialogo: cliccare sul quadratino indicato dalla freccia nella figura qui sotto (la finestra di dialogo diventerà più piccola), 4) selezionare, sul foglio elettronico, le celle (label + valori) corrispondenti alla variabile di cui si vuole costruire la distribuzione di frequenza: nel nostro caso, selezionare le celle da C1 a C16 inclusa, 5) cliccare nuovamente sul quadratino specificato al punto 3 (la finestra di dialogo tornerà alle dimensioni originali e, vicino alla dicitura Tabella/Intervallo, riporterà l’indicazione delle celle appena selezionate), 6) a questo punto spuntare la voce Nuovo foglio di lavoro e premere OK, 7) si apre un nuovo foglio di lavoro (Foglio 6), che riporta nella parte destra l’Elenco campi tabella pivot e nella parte sinistra un’anteprima della tabella pivot e del grafico pivot da costruire, 44 8) ripetere le medesime operazioni descritte ai punti 7 (il riquadro Etichette di riga qui si chiama Campi asse (categorie)), 8 e 9 della procedura per costruire la distribuzione di frequenza della variabile Età tramite una tabella pivot: questo è il risultato (sull’asse x sono presentate le modalità assunte dalla variabile Età nel nostro campione e sull’asse y è specificato il numero di soggetti che presenta quella modalità), 9) se lo desideriamo, possiamo ovviamente cambiare il titolo del grafico, stabilire i titoli degli assi e fissare il limite massimo (lo poniamo a 2, visto che non ci sono valori più alti) e l’unità principale dell’asse y (la poniamo a 1, perché non ha senso considerare le mezze unità in quanto si tratta di persone). 45 Ecco il risultato finale. 46 1.10 Il salvataggio per l’importazione in R Per poter essere importato e quindi letto dal software R, un foglio elettronico Excel deve essere salvato in formato .csv oppure in formato .txt. 1.10.1 Formato .csv Per salvare un foglio elettronico Excel in formato .csv, procedere nel seguente modo: 1) nella scheda File della barra multifunzione, cliccare su Salva con nome, 2) si apre una finestra di dialogo: nel campo Nome file, digitare il nome che si vuole dare al file (nel nostro caso: Dati) e, nel menu a tendina del campo Salva come, selezionare CSV (delimitato dal separatore di elenco), 47 3) scegliere la directory in cui si vuole salvare il file e cliccare su Salva, 4) nelle due finestre di dialogo che si aprono successivamente, cliccare OK e Sì. 1.10.2 Formato .txt Per salvare un foglio elettronico Excel in formato .txt, procedere come per il salvataggio in formato .csv: l’unica differenza è che, nella finestra di dialogo descritta al punto 2, nel menu a tendina del campo Salva come, bisogna selezionare Testo (con valori delimitati da tabulazioni). 48 2. Utili nozioni di programmazione in R 2.1 Cos'è R e come utilizzarlo R è un software (emulatore FREE di Splus) adatto alla manipolazione di dati, al calcolo e alla visualizzazione grafica; è distribuito gratuitamente in internet all’indirizzo www.r-project.org dove è anche possibile trovare ogni tipo di supporto per l’utilizzo e lo sviluppo. E' un linguaggio orientato alla programmazione ad oggetti: ogni variabile in R è detta oggetto ed è associata ad una determinata classe che ne definisce le proprietà. Per avviare il programma R è sufficiente fare doppio click sull’icona corrispondente o avviare il software dal menu di windows cliccando su “Programmi” (come un qualsiasi altro programma). Lanciando il software appare la commandwindow (o R–console) con un prompt>. Ci sono diversi modi per interagire con R: uno è quello di eseguire le operazioni direttamente dalla R–console digitando, dopo il prompt, un comando seguito dal tasto “Invio”. Ad un primo approccio R potrebbe sembrare una semplice CALCOLATRICE.... 7+4 ...ma come vedremo più avanti non è solo ciò, anzi... In alternativa all’uso diretto della R–console si possono usare gli script: dal menu “File”, scegliendo la voce “Nuovo script”, verrà attivata una nuova finestra con l’aspetto di un file di testo che è possibile salvare e richiamare in una nuova sessione. Gli script hanno un’estensione .R e possono essere aperti da R stesso oppure come un normale documento di testo. Esempio creo un nuovo file script: menu “File” - “Nuovo script” salvo il file sul desktop con nome 'es1': 1) menu “File” - "salva con nome" - 'es1' oppure 2) usare l’icona (floppy) - 'es1' Per eseguire i comandi riportati nello script è sufficiente posizionare il cursore sulla linea di interesse e scegliere la voce “Esegui linea o selezione” dal menu “Modifica”, oppure, in alternativa, usando il tasto F5. 7+4# dopo aver digitato l’operazione premere il tasto F5 49 Quando si vuole uscire dal programma, R chiede se si desidera salvare la R-console (.Rdata) su cui si è lavorato. In caso di risposta affermativa, questa memorizzerà tutti gli oggetti (espressioni, numeri, formule) usati nella sessione di lavoro senza output; inoltre, contestualmente alla R-console (o workspace), verrà salvato anche un file ascii (.Rhistory) che immagazzinerà tutti i comandi digitati nel prompt. Questa operazione consentirà, al riavvio seguente di R, in maniera istantanea, di ricaricare il precedente spazio di lavoro (file .RData) e con esso la storia dei comandi associati (file .RHistory). Il file .RHistory può risultare molto utile per richiamare, con i tasti "freccia su" e "freccia giù", tutti i comandi digitati in una precedente sessione di lavoro. Uscendo da R, quindi, potrebbe essere utile salvare workspace e history con i nomi che si desiderano. Una volta effettuata tale operazione, difatti, a una successiva apertura del programma, selezionando la voce “Carica area di lavoro” dal menu “File” e scegliendo i file .RData e .RHistory opportuni, sarà possibile specificare il workspace su cui si desidera operare. Se non diversamente specificato, R usa la directory di lavoro corrente per salvare automaticamente i dati. Spesso però è opportuno specificare la propria directory di lavoro selezionando la voce “Cambia directory” dal menu “File” e indicando la destinazione opportuna; tale operazione si può anche effettuare digitando i comandi getwd() e setwd(): Per conoscere la directory di lavoro corrente è necessario usare il comando getwd(): getwd() Per cambiarla usare il comando setwd(percorso) (alternativo del “Cambia directory”) setwd("C:\\nome directory") Ogni qualvolta si digita un comando contenente una path("C:\PROVA\...") R richiede di raddoppiare lo slash oppure di cambiarne l'inclinazione (tasto maiuscolo + tasto "7") 2.2 Come installare R e le funzioni di aiuto www.R-project.org 1. Download R→ "scegliere lo stato e il sito da cui fare il download" 2. Download and install R - Windows (95 and later)→base 3. Previous releases → R-2.15.2-win.exe 1. → → 50 2. → 3. → → Per scaricare il manuale - Documentation→Manuals Sul sito www.R-project.org sono disponibili svariate guide di introduzione ad R ed è inoltre possibile consultare i suggerimenti e i consigli presenti nelle FAQ (FrequentAskedQuestions) mentre si sta lavorando. L'istruzione per accedervi è la seguente: help.start() da cui apparirà una pagina web off–line attraverso la quale si accede ai manuali e ad informazioni generali. Inoltre un altro modo semplice per chiedere informazioni consiste nell’anteporre un punto interrogativo al comando di cui si desidera avere maggiori informazioni: 51 ?q help.search("q") Infine per ricercare informazioni su precisi argomenti, in R è implementato un motore di ricerca a cui si può accedere selezionando “search.r-project.org” dal menù “Aiuto” oppure mediante la R-console digitando il comando RSiteSearch("") (inserendo tra virgolette il nome dell’argomento di cui si vuole richiedere informazioni). Tale procedura restituirà una serie di link informativi dei comandi e dei pacchetti che gestiscono la query ricercata. 2.3 Gestione dei pacchetti Il programma R è arricchito da una serie di pacchetti aggiuntivi che ne aumentano notevolmente le potenzialità (Cfr. http://rm.mirror.garr.it/mirrors/CRAN/ → Packages). Sono tre le tipologie di pacchetti utilizzabili: 1) pacchetti già installati e caricati il cui elenco si ottiene con il comando (.packages()); 2) pacchetti già installati ma non ancora caricati: si tratta di pacchetti non immediatamente utilizzabili che è necessario caricare con il comando library(nome pacchetto); library(MASS) # caricamento del pacchetto MASS 3) pacchetti reperibili in rete. I sistemi di installazione di tali pacchetti sono molteplici: se si dispone già del pacchetto desiderato (reperito precedentemente dal web) è sufficiente scegliere dal menu “Pacchetti” la voce “Carica pacchetto”; se invece non si dispone del pacchetto e quindi lo si vuole scaricare online, dal menu “Pacchetti” si scelga “Installa pacchetti” e, dopo aver specificato il server distributore del programma a cui si vuole accedere, si selezioni il pacchetto da installare dalla lista presentata. E’ inoltre possibile visualizzare la lista dei pacchetti già installati digitando il comando library(). E’ possibile anche richiedere informazioni aggiuntive sui singoli pacchetti installati (relativamente alla directory in cui sono collocati sul pc, alle versioni, alle dipendenze che hanno con altri pacchetti ecc.) digitando installed.packages(). Per richiedere informazioni (anche a livello esplorativo) sui comandi dei pacchetti già installati una funzione utile è help.start()1. Questa reindirizzerà alla home-page dell’help di R da cui sarà possibile, cliccando su Packages, accedere alla lista di pacchetti caricati sul proprio PC. A quel 1 Alternativamente selezionare “Guida html” dal menù “Aiuto” 52 punto sarà sufficiente cliccare sul pacchetto desiderato per avere informazioni sui comandi che esso gestisce. 2.4 Nomi e assegnazioni in R I nomi in R possono essere lettere, cifre o punti. Non sono però ammessi nomi che iniziano con una cifra o che iniziano con un punto seguito da una cifra. 8c<-3 .4<-2 R è case-sensitive ovvero distingue tra minuscole e maiuscole. Per creare un oggetto è necessario utilizzare il comando<- o=(oppure anche->) prestando attenzione, nel momento in cui si decide di crearlo, ad eventuali oggetti preesistenti che possiedono lo stesso nome (questi ultimi verranno infatti sovrascritti e quindi cancellati). Inoltre per evitare di creare oggetti con nomi già usati dal default dell’ambiente R, ad esempio q, si suggerisce di consultare l’help. Nei casi di incertezza su una possibile assegnazione si provi a digitare nella R–console il nome che si desidera attribuire alla variabile, controllando che non si tratti di un carattere riservato. x<-3 x y=2 y 45->z z Il comando ls() permette di conoscere cosa è contenuto nel workspace, ovvero gli oggetti presenti nella memoria di lavoro2. Per rimuovere un oggetto si può usare il comando rm() mentre per cancellare tutte le variabili esistenti nell’area di lavoro è necessario usare il comando: rm(list=ls()). ls() In R l’uso del carattere # all’inizio di una riga di programma serve a introdurre un commento: si tratta di una riga di codice che verrà ignorata durante l’esecuzione. I commenti permetteranno di capire il flusso logico del codice agli utilizzatori e, a chi lo ha scritto, di ricordare immediatamente il perché di determinate istruzioni. E’ utile precisare inoltre che in R non è consentito il commento su più linee ovvero viene considerato commento solo la parte della riga di codice che segue il simbolo #. #questo è un commento 2 Un comando analogo è objects() 53 2.5 Operazioni elementari 2.5.1 Operatori aritmetici e relazionali + * / ^ (addizione) (sottrazione) (moltiplicazione) (divisione) (elevamento a potenza) 7 + 3 * 6 x1 <- 7 + 3 * 6 x1 5^2 y1 <- 5^2 ; y1 #il “punto e virgola” permette di scrivere più istruzioni sulla stessa riga 2.5.2 Alcune funzioni notevoli R dispone al suo interno di numerose funzioni per ciascuna delle quali è presente un file di aiuto a cui si può accedere digitando dal prompt "?nomefunzione" oppure "help(nomefunzione)". Quest’ultimo chiarisce tutti gli argomenti richiesti dalla funzione, il loro nome, il loro ordine, quelli necessari e quelli opzionali (ovvero quelli per cui un valore di default è già impostato). ?sum Sotto è presentato un elenco non esaustivo (con esempi) delle funzioni matematiche più utilizzate: sqrt(), sum(), prod(),min(), max(), log(), log10(), exp(),abs(), sign(), round(). sum(3,4) #somma prod(3,4) #prodotto sqrt(81) #radice quadrata "sqrt" z1 <- sqrt(81); z1 #assegnazione di radice quadrata log(1) #logaritmo "log" z2 <- log(5); z2 z3 <- exp(2); z3 #esponenziale exp(1) #numero di Eulero abs(-2) #valore assoluto 54 round(1/3,3) #arrotondamento log(exp(1)) #esempio di funzioni concatenate pi #"pi" in R è una costante predefinita corrispondente al numero π (3.141593) Esercizi Esercizio 1 Calcolare l’area di un cerchio di raggio (r) = 3 cm. (Area di un cerchio = r2) Soluzione: pi*3^2 [1] 28.27433 # Area del cerchio = 28.27433 cm2 Esercizio 2 Risolvere le seguenti espressioni algebriche: Soluzione: 1+2/7)*(-2/3)^2+(2-1/2)^3/(-3/2)-3/4*(-4/7) [1] -1.25 # Risultato: -1.25 Esercizio 3 Soluzione: (2*sqrt(15)-6)/(sqrt(3)-sqrt(2)-sqrt(5)) [1] -0.9101964 # Risultato: -0.9101964 Esercizio 4 Soluzione: log(2*4)-log(2*4-1)-3*log(2)+log(7) [1] 0 # Risultato: 0 55 2.6 Vettori in R In R gli oggetti appartengono a classi. Le classi principali sono cinque: 1) vettori; 2) matrici; 3) data.frame; 4) array; 5) liste. In questa dispensa saranno brevemente presentate solo le prime tre. Due comandi utili a interrogare R per sapere la classe e la struttura di un qualunque oggetto sono class(nome oggetto) e str(nome oggetto). Un vettore è una collezione unidimensionale di elementi alfanumerici. In R un numero viene interpretato come un vettore di dimensione 1×1. La funzione più comune per creare un vettore è c() (che sta per “concatena”). Per individuarne gli elementi è necessario specificare il nome del vettore seguito da un indice (di posizione) delimitato da parentesi quadre. Di seguito alcuni esempi di operazioni con vettori: Vett<-c(-3,8,6); Vett # specificazione di un vettore Vett[1] # estrae l’elemento in posizione 1 Vett[-1] # elimina dal vettore l’elemento in posizione 1 #(l'eliminazione non viene però memorizzata) Vett Vett[1:2] # estrae gli elementi dalla posizione 1 alla 2 Vett[c(1,3)] # estrae gli elementi in posizione 1 e 3 In generale le operazioni sui vettori devono essere inserite in un comando di assegnamento per poter essere memorizzate. Alcune fra le funzioni più utilizzate che vengono applicate ai vettori sono which(), sort() e length(). La funzione which()richiede come argomento un vettore di tipo logico. La funzione sort() ha il compito di ordinare gli elementi del vettore, mentre la funzione length() restituisce la dimensione del vettore. Di seguito alcuni esempi: length(Vett) max(Vett) # restituisce la lunghezza del vettore # restituisce il massimo min(Vett) # restituisce il minimo 56 Vett[which(Vett>0)] condizione # estrae solo gli elementi che soddisfano la which.min(Vett) # restituisce la posizione del minimo which.max(Vett) # restituisce la posizione del massimo sort(Vett) # ordina gli elementi del vettore length(Vett) # restituisce la dimensione del vettore Un operatore molto utile quando si opera con vettori e che serve per generare successioni di valori equidistanti è la funzione seq(a,b,by=i) (by=1 è l’opzione di default). Alcuni esempi: seq(1,10,by=2) seq(1,5,by=1) seq(1,21,by=2) seq(0, 1, length=11) L'opzione length stabilisce, anziché il passo, il numero di elementi che deve contenere la sequenza (si noti comunque che stabilendo a priori il numero degli elementi, si definisce indirettamente il passo della sequenza). Un'altra funzione, rep(), è altrettanto utile per generare sequenze regolari. Ecco 2 esempi: rep(1,6) # ripete il valore 1 per 6 volte Concatenata alla funzione seq(): rep(seq(2,10,by=2),2) # ripete la sequenza (2 4 6 8 10) per 2 volte Per chiarire: c(1,6) c(3,2) rep(c(1,6),c(3,2)) #l'1 viene replicato 3 volte e il 6 per 2 volte rep(c(1,6),each=3) #una variante del comando appena mostrato può essere l'opzione "each" Da notare che per queste ultime due funzioni vi è una corrispondenza di posizione vettoriale di 1 elemento a 1 elemento. Con i vettori è possibile effettuare anche operazioni matematiche (ammissibili). Ad esempio: Vett+3# ad ogni elemento di Vett viene aggiunto 3 Vett*6# ogni elemento di Vett viene moltiplicato per 6 57 Vett+c(1,1)# operazione non ammissibile! (non rispondenza tra le dimensioni) 2.7 Alcune funzioni statistiche Esistono anche svariate funzioni statistiche che possono essere applicate a vettori: mean(c(1,2,3,4,5,6,7,8,9,10)) #media Un vettore di numeri interi consecutivi può essere inserito anche con l’operatore “:” tra gli estremi della successione. 1:10 mean(1:10) median(1:10) #mediana var(1:10) #varianza (campionaria) sd(1:10) #deviazione standard table(1:10) #distribuzione delle frequenze assolute table(1:10)/length(1:10) #distribuzione delle frequenze relative mean(Vett) median(Vett) sd(Vett) var(Vett) var(Vett)*(length(Vett)-1)/length(Vett) # varianza della popolazione Vett2<-c(0,3,3) #dichiaro il vettore “Vett2” cov(Vett, Vett2) # covarianza dei vettori “Vett” e “Vett2” cor(Vett, Vett2) #correlazionedei vettori “Vett” e “Vett2” 2.8 Il ciclo for Il ciclo for() permette di eseguire una determinata operazione, oppure una serie di istruzioni, per un numero prefissato di volte. Vi si accede con for (variabile in vettore) { istruzioni }. 58 Esempio: si utilizzi il ciclo for() per definire la somma dei primi 10 numeri naturali. somma<-0 for (i in 1:10){ #la "i" serve unicamente come puntatore (temporaneo) per passare tutti gli oggetti,uno alla volta, specificati dopo l'"in" somma<-somma+i } somma Altro esempio: riempimento vettore num<-NULL #inizializzo un vettore con zero elementi (vuoto) for (i in 1:10){ num<-c(num, i) } num Alternativamente: num<-0 #inizializzo un vettore con zero elementi (vuoto) for (i in 1:10){ num[i]<-i } num 2.9 Matrici in R Per creare una matrice si usa il comando matrix(); è necessario specificare nrow e/o ncol per determinare le dimensioni della matrice e la modalità di riempimento (per riga byrow=T, per colonna, l’opzione di default, byrow=F). La gestione di una matrice è simile a quella vista per i vettori: ogni elemento di una matrice è univocamente determinato da due indici, il primo indica la posizione di riga e il secondo si riferisce alla colonna. Le funzioni cbind() e rbind() vengono usate per aggiungere rispettivamente colonne e righe ad una matrice. Alcuni esempi: A<-matrix(c(1,4,6,8,-1,-4,0,6,0),nrow=3,ncol=3,byrow=T); A Vett<-c(-3,8,6); Vett Amod<-cbind(A,Vett) # aggiunge una colonna ad A Amod Amod<-rbind(A,Vett); Amod # aggiunge una riga ad A A[1,1] # estrae l’elemento in posizione (1,1) ovvero prima colonna, prima riga 59 A[1,2] # estrae l’elemento in posizione (1,2) A[1,] # estrae la prima riga A[,1] # estrae la prima colonna A[1:2,]# estrae le righe dalla 1 alla 2 A[c(1,3),] # estrae le righe 1 e 3 dim(A) # dimensioni della matrice dim(A)[1] # numero di righe della matrice dim(A)[2] # numero di colonne della matrice diag(3)# matrice identità di ordine 3x3 diag(A)# elementi della diagonale principale t(A) # trasposta di A A*A # prodotto elemento per elemento delle due matrici A%*%A # prodotto scalare 2.10 I data.frame in R I data.frame sono gli oggetti che più si utilizzano nell’analisi statistica dei dati; sono simili alle matrici ma con colonne che possono contenere dati di tipo diverso: in un data.frame è possibile rappresentare contestualmente variabili numeriche e variabili alfanumeriche, cosa che non è possibile fare in una matrice. Definisco tre vettori di uguale lunghezza: eta<-c(44, 49, 52, 62, 53, 58, 56, 59, 53, 50, 64, 58, 42, 58, 63) sesso<-c("f","m","m","m","m","f","f","m","m","m","m","m","m","m","f") status<-c(1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0) # La variabile status indica la condizione di salute del soggetto: 0 indica i sani e 1 indica i malati Per creare un data.frame si usa il comando data.frame()inserendo nelle parentesi i nomi delle variabili (vettori) di uguale lunghezza che si vuole siano contenute nel data.frame stesso. prova<-data.frame(eta,sesso,status) head(prova) #visualizzo un estratto del data.frame appena creato Ora rimuovo i tre vettori e lavoro direttamente con il data.frame appena creato (che comunque contiene le variabili). rm(eta); rm(sesso); rm(status) 60 La gestione di tale oggetto è simile a quella vista per le matrici. Ogni elemento di un data.frame è univocamente determinato da due indici: il primo indica la posizione di riga e il secondo si riferisce alla colonna. Le funzioni cbind() e rbind()vengono usate per aggiungere rispettivamente colonne e righe: aggiunta<-c(33, "m",0) prova1<-rbind(prova, aggiunta); prova1 Inoltre vi sono differenti modi per estrarre parti di data.frame su cui si ha interesse lavorare. Un modo, analogamente a quanto visto per le matrici, è quello di operare con gli indici di riga e di colonna. dati.sub1<- prova[, c(1, 3)]; dati.sub1 # Selezione di colonne mediante indici dati.sub2<- prova[3:6, c(1,3)]; dati.sub2 # Selezione di un estratto di righe e colonne mediante indici (1a e 3a riga delle colonne) Per eliminare colonne e righe da un data.frame è sufficiente anteporre agli indici il segno “-”: dati.sub3<- prova[,-c(1,3)]; dati.sub3 dati.sub4<- prova[-c(7,11),]; dati.sub4 Altri possibili modi sono quelli di utilizzare l’operatore == oppure il comando subset(), che selezionano righe o colonne con condizioni logiche. Di seguito alcuni esempi. Selezione di righe prova[prova$sesso == "m",] # seleziono la parte di dataset relativa ai maschi oppure dati.sub5<- subset(prova, prova$sesso == "m"); dati.sub5# seleziono la parte di dataset relativa ai maschi Il carattere dedicato $, specificato tra il nome del data.frame e quello della variabile, consente di estrarre le variabili (vettori) dal data.frame considerato. prova$sesso # variabile sesso del data.frame “prova” Selezione di righe con condizione multipla: prova[prova$sesso == "m" & prova$status ==0,] # seleziono la parte di dataset relativa ai maschi sani 61 alternativamente: dati.sub6<- subset(prova, prova$sesso == "m" & prova$status ==0); dati.sub6# seleziono la parte di dataset relativa ai maschi sani Selezione contestuale di un estratto di righe e di intere colonne: dati.sub7 <- subset(prova, prova$sesso =="m" &prova$status == 1, select = c(eta, status)); dati.sub7 Selezione di riga con condizione multipla mediante indici: dati.sub8 <- prova[prova$eta %in% c(53, 64), ]; dati.sub8 Selezione di righe che contengono un valore predeterminato: row_sub = apply(prova, 1, function(row) any(row ==59 )) prova[row_sub,] Selezione di colonne che contengono un valore predeterminato: col_sub = apply(prova, 2, function(col) any(col ==59 )) prova[,col_sub] 2.11 Procedure di importazione ed esportazione dei dati L'importazione di dati, generati da programmi esterni ad R, può avvenire in diversi modi. Le funzioni dedicate a tale scopo sono diverse:read.table(), read.csv(), read.csv2(), read.delim(), read.delim2(), scan() sono solo alcune di esse per le quali si consiglia di consultare l’help del programma. Idati (o matrice di dati) importati in ambiente R assumono classe data.frame. Tra tutte, la funzione read.table consente di importare i dati (formato tabella) contenuti in un file di testo(.txt) in maniera più semplice: Per importare dei dataset esterni, esiste l'opzione universale file.choose() da inserire all'interno del comando di importazione relativo al tipo di dataset che si intende importare: tale l'opzione permette di scegliere il file da importare direttamente con il mouse senza dover digitare (e quindi ricordarsi) l'esatto nome (questo rende l'importazione interattiva). Per identificare il dataset importato è sempre consigliato assegnargli un nome (nella fattispecie dati): dati<-read.table(file.choose(), header= TRUE, dec=",", sep= "") # importazione del file "esempio.txt" dati; class(dati) #visualizzo dati e ne verifico la classe 62 Per visualizzare le variabili (solitamente identificate dalle colonne di una matrice di dati) del dataset importato è difatti necessario assegnare un nome all'importazione e successivamente utilizzare il comando del tipo ""nome assegnazione dataset importato in R"[,i]" (dove i è il numero della colonna). dati[,4] #visualizzo colonna 4 del data.frame "dati" L'opzione header, se TRUE (il default è FALSE), indica che la prima riga del file contiene i nomi delle variabili. L’opzione sep comunica a R il carattere separatore (delle colonne) nel file di origine (in questo caso “uno spazio”). L’opzione dec comunica al software il tipo di separatore decimale utilizzato nel file di origine. Vi è poi l'utilissima opzione na.strings che serve per far identificare da R i valori mancanti. A tale proposito si ricorda che a destra dell'uguale, tra virgolette, si inserisce il carattere che identifica il valore mancante nel set di dati originario: chiaramente tale carattere deve essere conosciuto a priori e comune per tutti i missing. L’utilizzo di quest’ultima opzione è apprezzabile con l’esempio seguente: passo 1a: importazione del file “esempio con missing.txt” (senza l'opzione na.strings) dati_M<-read.table(file.choose(), sep= "", dec=",", header= TRUE) passo 2a: calcolo della media di una variabile del dataset importato (colonna 4) in cui compare un valore mancante NON considerato tale da R. L’opzione na.rm=TRUE comunica a R di operare (nella fattispecie di fare la media) rimuovendo i valori mancanti. mean(dati_M[,4], na.rm = TRUE) #L’output è NA (NotAvailable) e inoltre viene visualizzato un messaggio di warning poiché i valori mancanti non sono considerati tali. passo 1b: importazione del file “esempio con missing.txt” (con l'opzione na.strings), i valori mancanti sono codificati da "." dati_C<-read.table(file.choose(), sep= "", header= TRUE, dec=",", na.strings=".") passo 2b: calcolo della media di una variabile del dataset importato (colonna 4 in cui compare un valore mancante considerato tale da R. L’opzione na.rm=TRUE comunica a R di operare (nella fattispecie di fare la media) rimuovendo i valori mancanti. head(dati_C) mean(dati_C[,4], na.rm = TRUE) #calcola la media sui valori validi effettivi considerando i valori mancanti come tali!!!! Per importare i dati da un fileExcel(.xls)è invece necessario: 1) salvare il file Excel con l’estensione ".csv" (dal menu a tendina relativo all’estensione del file); 2) chiudere il file .csv e importarlo in ambiente R con read.csv2 63 # esempio per l’importazione del file "esempio con missing.csv" considerando i valori mancanti identificati dalla stringa "." dati_csv<-read.csv2(file.choose(), header= TRUE, sep= ";", dec=",", na.strings=".") head(dati_csv) Per visualizzare la tipologia di carattere separatore utilizzato si consiglia di aprire, prima dell’operazione di importazione, il file origine (in questo caso “.csv”) con il "blocco note" (nella fattispecie il “;” comanda la struttura di separazione). Per le esportazioni di oggetti da R ad altri programmi le operazioni sono simili. Per esempio, per esportare un oggetto R in un file .txt si può utilizzare la funzione: write.table(nomeoggetto,"nomefileditesto.txt") Una specificazione di tale comando potrebbe essere quella di scrivere una matrice o un data.frame in un file di testo (formato tabella). Un esempio di ciò è il seguente: write.table(dati_csv,"esempio esportato.txt", sep=" ", row.names=F, col.names=T) Nella directory in cui si sta lavorando comparirà il nuovo file appena esportato “esempio esportato.txt”. getwd() # per visualizzare la directory di lavoro Con le opzioni row.names e col.names si specifica (in modo logico: TRUE o FALSE) se le righe e/o le colonne devono possedere le intestazioni. Per esportare un file in Excel è consigliabile passare prima dall'estensione .csv write.table(dati,"esempio esportato in EXCEL.csv", sep=";", dec=",", row.names=F, col.names=T) 2.11.1 I comandi header, colnames(), $ e attach() In fase di importazione, a prescindere dal file importato, l’opzione header=TRUE permette di utilizzare i nomi delle variabili del dataset originario (ottenibili dal comando colnames()). Questa operazione è consentita attraverso il carattere $ o alternativamente con il comando attach(). DATI<-read.table(file.choose(), sep= "", header= TRUE, dec=".", na.strings=".") #importo il file “stroke in young.txt” colnames(DATI) DATI$age 64 attach(DATI) age #visualizza la variabile "age" Una volta che si è assegnato il nome alla colonna (variabile) è possibile effettuare qualsivoglia operazione utilizzando tale nome. mean(age) #media di tutti gli elementi della variabile “age” var(age) #varianza campionaria di tutti gli elementi della variabile “age” 2.11.2 Cenni di riordino dei dati A volte è possibile che il dataset di origine non si presenti con il format consigliato per R ovvero di tipo “matrice di dati” (righe=soggetti variabili=colonne). In questi casi per rendere il dataset maggiormente fruibile dal software è necessario riordinarlo con il programma che ha generato quei dati. Di seguito un esempio con un file di dati excel (.csv). In excel, aprire il file “esempio format non matrice di dati.csv”. Come si può notare il dataset è suddiviso per gruppi (sesso); tuttavia per facilitare le analisi statistiche con R converrebbe avere un soggetto per ogni riga e quindi predisporre una “matrice di dati” pronta per l’importazione appunto in R. In questo caso è quindi auspicabile creare una variabile sesso che, per ogni soggetto, mi discrimini il genere di appartenenza. Quindi, operativamente, si sposteranno i dati del gruppo dei maschi (senza l’intestazione) immediatamente sotto i dati relativi alle femmine, in modo da incolonnarli; poi si cancellerà l’intestazione per il gruppo maschi, si dovrà creare la nuova variabile sesso3, che si riempirà con f o m, e infine si importerà il dataset in R con la procedura sopra descritta. dati_mod<-read.csv2(file.choose(), header= TRUE, sep= ";", dec=",") #importo il file “esempio format non matrice dati.csv” e gli assegno il nome "dati_mod" head(dati_mod) Come si può notare il format dei dati importati in R è di tipo “matrice dei dati” e quindi più facilmente analizzabile in R. colnames(dati_mod) attach(dati_mod) mean(Peso..kg.[sesso=="m"]) #peso dei maschi Tale procedura di riordino dei dati è possibile (e forse preferibile) anche in R. Di seguito le istruzioni. 3 Da notare che l’inserimento della variabile sesso è naturalmente consentito anche in R (dopo l’importazione) 65 dati_mod_R<-read.csv2(file.choose(), header= TRUE, sep= ";", dec=",") #importo il file “esempio format non matrice dati_R.csv” e gli assegno il nome "dati_mod_R" Visualizzo il dataset importato e verifico che il format non è “matrice di dati” dati_mod_R dim(dati_mod_R) # verifico le dimensioni del data.frame Ora seleziono i dati validi del gruppo dei maschi ovvero l’intersezione tra le prime quattro righe e le colonne a dalla 5 alla 7: dati.maschi<- dati_mod_R[1:4,5:7]; dati.maschi Omologo le intestazioni dei due data.frame che voglio aggregare (operazione necessaria per incolonnare due data.frame): colnames(dati.maschi)=colnames(dati_mod_R[1:11,1:3]) Aggrego i dati maschili sotto ai dati femminili (selezionati): dati_generale<- rbind(dati_mod_R[1:11,1:3], dati.maschi); dati_generale E infine aggiungo il vettore relativo al genere: dati_finale<-cbind(dati_generale, c(rep("f",11), rep("m",4))) e associo al data.frame un’intestazione più coerente: colnames(dati_finale)=c("soggetti", "colesterolo", "peso", "sesso") Visualizzo quindi il data.frame finale pronto per l’analisi statistica dati_finale attach(dati_finale) mean(peso[sesso=="m"]) #peso dei maschi 66 2.12 Come creare nuove funzioni in R Oltre alle funzioni notevoli (o dedicate) in R è anche possibile creare delle nuove funzioni tramite il comando function(): gli argomenti (arg) di tali funzioni, separati da virgole, vengono dichiarati nelle parentesi tonde, mentre il corpo è generalmente incluso tra parentesi graffe; queste ultime possono essere omesse se il corpo è costituito da operazioni scritte su un’unica riga dopo function(). Generalmente il risultato della funzione è l’ultimo elemento calcolato. Lo schema generale per la definizione e l’applicazione di una nuova funzione è il seguente: 1) Definizione nome_funzione<- function(arg1,arg2,...) { #corpo della funzione operazione1 operazione2 operazione3 #valore restituito dalla funzione operazione4 } 2) Applicazione nome_funzione(arg1, arg2, ...) Il nome_funzione può essere un qualsiasi nome contenente caratteri alfanumerici (compreso il “.”).Se già esiste una funzione con lo stesso nome quest’ultima verrà sostituita dalla nuova funzione definita. Gli argomenti che vengono forniti alla funzione possono essere obbligatori od opzionali. Ad es., function(x)definisce come singolo argomento obbligatorio x. Se si vuole renderlo opzionale si deve assegnare un valoreall’argomento, ad es. function(x=0). A livello di definizione della funzione non viene effettuato alcun controllo di ammissibilità. Ad esempio, se definisco una funzione che calcola la somma di due valori Somma<- function(a=0, b) a+b mi aspetterò che sia a che b siano valori numerici. Tuttavia, se richiamo Somma come Somma(1,"pippo") si verificherà un errore nel momento di effettuare l’operazione di somma. Se inveceagli argomenti assegno i valori 1 e 2, Somma(1,2) fornirà la risposta corretta,cioè 3. Essendo l’argomento a opzionale, potrei voler richiamare la funzione specificando solo il secondo argomento Somma(b=2) che restituirà il valore 2 (0+2). Infine, una funzione può anche non contenere argomenti o prevedere per ciascuno un valore di default; in questo caso potrà essere richiamata semplicemente digitando nome_funzione(). Il corpo della funzione contiene tutte le operazioni (comandi) in R che definiscono ciò che la funzione effettivamente esegue. Gli argomenti e le variabili che sono create all’interno della funzione sono variabili locali, nel senso che al termine della funzione il loro valore non viene mantenuto. Nell’esecuzione dei comandi all’interno della funzione le variabili locali hanno precedenza sulle variabili globali definite a livello di R-console; chiaramente tutte le variabili non definite localmente devono essere definite a livello di R-console altrimenti si produrrà un errore (vedi esempio seguente). 67 Definizione della nuova funzione “Es.fun”: Es.fun<- function(a=0) # definisco una nuova funzione che contempla il solo argomento opzionale #“a” { # “b” è invece una variabile utilizzata solo nel corpo della funzione a+b } Applicazione di “Es.fun”: Es.fun() # da notare che b non è definita né localmente né globalmente In questo caso, siccome b non è definita né localmente né globalmente, R restituisce un messaggio di errore: Error in Es.fun() : Object "b" not found Se però la definisco globalmente nella R-console (fuori dalla funzione): b <- 2 la funzione non va in errore: Es.fun() #(=2) Il valore restituito dalla funzione è il risultato dell’ultima operazione valutata. E’ possibile specificare esplicitamente cosa una funzione debba restituire attraverso i comandi return(): ad es. return(x) restituisce il contenuto dell’oggetto x. Tuttavia per default una funzione restituisce il risultato dell’ultima operazione. Inoltre un comando che spesso è utile per stampare a video i risultati è cat(). Scrivere delle funzioni è il modo più semplice in R per memorizzare una serie di comandi. Scritta una funzione si può utilizzare il comando edit(nome funzione) per richiamare un editore di testo, solitamente il Blocco Note, che visualizza il corpo della funzione. In una successiva sessione di lavoro le funzioni create possono essere richiamate utilizzando il comando source(nome file), oppure utilizzando la voce “Sorgente codice R…” dal menu “File”. Per conoscere gli argomenti di una funzione sono disponibili le funzioni args(nome funzione), attributes(nome funzione) e body(nome funzione). Di seguito un esempio di creazione di funzione. Calcolo di una media ponderata: Definizione: media.ponderata<- function(x, peso) { mp<-sum(x*peso)/sum(peso) cat("la media ponderata è ", mp,"\n") } 68 Applicazione della funzione media.ponderata: media-voto di 5 esami (ponderata per i crediti formativi universitari attribuiti a ogni esame). voti <- c(23, 26, 30, 27, 21) # inserisco i voti dei 5 esami cfu<- c(10, 2, 8, 6, 6) # inserisco i crediti dei 5 esami (l’ordine d’inserimento dà la corrispondenza con i singoli voti) media.ponderata(voti, cfu) #(=25.3125) Prima di passare al paragrafo successivo elimino tutti gli oggetti finora creati: rm(list=ls()) 2.13 Elementi di analisi esplorativa e nozioni elementari sulla gestione dei grafici In un generico dataset (matrice di dati) ogni riga rappresenta un’unità statistica e ogni colonna rappresenta una variabile rilevata sull’unità. dati<-read.table(file.choose(), sep= "", header= TRUE, dec=".", na.strings=".") #importo il file “stroke in young.txt” colnames(dati) # visualizzo i nomi delle colonne del dataset importato dim(dati) # visualizzo la dimensione del dataset importato fix(dati) # visualizzo i dati con un editor di R "user-friendly" attach(dati) # comunico al software che intendo lavorare con il nome delle variabili del dataset originario A seconda della natura delle variabili oggetto di studio, si utilizzano strumenti diversi per l’analisi statistica. I dati si dividono in due gruppi principali: qualitativi e quantitativi. I qualitativi sono così chiamati poiché le variabili da cui derivano possono essere descritte attraverso attributi (come ad esempio il genere, il tipo di trattamento, ecc.), eventualmente posti tra loro in relazione d’ordine (ad esempio il livello del titolo di studio, ecc.). Le variabili qualitative sono dunque rilevate su scala nominale e ordinale, rispettivamente. I dati numerici importati in R vengono di default letti come variabili quantitative; se però il ricercatore sa che tali dati corrispondono a fenomeni qualitativi,è necessario specificare l’attributo factor (oppure ordered nel caso di modalità ordinali). apoe # variabile numerica Apoe<-factor(apoe); Apoe # variabile qualitativa nominale Apoe.ord<-ordered(apoe); Apoe.ord # variabile qualitativa ordinale Anche per le variabili quantitative, benché a livello di programmazione non cambi molto, si possono distinguere due sotto-tipologie: quelle discrete e quelle continue. In generale si hanno 69 variabili quantitative discrete quando le caratteristiche sono rilevate attraverso operazioni di conteggio (come ad esempio il numero di figli per coppia, il numero di guasti, ecc.). Si attribuisce invece natura continua a quelle variabili che attengono a misurazioni di grandezze fisiche (ad esempio lunghezza, temperatura, tempo,ecc.). La prima fase di ogni analisi statistica consiste nell’organizzazione e sintesi delle osservazioni, prima di utilizzarle nell’analisi. Opportune rappresentazioni tabellari e grafiche dei dati sono strumenti essenziali nell’elaborazione dell’informazione. In questo paragrafo vengono introdotti alcuni comandi che permettono di estrarre da un set di dati informazioni di riepilogo sulla base della natura qualitativa o quantitativa delle variabili. Vengono poi presentati alcuni metodi grafici con cui è possibile ispezionare le caratteristiche del campione in esame. In primo luogo, soprattutto per variabili qualitative (es. Apoe) o quantitative discrete (es. apoe), un utile strumento per avere una panoramica iniziale è la tabella delle frequenza assolute (o relative): il comando per ottenere ciò è table. table(apoe) #distribuzione delle frequenze assolute Per estrarre la frequenza di una specifica modalità, l’operatore di selezione (interno al comando table) è il medesimo di prima (==). table(apoe[apoe==2]) Un commando alternativo, applicabile a variabili qualitative e che gestisce anche i valori mancanti, è summary: summary(Apoe) # si ricordi che Apoe (con A maiuscola) è nominale summary è un comando molto importante anche per visualizzare le principali statistiche di sintesi e riepilogare le informazioni contenute in una variabile quantitativa continua. summary(age) Per ottenere la distribuzione delle frequenze relative è sufficiente dividere per la numerosità campionaria. table(apoe)/length(apoe) oppure table(apoe)/sum(table(apoe)) Mentre per la distribuzione cumulate il commando è cumsum cumsum(table(apoe)) # frequenze assolute cumulate cumsum(table(apoe))/length(apoe) # frequenze relative cumulate Se poi per una variabile quantitativa volessi ottenere una distribuzione di frequenza più sintetica sarebbe opportuno dividere i dati in classi. Per esempio, la variabile age potrei raggrupparla così: 70 classi = c(10, 20, 30, 40, 50, 60) classi assegnando, con il comando cut, ciascuna età della variabile alla sua classe di appartenenza: age.per.classi=cut(age, breaks = classi); age.per.classi e creando infine la tabella di frequenza: table(age.per.classi) # frequenze assolute table(age.per.classi) / sum(table(age.per.classi)) # frequenze relative Se poi volessi lasciare ad R l’onere di costruire le classi, c’è la possibilità di scegliere solo il numero di classi in cui vogliamo suddividere il nostro insieme di dati: age.per.classi.R=cut(age, breaks = 5); age.per.classi.R table(age.per.classi.R) In questo caso abbiamo semplicemente una suddivisione in 5 intervalli del campo di variazione dei dati. Il comando table è anche utile per creare tavole di contingenza per 2 variabili: l’esempio che segue è illuminante: A <- factor(c(0,0,0,0,1,1,2,2,2,2,2,2,2)) B <- factor(c(0,1,0,0,1,1,1,1,0,0,1,1,1)) table(B, A) #la prima variabile si colloca per riga, la seconda per colonna Benché le distribuzioni di frequenza siano strumenti esaurienti dal punto di vista dell’informazione che contengono, spesso è molto meglio darne anche una rappresentazione grafica. Il sistema grafico di R si sviluppa su due insiemi di funzioni di base: le funzioni di alto livello creano le vere e proprie immagini complete (ovvero la parte corposa del grafico); le funzioni di basso livello (od opzioni) consentono invece di manipolare un grafico esistente aggiungendo o raffinando particolari elementi. Di seguito un elenco non esaustivo di funzioni di alto livello, contemplanti le rilevazioni contenute nei vettori x e y (sotto dichiarati), utile alla realizzazione di differenti tipi di grafici. x<-c(1,2,3,4,5,6,7,8,9,10,11,12,13) y<-c(5,4,3,2,8,2,4,6,8,10,0,3,-4) hist(y) # fornisce l’istogramma sulla base delle frequenze del vettore y 71 plot(x,y) #fornisce il grafico a dispersione di x e y barplot(x) # fornisce un grafico a barre del vettore x (1 barra per ogni elemento del vettore) 72 pie(table(y)) #fornisce un grafico a torta del vettore x boxplot(y) # fornisce il boxplot4 del vettore y install.packages("vioplot"); require(vioplot) #installo e carico il pacchetto "violplot" vioplot(y, names="") # fornisce il violin-plot del vettore y 4 I pallini rappresentati sono gli outlier (valori estremi o anomali) che distano dal primo quartile (in senso decrescente) e dal terzo (in senso crescente) di più di ‘1,5 × range interquartile dei dati’ (il range interquartile è la differenza tra il terzo e il primo quartile). 73 par(mfrow=c(1,2)) finestra # permette di visualizzare più grafici5in un’unica boxplot(x, xlab= "box plot"); vioplot(x, names="violin plot") # grafici appaiati6 dal comando "par(mfrow=c(…,…))" Quando due variabili inserite nel comando plot sono rispettivamente nominale e quantitativa, R restituisce un’unica finestra grafica i boxplots della seconda per ogni modalità della prima. plot(B,x) 5 6 A seconda dei numeri inseriti nel vettore: c(numero di righe, numero di colonne). Nella fattispecie due grafici disposti su una riga e due colonne. 74 Per il violin plot non esiste questa possibilità e di conseguenza bisogna operare con le condizioni logiche: vioplot(x[B==0],x[B==1], names=c("0","1")) dev.off() # chiudo la finestra grafico (alternativo alla "x" in alto a destra) 75 Di seguito un elenco, sempre non esaustivo, di funzioni di basso livello: main : assegna un titolo al grafico. Esempio: plot(x,y,main="titolo del grafico") sub : assegna un sottotitolo al grafico. Esempio: plot(x, y, sub="sottotitolo del grafico") 76 xlab:assegna un nome all’asse delle ascisse. ylab: assegna un nome all’asse delle ordinate. Esempio: plot(x,y, xlab="ascisse", ylab="ordinate") xlim=c(a, b) : delimita l’asse delle ascisse tra il valore a e il valore b ylim=c(c, d) : delimita l’asse delle ordinate tra il valore c e il valore d. Esempio: plot(x,y,xlim=c(0, 5), ylim=c(0, 8)) 77 type : indica il tipo di grafico (a dispersione) che viene rappresentato. Esempio: plot(x[1:6],y[1:6],type="o") # grafico (a dispersione) per segmenti lty: tipo di linea che viene disegnata. Esempio: plot(x[1:4],y[1:4],type="o",lty=3) 78 lwd: larghezza della linea che viene disegnata. Esempio: plot(x[1:4],y[1:4],type="o",lty=3, lwd=3) labels=T: visualizza la frequenza di ciascuna colonna. Esempio: hist(x, labels=T) # fornisce l’istogramma sulla base delle frequenze del vettore x C’è poi anche la possibilità di specificare una legenda informativa nel riquadro grafico: il comando legend e l’opzione locator(1) rendono questa operazione interattiva. plot(x,y, xlab="ascisse", ylab="ordinate") legend(locator(1), "unità statistica", pch=1) 79 plot(x,y, xlab="ascisse", ylab="ordinate") legend(locator(1),c("maschi","femmine"),pch=c(1,1)) legend(locator(1),c("maschi","femmine"),pch=c(1,1),col=c(2,3)) Per ulteriori informazioni si rimanda all'help di R: ?plot ?plot.default(graphics) 80 La seguenti tabelle schematizzano alcune rappresentazioni grafiche unidimensionali e bidimensionali a seconda del tipo di variabile. variabile qualitativa (factor o ordered) Grafico a barre plot(x) Diagramma a bastoncini plot(table(x)) Areogramma a settori circolari (torta) pie(table(x)) x\y→ ↓ variabile qualitativa (factor o ordered) variabile quantitativa variabile quantitativa discreta Grafico a barre barplot(x) Diagramma a bastoncini plot(table(x)) Areogramma a settori circolari (torta) pie(table(x)) variabile quantitativa continua Istogramma hist(x) Scatter plot plot(x) Boxplot boxplot(x) variabile qualitativa variabile quantitativa (factor o ordered) Areogramma a colonne Boxplots di y per i livelli di x plot(x,y) sovrapposte plot(x,y) Boxplots di x per i livelli di y Scatter plot plot(x,y) plot(x,y) 2.14 La ricodifica di variabili in R In ambiente R esistono numerosi metodi (anche personalizzabili) di ricodifica delle modalità; di seguito ne vengono presentati tre fra i più usati. 1°metodo – Ricodifica dicotomica In questo primo metodo viene attuata una binarizzazione con operatori relazionali quali<, > o ==. Tale operazione restituisce degli output logici di TRUE o FALSE a seconda che la condizione specificata tra parentesi sia rispettata o meno. Tali output saranno quindi moltiplicati(*) per 1 per essere trasformati numericamente in 1 o 0 e quindi più facilmente analizzabili. Di seguito qualche esemplificazione. gii<-1*(ii>1); gii gapoe<-1*(apoe>3); gapoe 2° metodo – Ricodifica mediante l’uso dell’operatore relazionale == (uguale) Importo il dataset: dati<-read.table("datiSNPs.csv", sep= ";", header= TRUE, na.strings="NA") head(dati) colnames(dati) attach(dati) 81 Ricodifico i primi tre SNPs del dataset seguendo lo schema sotto riportato: Variabile Modalità origine rs2808630 0 rs2808630 1 rs2808630 2 → Modalità destinazione CC → CT → TT → rs2516839 rs2516839 rs2516839 0 1 2 → → → CC CT TT rs7575840 rs7575840 rs7575840 0 1 2 → → → GG GT TT dati.3SNPs<-subset(dati, select=c(rs2808630, rs2516839, rs7575840)) #estraggo gli SNPs di interesse daldataset importato head(dati.3SNPs); table(dati.3SNPs) #verifico che le modalità origine siano quelle specificate (ovvero 0, 1, 2) dati.3SNPs; dim(dati.3SNPs) #visualizzo dati.3SNPs e ne verifico le dimensioni Ricodifico gli SNPs di dati.3SNPs: nella fattispecie devo passare da variabili categoriche di tipo numerico (int) a variabili categoriche di tipo stringa (motivo per cui devo bordare di apici le nuove modalità): str(dati.3SNPs) #verifico il formato delle variabili La procedura è la seguente: con la stringa dati.3SNPs[,1] comunico al software di operare sulla prima colonna del data frame dati.3SNPs; la stringa [dati.3SNPs[,1]==0] indica a R la condizione logica che deve applicare per la ricodifica (nella fattispecie considera le osservazioni che hanno la variabile rs2808630, alias dati.3SNPs[,1], pari a 0). Infine con l’assegnazione (<-'C/C') segnalo il nuovo valore alfanumerico che dovrà assumere la modalità origine. Infine ripeto le medesime istruzioni (mutatismutandis) per le altre modalità e per le altre variabili. dati.3SNPs[,1][dati.3SNPs[,1]==0]<-'C/C' dati.3SNPs[,1][dati.3SNPs[,1]==1]<-'C/T' dati.3SNPs[,1][dati.3SNPs[,1]==2]<-'T/T' dati.3SNPs[,2][dati.3SNPs[,2]==0]<-'C/C' dati.3SNPs[,2][dati.3SNPs[,2]==1]<-'C/T' dati.3SNPs[,2][dati.3SNPs[,2]==2]<-'T/T' dati.3SNPs[,3][dati.3SNPs[,3]==0]<-'G/G' dati.3SNPs[,3][dati.3SNPs[,3]==1]<-'G/T' dati.3SNPs[,3][dati.3SNPs[,3]==2]<-'T/T' head(dati.3SNPs) #visualizzo un estratto del dataset ricodificato 82 Un modo più efficiente di gestire questo tipo di ricodifica è quello di implementarla in una funzione adhoc; l’esempio che segue, utile per ricodificare SNPs con modalità identiche, è illuminante: dati.4SNPs<-subset(dati, select=c(rs780094,rs10510293,rs864265, rs12654264)); #estraggo gli SNPs di interesse (che hanno modalità uguali) head(dati.4SNPs); table(dati.4SNPs) #verifico che le modalità origine siano quelle specificate (ovvero 0, 1, 2) Definisco la nuova funzione recode.snp: recode.snp<-function(dataset,mod.origine,mod.dest){ dataset<-as.matrix(dataset) for (i in 1:dim(dataset)[2]){ for (j in 1:length(mod.origine)){ dataset[,i][dataset[,i]==mod.origine[j]]=mod.dest[j] } } return(as.data.frame(dataset)) } Applico recode.snp e le assegno il nome del dataset che voglio ricodificare: si ricordi che l’ultima operazione della funzione è return(as.data.frame(dataset)) e quindi l’output è proprio un data.frame ricodificato. dati.4SNPs<-recode.snp(dati.4SNPs,c(0,1,2),c('C/C','C/T','T/T')) head(dati.4SNPs) #visualizzo un estratto del dataset ricodificato 3° metodo – Il comando recode del pacchetto epicalc Per utilizzare questa procedura è necessario che la variabile ricodificata rispetti il formato della variabile origine (es. character → character, integer → integer, ecc.). Importo il dataset: datiSNP<-read.table("datiSNPs.csv", sep= ";", header= TRUE, na.strings="NA") install.packages("epicalc") #installo il pacchetto epicalc library(epicalc) #carico il pacchetto epicalc colnames(datiSNP) head(datiSNP); dim(datiSNP) 83 Ora ricodifico gli SNPs del dataset secondo il seguente schema: Variabile Modalità origine 0; 1; 2 rs2808630 “ rs2516839 “ rs7575840 “ rs1260326 “ rs780094 “ rs10510293 “ rs864265 “ rs12654264 “ rs5370 “ rs328 “ rs3890182 “ rs875434 “ rs3135506 “ rs662799 “ rs1507203 “ rs1800588 “ rs1800775 “ rs7231460 “ rs1529729 “ rs688 “ rs4420638 “ rs10500295 → Modalità destinazione C/C; C/T; T/T → C/C; C/T; T/T → G/G; G/T; T/T → C/C; C/T; T/T → C/C; C/T; T/T → C/C; C/T; T/T → G/G; G/T; T/T → A/A; A/T; T/T → G/G; G/T; T/T → C/C; C/G; G/G → A/A; A/G; G/G → C/C; C/T; T/T → C/C; C/G; G/G → A/A; A/G; G/G → C/C; C/T; T/T → C/C; C/T; T/T → A/A; A/C; C/C → C/C; C/T; T/T → C/C; C/T; T/T → C/C; C/T; T/T → A/A; A/G; G/G → A/A; A/G; G/G → des(datiSNP) #visualizzo la classe delle variabili contenute nel dataframe “datiSNP” datiSNP2=matrix(factor(as.matrix(datiSNP)),ncol=23) datiSNP2=as.data.frame(datiSNP2) #converto le variabili del dataframe in formato “factor” per avere la corrispondenza con la varibili ricodificate (per fare questo passaggio mi appoggio su un oggetto di tipo matrice) colnames(datiSNP2)=colnames(datiSNP) des(datiSNP2) head(datiSNP2) attach(datiSNP2) #gestisco le variabili utilizzando il loro nome (operazione necessaria per l’opzione vars del comando recode) recode(vars=c(rs2808630, rs2516839, rs1260326, rs780094, rs10510293, rs875434, rs1507203, rs1800588, rs7231460, rs1529729, rs688), old.value=c('0','1','2'), new.value=c('C/C','C/T','T/T'), dataFrame = datiSNP2) 84 recode(vars=c(rs7575840, rs864265, rs5370), old.value=c('0','1','2'), new.value=c('G/G','G/T','T/T'), dataFrame = datiSNP2) recode(vars=rs12654264, old.value=c('0','1','2'), new.value=c('A/A','A/T','T/T'), dataFrame = datiSNP2) recode(vars=c(rs328,rs3135506),old.value=c('0','1','2'), new.value=c('C/C','C/G','G/G'), dataFrame = datiSNP2) recode(vars=rs1800775, old.value=c('0','1','2'), new.value=c('A/A','A/C','C/C'), dataFrame = datiSNP2) recode(vars=c(rs3890182, rs662799, rs4420638, rs10500295), old.value=c('0','1','2'), new.value=c('A/A','A/G','G/G'), dataFrame = datiSNP2) head(datiSNP2) detach(datiSNP2); detach(package:epicalc) #disattivo l’attach del dataframe datiSNP2 e il pacchetto epicalc 85 Esercitazione 1 Esercizi di “Elementi di programmazione in R e statistica descrittiva” Esercizio 1 Il numero di decessi per malattie del lavoro in 10 zone industriali è descritto dalla seguente serie: 29 42 20 39 23 27 32 19 40 23 Costruire la distribuzione delle frequenze assolute e relative. Calcolare la moda, la mediana, la media, la varianza campionaria, la deviazione standard e il coefficiente di variazione. Infine collocare le misure appena citate nella sezione opportuna della tabella sottostante e giustificare la scelta. Misure di posizione Misure di variabilità Soluzione: Inserisco i dati come un vettore: decessi<-c(29,42,20,39,23,27,32,19,40,23) Alternativamente posso usare la funzione scan(): decessi<-scan() 29 42 20 39 23 27 32 19 40 23 table(decessi) # distribuzione delle frequenze assolute decessi 19 20 23 27 29 32 39 40 42 1 1 2 1 1 1 1 1 1 table(decessi)/length(decessi) # distribuzione delle frequenze relative decessi 19 0.1 20 0.1 23 0.2 27 0.1 29 0.1 32 0.1 39 0.1 40 0.1 42 0.1 86 Calcolo gli indici richiesti: which.max(table(decessi)) #moda (la modalità con la frequenza maggiore) "23" median(decessi) # mediana 28 mean(decessi)# media 29.4 var(decessi) # varianza campionaria 72.71111 sd(decessi) # deviazione standard 8.527081 sqrt(var(decessi)) # altra formula per la deviazione standard 8.527081 sd(decessi)/mean(decessi) # coefficiente di variazione 0.2900368 Misure di posizione Moda Mediana Media Misure di variabilità Varianza Deviazione standard Coefficiente di variazione 87 Esercizio 2 Dopo aver importato il file “altezze.csv” relativo alla statura (in cm) di 90 studenti di una scuola media superiore, definito il numero di classi uguale a 6 con ampiezza costante uguale a 5 cm, calcolare le frequenze assolute, relative e relative cumulate per ogni classe: Classi Frequenza assoluta Frequenza relativa Frequenza relativa cumulata (160; 165] (165; 170] (170; 175] (175; 180] (180; 185] (185; 190] Totale 90 Soluzione: Importo il file assegnandogli il nome altezze, ne visualizzo un estratto ed eseguo l’attach: altezze<- read.csv2(file.choose(), sep=";", dec=",", header = T) #importo il file altezze.csv head (altezze) attach (altezze) Definisco le classi in cui suddividere le altezze: classi = c(160, 165, 170, 175, 180, 185, 190) classi Con il comando cut, ciascuna altezza sarà collocata nella sua classe di appartenenza: classi.altezza<-cut(Altezza, breaks = classi); classi.altezza 88 Creo infine le tabelle di frequenza: table(classi.altezza) # frequenze assolute (160,165] 3 (165,170] 13 (170,175] 31 (175,180] 31 (180,185] 10 (185,190] 2 table(classi.altezza) / sum(table(classi.altezza)) # frequenze relative (160,165] (165,170] (170,175] (175,180] (180,185] (185,190] 0.03333333 0.14444444 0.34444444 0.34444444 0.11111111 0.02222222 cumsum(table(classi.altezza)) / sum(table(classi.altezza)) #frequenze relative cumulate (160,165] (165,170] (170,175] (175,180] (180,185] (185,190] 0.03333333 0.17777778 0.52222222 0.86666667 0.97777778 1.00000000 Esercizio 3 Dicotomizzare la variabile Altezza dell’esercizio 2 su una soglia di 175 cm (0 se minore, 1 se maggiore o uguale), assegnarle in nome di altezza01, assemblarla al data.frame originario e esportare l’oggetto assemblato in un file formato .txt. Soluzione: altezza01 <- 1*(Altezza>=175); altezza01 data.altezza <- data.frame(altezze,altezza01) write.table(data.altezza,"data.altezza.txt", sep=" ", dec=",", row.names=F, col.names=T) 89 Esercizio 4 Importare in R i datasets “sesso.csv” e “peso.csv” e: a) assemblarli al data.frame altezze già importato assegnandogli il nome soggetti, b) calcolare media, mediana e varianza (generali e per sesso) per la variabile peso; costruire quindi la distribuzione di frequenza per il sesso, c) rappresentare il box-plot della variabile Altezza per ogni sesso e valutare qualitativamente se le mediane nei due sessi sono diverse, se le distribuzioni sono simmetriche e simili e se esistono eventuali outliers (valori estremi), d) esportare il data.frame soggetti in un file .txt. Soluzione: Importo i datasets “sesso.csv” e “peso.csv”, li assemblo al data.frame altezze e creo due ulteriori data.frame (uno per i maschi e uno per le femmine): sesso<-read.csv2(file.choose(), sep=";", header = T) #importo il file sesso.csv peso<-read.csv2(file.choose(), peso.csv sep=";", header = T) #importo il file soggetti<-data.frame(altezze, sesso, peso) head (soggetti) maschi<- subset(soggetti, soggetti$sesso == "m"); maschi # seleziono la parte di dataset relativa agli uomini femmine<- subset(soggetti, soggetti$sesso == "f"); femmine # seleziono la parte di dataset relativa alle donne Calcolo media, mediana e varianza campionaria per la variabile peso e costruisco la distribuzione di frequenza per il sesso: mean(soggetti$peso); mean(maschi$peso); mean(femmine$peso) [1] 80.12222 [1] 80.4375 [1] 79.7619 median(soggetti$peso); median(maschi$peso); median(femmine$peso) [1] 81 [1] 81 [1] 80 90 var(soggetti$peso); var(maschi$peso); var(femmine$peso) [1] 29.8613 [1] 27.48537 [1] 33.06388 table(soggetti$sesso) # distribuzione di frequenza di sesso f m 42 48 plot(soggetti$sesso, soggetti$Altezza, ylab="altezza (in cm)", col=c("pink","lightblue")) #box plot dell’altezza per sesso Esporto il data.frame soggetto in un file .csv: write.table(soggetti,"soggetti.txt", sep="\t", dec=",", row.names=F, col.names=T) 91 Esercizio 5 Dopo aver importato in R il dataset del file “stroke in young.csv” risolvere i seguenti punti: a) per ogni variabile (eccetto ‘Id’) descrivere opportunamente il campione a livello sia esplorativo sia grafico e completare i seguenti items: 1] la media del BMI è ………. Kg/m2; 2] il totale dei soggetti fumatori è ………; 3] il soggetto più anziano ha ……… anni; 4] i soggetti affetti da diabete mellito sono …………; b) ricodificare la variabile ‘MTHFR’ in 0 (assenza dell’allele T) e 1 (presenza dell’allele T) e utilizzare un comando/metodo che sia adeguato a descrivere la distribuzione del gene ricodificato. Informazioni supplementari per l’esercizio 5: Legenda delle variabili presenti nel dataset: Id = id code; cc = condizione di salute [1 = malato, 0 = sano]; sex = sesso [1 = maschi, 2 = femmine]; age = età in anni; bmi = Body Mass Index (BMI) in Kg/m2; hyp = ipertensione [1 = NO, 2 = SI]; dm = diabete mellito [1 = NO, 2 = SI]; smoke = fumatore [1 = NO, 2 = SI]; hypercho = ipercolesterolemia [1 = NO, 2 = SI]; ii = fattore II G20210A [1 = GG, 2 = GA, 3 = AA]; v = fattore V G1691A [1 = NO, 2 = SI]; MTHFR = gene MTHFR [1 = CC, 2 = CT, 3 = TT]; APOE = gene APOE [diviso per categorie]. Soluzione: dati<-read.csv2(file.choose(), header= TRUE, sep=";", na.string="#NULL!") fix(dati) # visualizzo i dati con un editor di R “user-friendly” colnames(dati) # ricavo i nomi delle variabili del dataset importato attach(dati) # accedo alle variabili digitando il loro nome 92 Comunico al software la natura qualitativa delle seguenti variabili; essendo codificate numericamente, R, di default, le riconosce come quantitative anche se per il ricercatore non lo sono. SEX <- factor(sex) HYP <- factor(hyp) DM <- factor(dm) SMOKE <- factor(smoke) HYPERCHO <- factor(hypercho) CC <- factor(cc) II <- factor(ii) FV <- factor(v) MTHFR <- factor(mthfr) APOE <- factor(apoe) Quindi ora le variabili MAIUSCOLE sono considerate dal software come qualitative (o categoriche). Effettuo una prima analisi esplorativa descrivendo quantitativamente e qualitativamente le caratteristiche del campione: table(CC) 0 1 164 163 table(SEX) 1 2 169 158 table(HYP) 1 2 290 37 table(DM) 1 2 317 10 table(SMOKE) 1 2 210 117 table(HYPERCHO) 1 2 250 77 summary(age) Min. 1st Qu. 11.00 30.00 Median 36.00 Mean 34.92 3rd Qu. 40.00 Max. 52.00 93 summary(bmi) Min. 1st Qu. 14.84 21.18 Median 23.52 Mean 23.98 3rd Qu. 26.26 Max. 40.13 NA's 19 Descrizione quantitativa delle variabili genetiche mediante tabelle di frequenza: table(II) # 1=GG, 2=GA, 3=AA 1 2 3 306 13 2 table(FV) # 1=assente 2=presente 1 2 310 11 table(MTHFR) # 1=CC, 2=CT, 3=TT 1 2 3 112 158 57 table(APOE) # 1=e2e2, 2=e2e3, 3=e3e3, 4=e2e4, 5=e3e4, 6=e4e4 1 2 3 4 5 6 2 28 231 61 1 2 Descrizione qualitativa (grafici) delle variabili cliniche: plot(CC, ylim=c(0,200),col=c(3,2), names=c("sani","malati"), main="Ripartizione di malati e sani") legend(locator(1),c("164 sani","163 malati"),fill=c(3,2)) 94 barplot(table(SEX), main="Ripartizione per sesso",ylim=c(0,200), col=c("cyan","rosybrown2"), names=c("maschi","femmine")) legend(1.5,200, c(length(SEX[SEX==1]), length(SEX[SEX==2])), fill=c("cyan","rosybrown2")) par(mfrow=c(1,2)) hist(age,main="Distribuzione per età", ylim=c(0,100), xlab="Età", labels=TRUE, breaks=seq(10,60,5)) boxplot(bmi,main="Boxplot del Body Mass Index", ylab="Kg/m2",col= "yellow") 95 par(mfrow=c(2,2)) barplot(table(HYP), main="Distribuzione ipertensione",ylim=c(0,300), col=c(3,2), names=c("No","Si")) legend(1.5,270,c(length(HYP[HYP==1]),length(HYP[HYP==2])), fill=c(3,2)) barplot(table(DM), main="Ripartizione per diabete mellito", ylim=c(0,330), col=c(3,2), names=c("No","Si")) legend(1.5,280,c(length(DM[DM==1]),length(DM[DM==2])), fill=c(3,2)) barplot(table(SMOKE), main="Ripartizione per attitudine al fumo", ylim=c(0,270), col=c(3,2), names=c("No","Si")) legend(1.5,220,c(length(SMOKE[SMOKE==1]),length(SMOKE[SMOKE==2])), fill=c(3,2)) barplot(table(HYPERCHO), main="Ripartizione per ipercolesterolemia", ylim=c(0,300), col=c(3,2), names=c("No","Si")) legend(1.5,270,c(length(HYPERCHO[HYPERCHO==1]),length(HYPERCHO[HYPERCHO ==2])),fill=c(3,2)) mean(bmi, na.rm=T) # (La media del BMI è 23.97578) [1] 23.97578 table(SMOKE) # (i fumatori sono 117) 1 2 210 117 96 max(age) # (il soggetto più anziano ha 52 anni) [1] 52 table(DM) # (i soggetti affetti da diabete mellito sono 10) 1 2 317 10 gmthfr<-1*(mthfr>1) # codifica per l’allele T table(gmthfr) 0 1 112 215 table(gmthfr)/length(gmthfr) 0 1 0.3425076 0.6574924 97 Esercizio 6 Dopo aver importato il file “altezze.csv” relativo alla statura (in cm) di 90 studenti di una scuola media superiore, definito il numero di classi uguale a 6 con ampiezza costante uguale a 5 cm, calcolare: a. le frequenze assolute e relative per ogni classe; b. calcolare mediante funzioni (function()) la media ponderata e la varianza ponderata; da queste ricavare quindi la deviazione standard e il coefficiente di variazione. Classi Valore centrale di classe (160; 165] 162.5 (165; 170] 167.5 (170; 175] 172.5 (175; 180] 177.5 (180; 185] 182.5 (185; 190] 187.5 Totale Frequenza assoluta Frequenza relativa 90 Soluzione: Importo il file assegnandogli il nome altezze, ne visualizzo un estratto ed eseguo l’attach: altezze <- read.csv2 altezze.csv (file.choose(), header = T) # Importo il file head (altezze) attach (altezze) Definisco le classi in cui suddividere le altezze: classi = c (160, 165, 170, 175, 180, 185, 190) classi 98 Con il comando cut, ciascuna altezza sarà collocata nella sua classe di appartenenza: classi.altezza <- cut (Altezza, breaks = classi); classi.altezza Creo le tabelle di frequenza: table(classi.altezza) # frequenze assolute (160,165] 3 (165,170] 13 (170,175] 31 (175,180] 31 (180,185] 10 (185,190] 2 table(classi.altezza) / sum(table(classi.altezza)) # frequenze relative (160,165] (165,170] (170,175] (175,180] (180,185] (185,190] 0.03333333 0.14444444 0.34444444 0.34444444 0.11111111 0.02222222 Calcolo la media ponderata e la varianza ponderata mediante funzioni di R ad hoc create. Media ponderata: Valori = valori centrali di classe; Ponderazioni = frequenze assolute di classe. Definisco la funzione: media.ponderata <- function(x, peso) { mp <- sum(x*peso)/sum(peso) cat("la media ponderata è ", mp,"\n") } Definisco gli oggetti su cui applicare la funzione: valori <- c (162.5, 167.5, 172.5, 177.5, 182.5, 187.5) # Valori num.classe <- c (3, 13, 31, 31, 10, 2) # Ponderazioni Applico la funzione: media.ponderata (valori, num.classe) # (= 174.6111) Varianza ponderata: Valori = valori centrali di classe; Centro = media ponderata calcolata con la funzione precedente (media = 174.6111) ; Ponderazioni = frequenze assolute di classe. Definisco la funzione: varianza.ponderata <- function(x, media, peso) { vp <- sum(((x-media)^2)* peso) / (sum(peso)-1) cat("la varianza ponderata è ", vp,"\n") } 99 Definisco gli oggetti su cui applicare la funzione: valori <- c (162.5, 167.5, 172.5, 177.5, 182.5, 187.5) # Valori media <- 174.6111 # Centro num.classe <- c (3, 13, 31, 31, 10, 2) # Ponderazioni Applico la funzione: varianza.ponderata (valori, media, num.classe) # (= 27.51561) Ora calcolo deviazione standard e coefficiente di variazione: sqrt(27.51561) # (= 5.245532, deviazione standard) 5.245532 / 174.6111 # (= 0.03004123, coefficiente di variazione) 100 3. Principi di inferenza statistica 3.1 Distribuzioni di campionamento (teoriche) e variabili casuali Le distribuzioni campionarie sono alla base dell’inferenza statistica. Esse permettono di analizzare le proprietà probabilistiche delle statistiche campionarie, da cui discende la teoria necessaria per le procedure di inferenza statistica. La distribuzione campionaria è la distribuzione di tutti i possibili valori che possono essere assunti da una statistica, ossia da una funzione dei dati (ad esempio, media, varianza, ecc), calcolata su campioni di uguale dimensione ed estratti casualmente dalla stessa popolazione. Le distribuzioni campionarie possono essere empiricamente costruite attraverso R: (1) si estraggono M campioni di dimensione n da una variabile casuale (popolazione) di riferimento; (2) si calcola la statistica di interesse per ogni campione; (3) si costruisce l’istogramma della statistica dei diversi valori osservati. Esempio con la statistica media campionaria: # inizializzo a zero l’oggetto mu mu=0 # In mu (vettore) inserirò tutti i valori di media campionaria, calcolati su ogni campione e su cui andrò a produrre l’istogramma. #scelgo arbitrariamente il numero di campioni (M) che simulerò e la relativa numerosità campionarie (n) M=10000 # campioni estratti con campionamento casuale semplice n=1000; # dimensione campionaria di ogni campione for(i in 1:10000){ #(1) x = rnorm(1000,60,9.2) #variabile casuale di riferimento: Normale(60,9.2) mu[i] = mean(x) #(2) } #(3) hist(mu, xlim=c(58,62), prob=F, main="Istogramma delle simulazioni di media campionaria su 10000 campioni di ampiezza 1000") 101 Da cui si può ottenere la distribuzione delle frequenze relative (probabilistica) hist(mu,ylim=c(0,1.6), xlim=c(58,62), prob=T, main="Istogramma delle frequenze relative delle simulazioni di media campionaria su 10000 campioni di ampiezza 1000") #sovrappongo la funzione di densità di una variabile casuale normale di media 60 e deviazione standard 0.29=deviazione standard/n curve(dnorm(x,60,0.29),58,62, add = TRUE) L’approssimazione è più che eccellente!!! 102 Capita spesso che studiando un fenomeno aleatorio si sia anche interessati a una qualche funzione dei possibili esiti oltre agli esiti stessi. Queste funzioni teoriche di valori, definite sullo spazio campionario, sono note come variabili casuali. I valori di una variabile casuale sono determinati dall’esito di un qualche esperimento a cui possiamo associare delle probabilità: tali probabilità produrranno la distribuzione teorica di campionamento della variabile casuale. 3.2 Alcune variabili casuali notevoli Lo standard dei comandi che R segue per le variabili casuali (v. c.) notevoli è quello di identificare il nome specifico, ad esempio binom per la v. c. binomiale, e farlo precedere dalle lettere d, p e q per identificare rispettivamente la densità (o probabilità), la distribuzione cumulata e i quantili; inoltre il prefisso r serve per generare delle determinazioni casuali dalla variabile in oggetto. Nello specifico: • d permette di ottenere la funzione di densità (o probabilità) della variabile, indicando quindi un numero o un vettore di numeri rispetto ai quali si desidera ottenere la funzione di densità o di probabilità; • p permette di ottenere la funzione di ripartizione (distribuzione cumulata) della variabile; in tal caso è necessario indicare il quantile o il vettore dei quantili rispetto ai quali si vuole calcolare il valore della funzione di ripartizione (aggiungendo l’opzione lower.tail=F si ottiene la probabilità dell’evento complementare); • q permette di ottenere i quantili della variabile specificata, indicando la coda inferiore di probabilità o il vettore delle code superiori di probabilità legate ai quantili corrispondenti; • r permette di generare numeri casuali dalla variabile specificata, indicando un numero intero corrispondente alla numerosità del campione che si vuole ottenere. Per un campione di numeri casuali piuttosto numeroso, la distribuzione empirica di questi ultimi, ad esempio tramite un istogramma, simula la funzione di densità della variabile da cui è stato generato il campione stesso. Oltre al prefisso, tali funzioni, per loro natura, richiedono anche la specificazione dei parametri della distribuzione. Ad esempio per la v. c. normale è necessario inserire mean= e sd= un qualsivoglia comando. Lista delle radici dei comandi in R per gestire le variabili casuali più conosciute Variabile Casuale Bernoulli Binomiale Poisson Normale Chi-quadro T di Student F di Snedecor/Fisher Tipologia Parametri Radice comando in R binom Discreta 1, prob binom Discreta n, prob pois Discreta media norm Continua media, dev.st. chisq Continua gdl t Continua gdl f Continua gdl1,gdl2 prob=probabilità, dev. st. = deviazione standard, gdl= gradi di libertà 103 Di seguito due esempi sull’uso dei comandi appena descritti 1. Supponendo che la statura dei bambini di 10 anni si distribuisca pressoché normalmente con una media di 122 cm e una deviazione standard di 12, calcolare a. La percentuale che un bambino scelto a caso nella popolazione abbia una statura maggiore di 145 cm; b. La probabilità che un bambino sia alto da 126 a 130 cm; c. L’altezza dei bambini relativa al 95° percentile; d. In una popolazione di 10000 individui quanti bimbini ci si attende abbiano una statura inferiore a 118 cm? Grafico la distribuzione di densità della v.c. Normale (mu=122, sd=12) curve(dnorm(x,122,12),82,162, xlab= "statura", ylab="densità") a. La percentuale che un bambino scelto a caso nella popolazione abbia una statura maggiore di 145 cm; 1-pnorm(145, 122, 12) # 2.76 % #(complemento della funzione di ripartizione a 145) b. La probabilità che un bambino sia alto da 126 a 130 cm; 104 pnorm(130,122,12)-pnorm(126,122,12) # 0.1169488 #(differenza di funzione di ripartizione) c. L’altezza dei bambini relativa al 95° percentile; qnorm(0.95,122,12) # 141.7382 d. In una popolazione di 10000 individui quanti bimbini ci si attende abbiano una statura inferiore a 118 cm? pnorm(118,122,12)*10000 # 3694 2. Da uno studio condotto sullo sviluppo di malattie cardiovascolari nel reparto alzhaimer di una clinica geriatrica è risultato che il 70% degli anziani presenta placche aterosclerotiche a livello diffuso. Supponendo che la v. c. che governa tale patologia sia una binomiale con probabilità di evento pari a 0.7, e supponendo che si debbano visitare 10 nuovi pazienti anziani dementi, si calcoli: a. la probabilità che cinque pazienti presentino placca aterosclerotica; b. sette presentino la placca; c. al più quattro presentino la patologia; Grafico la distribuzione di probabilità della v.c. Binomiale (n=10,p=0.7) plot(0:10,dbinom(0:10,10,0.7),type="h",xlab="malati alzhaimer", ylab="rischio alzhaimer",ylim=c(0,.6),lwd=3) 105 a. la probabilità che cinque presentino placca aterosclerotica; dbinom(5,10,0.7) #0.1029193 b. sette presentino la placca; dbinom(7, 10, 0.7) #0.2668279 c. al più quattro presentino la patologia; pbinom(4, 10, 0.7) # 0.04734899 3.3 Stime e stimatori Quando si raccoglie un campione di popolazione la prima operazione che viene immediata è quella di descriverlo con opportuni indici di sintesi (o parametri). Sopra ne abbiamo già visti diversi, quali media, varianza, mediana, proporzione ecc.; ma se si desidera estendere i risultati trovati sul campione a un’intera popolazione i valori di quegli indici sono ancora validi? In questa fase emerge la grande differenza tra stima e stimatore. Per stima statistica “puntuale” si intende il valore dell’indice (parametro) calcolato appunto sul campione. Lo stimatore è invece qualcosa di più raffinato e sottintende al concetto frequentista di campionamento ripetuto. Difatti considerando sequenzialmente numerosi (potenzialmente infiniti) campioni di uguale struttura, e calcolando su ciascuno di essi, di volta in volta, la stima puntuale, si genera in automatico una variabile casuale a cui è associata una distribuzione di probabilità (o campionaria): tale variabile casuale è appunto lo stimatore dell’indice di sintesi. Dato questa piccola introduzione, R, mediante simulazioni, ci fornisce la possibilità di reiterare il campionamento e quindi di verificare la forma delle distribuzioni di probabilità degli stimatori degli indici di sintesi a cui siamo interessati. Le distribuzioni di probabilità saranno essenziali per poter fare inferenza (test di significatività e intervalli di confidenza) ovvero quel processo che ci consente di estendere i risultati dal campione alla popolazione. Inoltre, un altro concetto molto importante è quello della variabile casuale di partenza o modello probabilistico di riferimento. Difatti, a seguito del campionamento ripetuto, quando si genera uno stimatore (e quindi una distribuzione di probabilità) spesso è ben conosciuta la legge casuale (ovvero il caso) che a priori governa il fenomeno di interesse. Dato ciò, sono molteplici le circostanze in cui è la variabile casuale normale ad assurgere a tale ruolo. Di seguito è illustrata la verifica, mediante simulazioni, delle distribuzioni di probabilità di tre stimatori: media campionaria, varianza campionaria e rapporto di varianze campionarie. Simulazione di stime di media campionaria da 10000 campioni di numerosità 1000. Variabile casuale di partenza con parametri scelti arbitrariamente: N (=60, =9.2). Stimatore media campionaria (convergenza a una normale standardizzata) Inizializzo a zero i vettori “mu” e “z”. Il primo conterrà tutte le medie campionarie dei 10000 campioni simulati, il secondo i valori della statistica test z= media campionaria standardizzata sui veri valori parametrici. mu=0 z=0 106 for(i in 1:10000){ x = rnorm(1000,60,9.2) mu[i] = mean(x) # stima del parametro oggetto di analisi z[i] = (mu[i]-60)/(9.2/sqrt(1000)) #statistica test o q.tà pivotale } var(z) # 1 mean(z) # 0 Sovrappongo l’istogramma dei valori z prodotti dalla simulazione alla densità di una vera variabile casuale normale standardizzata: l’approssimazione è più che eccellente. hist(z,ylim=c(0,0.8), xlim=c(-4,4), prob=T, main="Istogramma delle simulazioni di media campionaria (standardizzata) su 10000 campioni di ampiezza 1000") curve(dnorm(x),-4,4, add = TRUE) #densità di una v.c. normale Lo stimatore media campionaria si distribuisce come una variabile casuale normale! Simulazione di stime di varianza campionaria da 10000 campioni di numerosità 40 (n). Stimatore varianza campionaria (convergenza a una distribuzione 2 con gradi di libertà 39 (40-1), a meno di una costante). Variabile casuale di partenza con parametri scelti arbitrariamente: N (=60, =9.2). Inizializzo a zero i vettori “varianza” e “X2”. Il primo conterrà tutte le varianze campionarie dei 10000 campioni simulati, il secondo i valori della statistica test X2= varianza×39/2 varianza=0 X2=0 for(i in 1:10000){ y = rnorm(40,60,9.2) varianza[i] = var(y) #stima del parametro oggetto di analisi X2[i] = varianza[i]*39/9.2^2 # statistica test o q.tà pivotale } 107 Sovrappongo l’istogramma dei valori chi prodotti dalla simulazione a una vera variabile casuale 2 con 39 gradi di libertà: l’approssimazione è più che eccellente. hist(X2, prob=T, main="Istogramma delle simulazioni di X2 campionarie su 10000 campioni di ampiezza 40") curve(dchisq(x,39), add = TRUE) #densità di una v.c. 2 con 39 g.d.l. Lo stimatore varianza campionaria (moltiplicato per la costante “(n-1)/varianza della popolazione”) si distribuisce come una variabile con gradi di libertà pari alla numerosità campionaria meno uno! Simulazione di stime di rapporto di varianze da 10000 coppie di campioni di numerosità 25. Stimatore: rapporto di varianze (convergenza a una distribuzione F di Fisher con gradi di libertà n-1 per il numeratore e n-1 per il denominatore). Le variabili casuali di partenza sono due normali con parametri scelti arbitrariamente (le varianze devono essere uguali, mentre le medie possono essere diverse): N (=60, =9.2) e N (=80, =9.2). Inizializzo a zero il vettore “F” che conterrà tutti i valori della statistica test F= var(x1)/var(x2) F=0 # inizializzo a zero l’oggetto F for(i in 1:10000){ x1 = rnorm(25,60,9.2) x2 = rnorm(25,80,9.2) F[i] = var(x1)/var(x2) #statistica test (q.tà pivotale) } Sovrappongo l’istogramma dei valori F prodotti dalla simulazione a una vera variabile casuale F di Fisher con gradi di libertà 24 per il numeratore e 24 per il denominatore: l’approssimazione è più che eccellente. hist(F, ylim=c(0,1.2),prob=T, main="Istogramma delle simulazioni di rapporto di varianze su 10000 campioni di ampiezza 25", breaks=seq(0,7,length=100)) curve(df(x,24,24), add = TRUE) #densità di una v.c. F di Fisher con g.d.l. 24 per il numeratore e 24 per il denominatore 108 Lo stimatore rapporto di varianze si distribuisce come una variabile F di Fisher con gradi di libertà pari alla numerosità campionaria meno uno per il numeratore e altrettanti per il denominatore! 3.4 Gli elementi e la filosofia dei test di significatività Scopo del test: fornire un risultato statistico contro un’ipotesi (congettura) di ricerca data per forte o assodata; in altri termini, tentare di negare l’ipotesi nulla (dominante… fino a prova contraria). Passi: 1) Stabilire la variabile osservata su cui fare il test e una variabile casuale (modello probabilistico di riferimento) che la governi; 2) Stabilire la o le popolazioni di riferimento su cui è stata osservata la variabile; 3) Specificare il parametro (indice) da indagare; 4) Formulare sul parametro sia l’ipotesi nulla (preponderante fino a prova contraria) che l’ipotesi alternativa; 5) Stabilire un livello di significatività; 6) Definire una statistica test (o funzione di confronto (perdita) o quantità pivotale); tale oggetto deve essere funzione del campione e del parametro da indagare ma la sua distribuzione deve essere nota (tabulata) e non funzione di questi due (cfr. paragrafo precedente); 7) Appurare lo stimatore (o variabile casuale della statistica test) e la sua distribuzione (cfr. paragrafo precedente); 8) Definire la regola di decisione per il rifiuto dell’ipotesi nulla: approccio del quantile vs. approccio del p-value. 109 3.5 Test di significatività parametrici confidenza e intervalli di …da modello probabilistico normale 3.5.1 Sulla media di una variabile casuale normale con noto (Test Z a un campione) Test Z a un campione (esempio di test a due code) Alcuni ricercatori sono interessati ad ottenere una risposta alla seguente domanda: “è possibile concludere che l’età media di una certa popolazione d’interesse è uguale a 45 anni?” (Ipotesi nulla H0). Passo 1: età<-c(64, 95, 28, 64, 62, 54, 92, 96, 86, 69, 102, 75, 33, 33, 68, 86, 45, 37, 59, 20, 33, 18, 7, 18, 38, 66, 45, 66, 80, 69, 58, 44, 41, 70, 25, 51, 71, 68, 13, 38) età ~ N(,2=202) (modello probabilistico di partenza da informazioni preliminari) Passo 2: una popolazione (“…una certa popolazione d’interesse…”) Passo 3: Passo 4: H0: =45; H1: ≠45 (test a due code: ipotesi alternativa bidirezionale) Passo 5: = 0.05 Passo 6: statistica test Passo 7: Z ~ N(0,1) Passo 8: In R: Calcolo la media campionaria: mean(età) # 54.675 = media campionaria 110 Calcolo lo z osservato: z_oss=(mean(età)-45)/(20/sqrt(length(età))); z_oss # 3.059504 Approccio del quantile Mi calcolo lo z critico a un livello 0.025 (alpha/2) poiché il livello di significatività è ripartito simmetricamente tra le due code della Normale (0.025 per coda). z_cri <- qnorm(0.975); z_cri # z(1-alpha/2)= 1.96 Ora grafico la distribuzione dello stimatore per avere chiaro l’oggetto con cui sto operando: curve(dnorm(x), -4, 4, xlab= "z", ylab="f(z)") abline(v=-1.96, lty="longdash") #quantile -z(1-alpha/2) abline(v=1.96, lty="longdash") # quantile z(1-alpha/2) abline(v=z_oss, lwd=4) #quantile z osservato abs(z_oss) > z_cri # comando logico: restituisce TRUE o FALSE regola di decisione => abs(z_oss) > z (1-alpha/2) ? Nella fattispecie abs(z_oss) è maggiore dello z critico (z(1-alpha/2)) e quindi rifiuto H0 (età media = 45): lo “z” osservato è significativo Approccio p-value: regola di decisione (soglia del 0.05) => p-value < ? p.value <- 2 * (1-pnorm(abs(z_oss)) # moltiplico per due poiché il test è a due code 111 p.value # 0.0022 < 0.05 Confronto con p=0.05 e pervengo alla stessa decisione: rifiuto H0. Ho una consistente evidenza contro H0 di =45; In altri termini, data vera H0, la probabilità di ottenere z_oss o addirittura valori più estremi è "bassa" (0.0022 <0.05) e quindi il valore osservato del test Z (z_oss) è da considerarsi statisticamente significativo. Graficamente: xv<-seq(-4,4,0.01) yv<-dnorm(xv) plot(xv,yv,type="l",xlab="z",ylab="f(z)") polygon(c(xv[xv<=-abs(z_oss)], -abs(z_oss)), c(yv[xv<=abs(z_oss)],yv[xv==-4]), col="red") polygon(c(xv[xv>=abs(z_oss)],abs(z_oss)),c(yv[xv>=abs(z_oss)],yv[xv==4]), col="red") abline(v=-1.96, lty="longdash") abline(v=1.96, lty="longdash") abline(v=z_oss, lwd=4) #quantile z osservato legend(-3.7,0.4,"p value",fill="red") legend(-3.7,0.35,"p value=0.05",lty=2,bty="n") 112 Test Z a un campione (esempio di test a una coda: coda destra) Alcuni ricercatori sono interessati ad ottenere una risposta alla seguente domanda: “è possibile concludere che l’età media di una certa popolazione d’interesse è minore di 45 anni?” (ipotesi nulla H0). Passo 1: età<-c(64, 95, 28, 64, 62, 54, 92, 96, 86, 69, 102, 75, 33, 33, 68, 86, 45, 37, 59, 20, 33, 18, 7, 18, 38, 66, 45, 66, 80, 69, 58, 44, 41, 70, 25, 51, 71, 68, 13, 38) età ~ N(,2=202) (modello probabilistico di partenza da informazioni preliminari) Passo 2: una popolazione (“…una certa popolazione d’interesse…”) Passo 3: Passo 4: H0: = 45; H1: ≥ 45 (test a una coda: ipotesi alternativa unidirezionale) Passo 5: = 0.05 113 Passo 6: statistica test Passo 7: Z ~ N(0,1) Passo 8: In R: Calcolo la media campionaria: mean(età) # 54.675 = media campionaria Calcolo lo z osservato: z_oss=(mean(età)-45)/(20/sqrt(length(età))); z_oss # 3.059504 Approccio del quantile Mi calcolo lo z critico a un livello 0.05 (alpha) poiché il livello di significatività viene collocato nella zona dell’ipotesi H1, che in questo caso corrisponde alla coda di destra della Normale: z_cri <- qnorm(0.95); z_cri # z(1-alpha)= 1.644854 Ora grafico la distribuzione dello stimatore per avere chiaro l’oggetto con cui sto operando: curve(dnorm(x), -4, 4, xlab= "z", ylab="f(z)") abline(v= 1.644854, lty="longdash") # quantile z(1-alpha) abline(v=z_oss, lwd=4) #quantile z osservato 114 z_oss > z_cri # comando logico: restituisce TRUE o FALSE regola di decisione => abs(z_oss) > z (1-alpha) ? Nella fattispecie abs(z_oss) è maggiore dello z critico (z(1-alpha)) e quindi rifiuto H0 (età media = 45): lo “z” osservato è significativo. Approccio p-value: regola di decisione (soglia del 0.05) => p-value < ? p.value <- 1-pnorm(z_oss) # NON moltiplico per due poiché il test è a una coda p.value # 0.00110852 < 0.05 Confronto con p=0.05 e pervengo alla stessa decisione: rifiuto H0. Ho una consistente evidenza contro H0: = 45. In altri termini, data vera H0, la probabilità di ottenere z_oss o addirittura valori più estremi è "bassa" (0.00110852 < 0.05) e quindi il valore osservato del test Z (z_oss) è da considerarsi statisticamente significativo. Graficamente: xv<-seq(-4,4,0.01) yv<-dnorm(xv) plot(xv,yv,type="l",xlab="z",ylab="f(z)") polygon(c(xv[xv>=abs(z_oss)],abs(z_oss)),c(yv[xv>=abs(z_oss)],yv[xv==4]), col="red") abline(v=1.644854, lty="longdash") abline(v=z_oss, lwd=4) #quantile z osservato legend(-3,0.4,"p value",fill="red") legend(-3,0.35,"p value=0.05",lty=2,bty="n") 115 Test Z a un campione (esempio di test a una coda: coda sinistra) Alcuni ricercatori sono interessati ad ottenere una risposta alla seguente domanda: “è possibile concludere che l’età media di una certa popolazione d’interesse è maggiore di 45 anni?” (ipotesi nulla H0). Passo 1: età<-c(64, 95, 28, 64, 62, 54, 92, 96, 86, 69, 102, 75, 33, 33, 68, 86, 45, 37, 59, 20, 33, 18, 7, 18, 38, 66, 45, 66, 80, 69, 58, 44, 41, 70, 25, 51, 71, 68, 13, 38) età ~ N(,2=202) (modello probabilistico di partenza da informazioni preliminari) Passo 2: una popolazione (“…una certa popolazione d’interesse…”) Passo 3: Passo 4: H0: = 45; H1: ≤ 45 (test a una coda: ipotesi alternativa unidirezionale) Passo 5: = 0.05 Passo 6: statistica test Passo 7: Z ~ N(0,1) Passo 8: In R: Calcolo la media campionaria: mean(età) # 54.675 = media campionaria Calcolo lo z osservato: z_oss=(mean(età)-45)/(20/sqrt(length(età))); z_oss # 3.059504 Approccio del quantile Mi calcolo lo z critico a un livello 0.05 (alpha) poiché il livello di significatività viene collocato nella zona dell’ipotesi H1, che in questo caso corrisponde alla coda di sinistra della Normale: z_cri <- qnorm(0.05); z_cri # z(alpha)= -1.644854 116 Ora grafico la distribuzione dello stimatore per avere chiaro l’oggetto con cui sto operando: curve(dnorm(x), -4, 4, xlab= "z", ylab="f(z)") abline(v=-1.644854, lty="longdash") #quantile -z(1-alpha) abline(v=z_oss, lwd=4) #quantile z osservato z_oss < z_cri # comando logico: restituisce TRUE o FALSE regola di decisione => z_oss < z (alpha) ? Nella fattispecie z_oss è maggiore dello z critico (z(alpha)) e quindi non rifiuto H0 (età media = 45): lo “z” osservato non è significativo Approccio p-value: regola di decisione (soglia del 0.05) => p-value < ? p.value <- pnorm(z_oss) # NON moltiplico per due poiché il test è a una coda p.value # 0.9988915 > 0.05 Confronto con p=0.05 e pervengo alla stessa decisione: non rifiuto H0. Non ho nessuna evidenza contro H0 di = 45; In altri termini, data vera H0, la probabilità di ottenere z_oss o addirittura valori più estremi è "alta" (0.9988915 > 0.05) e quindi il valore osservato del test Z (z_oss) è da considerarsi non statisticamente significativo. Graficamente: xv<-seq(-4,4,0.01) yv<-dnorm(xv) plot(xv,yv,type="l",xlab="z",ylab="f(z)") 117 polygon(c(xv[xv<=abs(z_oss)], abs(z_oss)), c(yv[xv<=abs(z_oss)],yv[xv==4]), col="red") abline(v=-1.644854, lty="longdash") abline(v=z_oss, lwd=4) #quantile z osservato legend(1,0.4,"p value",fill="red") legend(1,0.35,"p value=0.05",lty=2,bty="n") Intervalli di confidenza (IC) Esempio: Fissiamo un livello di confidenza pari 0.95 = 1 - Calcolo il 97.5° percentile poiché il 5% (), complemento a 100 del livello di confidenza, è ripartito sulle code simmetriche in due parti uguali di 2,5%. qnorm(0.975) # 1.959964 (= a z_critico di prima) se=20/sqrt(length(età)); se # 3.162278 L1<- mean(età)- 1.959964*se L2<- mean(età)+ 1.959964*se cat("95%CI Media = ", L1, L2, "\n") 95%CI Media = 48.47705 60.87295 118 Con una probabilità del 95% la vera età media della popolazione è contenuta nell’intervallo di valori compreso tra 48 e 61 anni, ovvero con un livello di confidenza del 95% si considera verosimile che l’età media sia compresa tra 48 e 61 anni (interpretazione di Fisher). In altri termini, replicando l’esperimento un numero elevato di volte, circa il 95% degli intervalli di confidenza osservati dovrebbe contenere il vero valore del parametro μ (interpretazione frequentista di Neyman); Inoltre, grazie alla dualità tra i test e gli IC tutti i valori di 0 che sono compresi nell’intervallo non sono rifiutati da un test di significatività a due code (al 5% =livello di significatività, complemento a 100 del livello di confidenza); quindi, siccome il 45 dell’ipotesi nulla non è contenuto, già dall’IC 95% posso rifiutare H0:=45 senza fare il test (infatti il p-value era <0,05 e avevo una consistente evidenza contro H0). Corollario su IC Ora verifichiamo empiricamente l’interpretazione frequentista di Neyman dell’intervallo di confidenza; prima si era detto che replicando l’esperimento un numero elevato di volte, circa il 95% (poiché quello è il livello di confidenza dai fissato a priori) degli intervalli di confidenza osservati avrebbe contenuto il vero valore del parametro μ (probabilità di copertura). Per verificare tale proposizione si può ricorrere a una simulazione per valutare il livello di copertura effettivo di un intervallo di confidenza appunto di livello 0,95. Chiaramente la simulazione avverrà sul parametro m oggetto di indagine. Le seguenti istruzioni sono necessarie per generare 1000 campioni simulati, su cui calcolare gli intervalli di confidenza di cui memorizzerò gli estremi nella matrice mu.ic di 1000 righe (numero dei campioni simulati) e 2 colonne (gli estremi dell’IC per ogni campione): 1) età ~ N(,2=202) (modello probabilistico di partenza da informazioni preliminari) 2) Numerosità di ogni campione: 40 3) Livello di confidenza = 95% Inizializzo a zero la matrice mu.ic che conterrà tutti gli estremi degli IC (livello di confidenza =0.95) mu.ic = matrix(0, ncol = 2, nrow = 1000) …e poi faccio la simulazione for (i in 1:1000) { n = 40 x = rnorm(n, mean = 50, sd = 20) mu = mean(x) mu.lower = mu - qnorm(0.975)*20/sqrt(n) mu.upper = mu + qnorm(0.975)*20/sqrt(n) mu.ic[i,1] = mu.lower mu.ic[i,2] = mu.upper } Verifico che la probabilità di copertura sia molto prossima a 0.95 (95%) mean((mu.ic[,1] <= 50) & (mu.ic[,2] >= 50)) 119 E rappresento un estratto di ciò graficamente (estraggo solo 100 IC 95% sui 1000 simulati) ESTR<-sample(1:1000, 100, replace = FALSE) plot(mu.ic[ESTR,1], 1:100, xlim=c(30,70), xlab = "età media (mu)", ylab = "campioni simulati", cex=0.6) points(mu.ic[ESTR,2],1:100, , cex=0.6) segments(mu.ic[ESTR,1],1:100,mu.ic[ESTR,2],1:100) abline(v = 50, col = 2) MODO "AUTOMATICO" PER AVERE TEST E IC install.packages("BSDA") #installo il pacchetto "BSDA" (Basic Statistics and Data Analysis) library(BSDA) #carico il pacchetto appena installato z.test(età, mu = 45, sigma.x = 20, alternative = "two.sided", conf.level = 0.95) One-sample z-Test data: età z = 3.0595, p-value = 0.002217 alternative hypothesis: true mean is not equal to 45 95 percent confidence interval: 48.47705 60.87295 sample estimates: mean of x 54.675 Quindi in R, la regola decisionale per i test “rifiuto/non rifiuto” segue l’approccio del p-value! 120 Altro esempio: stesso test ma cambio l’ipotesi nulla ovvero modifico il passo 4 Passo 4: H0: =45; H1: ≥45 (test a una coda: ipotesi alternativa unidirezionale) z.test(età, mu = 45, sigma.x = 20, alternative = "greater", conf.level = 0.95) One-sample z-Test data: età z = 3.0595, p-value = 0.001109 alternative hypothesis: true mean is greater than 45 95 percent confidence interval: 49.47352 NA sample estimates: mean of x 54.675 Altro esempio: stesso test ma cambio l’ipotesi nulla ovvero modifico solo il passo 4 Passo 4: H0: =45; H1: ≤45 (test a una coda: ipotesi alternativa unidirezionale) z.test(età, mu = 45, sigma.x = 20, alternative = "less", conf.level = 0.95) One-sample z-Test data: età z = 3.0595, p-value = 0.9989 alternative hypothesis: true mean is less than 45 95 percent confidence interval: NA 59.87648 sample estimates: mean of x 54.675 Ora vedremo esempi degli altri test di significatività solo mediante il modo automatico…per velocizzare le cose!!! 121 3.5.2 Sulla media di una variabile casuale normale con ignoto (Test T a un campione) Modello probabilistico di partenza da informazioni preliminari età ~ N(,2), test a due code, ipotesi uguali a quelle di prima, livello di confidenza=0.90) t.test(età, mu = 45, alternative = "two.sided", conf.level=0.9) One Sample t-test data: età t = 2.4647, df = 39, p-value = 0.01822 alternative hypothesis: true mean is not equal to 45 90 percent confidence interval: 48.06104 61.28896 sample estimates: mean of x 54.675 Per i test unidirezionali (a una coda) i comandi sono analoghi al test spiegato al punto a) mutatis mutandis. 3.5.3 Sulla differenza tra medie di due variabili casuali normali con noti e uguali (Test Z per due campioni indipendenti) Modello probabilistico di partenza da informazioni preliminari età maschi ~ N(,2=202); età femmine ~ N(,2=202) età<-c(64, 95, 28, 64, 62, 54, 92, 96, 86, 69, 102, 75, 33, 33, 68, 86, 45, 37, 59, 20, 33, 18, 7, 18, 38, 66, 45, 66, 80, 69, 58, 44, 41, 70, 25, 51, 71, 68, 13, 38) età.maschi<-età[1:20]; età.maschi [1] 64 95 37 59 20 28 64 62 54 92 96 86 69 102 75 33 33 68 86 45 età.femmine<-età[21:40]; età.femmine [1] 33 18 7 18 38 66 45 66 80 69 58 44 41 70 25 51 71 68 13 38 mean(età.maschi) # 63.4 mean(età.femmine) # 45.95 mean(età.maschi) - mean(età.femmine) # 17.45 122 z.test(età.maschi,età.femmine, mu=0, sigma.x=20, sigma.y=20, alternative = "two.sided") Two-sample z-Test data: età.maschi and età.femmine z = 2.7591, p-value = 0.005796 alternative hypothesis: true difference in means is not equal to 0 95 percent confidence interval: 5.054099 29.845901 sample estimates: mean of x mean of y 63.40 45.95 3.5.4 Sulla differenza tra medie di due variabili casuali normali con ignoti ma uguali (Test T per due campioni indipendenti) Modello probabilistico di partenza da informazioni preliminari età maschi ~ N(,2); età femmine ~ N(,2) t.test(età.maschi, età.femmine, mu = 0, alternative = "two.sided", var.equal = TRUE) Two Sample t-test data: età.maschi and età.femmine t = 2.3477, df = 38, p-value = 0.0242 alternative hypothesis: true difference in means is not equal to 0 95 percent confidence interval: 2.403057 32.496943 sample estimates: mean of x mean of y 63.40 45.95 3.5.5 Sulla differenza tra medie di due variabili casuali normali con ignoti e diversi (Test T per due campioni indipendenti) Modello probabilistico di partenza da informazioni preliminari età maschi ~ N(,2); età femmine ~ N(,2) t.test(età.maschi, età.femmine, mu = 0, alternative = "two.sided", var.equal = FALSE) 123 Welch Two Sample t-test data: età.maschi and età.femmine t = 2.3477, df = 37.5, p-value = 0.02427 alternative hypothesis: true difference in means is not equal to 0 95 percent confidence interval: 2.396467 32.503533 sample estimates: mean of x mean of y 63.40 45.95 3.5.6 Sulla differenza tra medie di due variabili casuali normali con ignoti ma uguali (Test T per due campioni appaiati) Modello probabilistico di partenza da informazioni preliminari PAD 0 (prima) ~ N(,2); PAD 1 (dopo) ~ N(,2) pressione<- read.csv2(file.choose(), sep=";", dec=",", header = T) #importo il file pressione.csv attach(pressione) mean(PAD[gruppo==0]); mean(PAD[gruppo==1]) [1] 126.1 [1] 133.1 t.test(PAD~gruppo, mu = 0, alternative = "two.sided", paired=T) Paired t-test data: PAD by gruppo t = -0.6058, df = 9, p-value = 0.5596 alternative hypothesis: true difference in means is not equal to 0 95 percent confidence interval: -33.14072 19.14072 sample estimates: mean of the differences -7 Alternativamente t.test(PAD[gruppo==0], PAD[gruppo==1], mu = 0, alternative = "two.sided", paired=T) 124 Paired t-test data: PAD[gruppo == 0] and PAD[gruppo == 1] t = -0.6058, df = 9, p-value = 0.5596 alternative hypothesis: true difference in means is not equal to 0 95 percent confidence interval: -33.14072 19.14072 sample estimates: mean of the differences -7 3.5.7 Sul rapporto di varianze di due variabili casuali normali (Test F per due campioni indipendenti) Modello probabilistico di partenza da informazioni preliminari età maschi ~ N(,2); età femmine ~ N(,2) var.test(età.maschi, età.femmine, ratio = 1, alternative = "two.sided") F test to compare two variances data: età.maschi and età.femmine F = 1.2611, num df = 19, denom df = 19, p-value = 0.6182 alternative hypothesis: true ratio of variances is not equal to 1 95 percent confidence interval: 0.4991395 3.1859847 sample estimates: ratio of variances 1.261051 3.6 Test di significatività da modello probabilistico non Normale Test di significatività mediante approssimazione normale (n > 30) 3.6.1 Su una proporzione (Test Z su proporzione) Passo 1: XpiomboSI~Be(ppiomboSI) continua!) (≠ XpiomboSI~N(,2) !) e XpiomboSI osservata dicotomica (non Passo 4: H0: ppiomboSI ≥ 0.15; H1: ppiomboSI < 0.15 (test a una coda: ipotesi alternativa unidirezionale) Grazie al teorema centrale del limite (versione DeMoivre-Laplace) posso applicare il test Z prop.test(25, 250, p=0.15, alternative="less", correct=F) 125 1-sample proportions test without continuity correction data: 25 out of 250, null probability 0.15 X-squared = 4.902, df = 1, p-value = 0.01341 alternative hypothesis: true p is less than 0.15 95 percent confidence interval: 0.0000000 0.1356179 sample estimates: p 0.1 Il commando di R in cui è implementato questo test (e il successivo) restituisce un valore osservato di statistica test in scala 2 (X-squared). Tuttavia grazie alla corrispondenza biunivoca 21gdl = Z facendo appunto la radice quadrata di quel valore è possibile ottenere il quantile z osservato proprio come spiegato nelle lezioni teoriche. sqrt(4.902) # = z osservato 3.6.2 Sulla differenza di due proporzioni (Test Z su differenza di proporzioni) Passo 1: XPSAalto~Be(palto) e XPSAbasso~Be(pbasso) (≠ X~N(,2) !) e XPSAalto e XPSABasso osservate dicotomiche (non continue!) Passo 4: H0: palto ≤ pbasso, cioè palto – pbasso ≤ 0; H1: palto > pbasso, cioè palto – pbasso > 0 (test a una coda: ipotesi alternativa unidirezionale) Grazie al teorema centrale del limite (versione DeMoivre-Laplace) posso applicare il test Z Tab<-matrix(c(46, 10, 21, 47), nrow=2, ncol=2, dimnames= list(c("PSA alto", "PSA basso"), c("malati", "sani"))); Tab malati sani PSA alto 46 21 PSA basso 10 47 prop.test(Tab, alternative = "greater", correct=F) 2-sample test for equality of proportions without continuity correction data: Tab X-squared = 32.4889, df = 1, p-value = 5.994e-09 alternative hypothesis: greater 95 percent confidence interval: 0.3864044 1.0000000 sample estimates: prop 1 prop 2 0.6865672 0.1754386 Le proporzioni vengono calcolate per riga (46/67=0.6865, 10/57=0.1754) e quindi il test implementato in R considera le variabili casuali disposte appunto per riga e i “successi” (malati nella fattispecie) collocati nella prima colonna. 126 Alternativamente, cambiando le modalità di inserimento… Malati_per_PSA=c(46,10) totali=c(67,57) prop.test(x = Malati_per_PSA, n = totali, alternative = "greater", correct=F) 2-sample test for equality of proportions without continuity correction data: Malati_per_PSA out of totali X-squared = 32.4889, df = 1, p-value = 5.994e-09 alternative hypothesis: greater 95 percent confidence interval: 0.3864044 1.0000000 sample estimates: prop 1 prop 2 0.6865672 0.1754386 Oppure ancora…definendo dapprima i valori di cella, creando quindi due vettori e da questi la tavola di contingenza 2x2 su cui applicare il test a<-46; b<-21; c<-10; d<-47; a b c d PSA<-c(rep("PSA Alto",a),rep("PSA Alto",b),rep("PSA Basso",c),rep("PSA Basso",d)) status<-c(rep("malati",a),rep("sani",b),rep("malati",c),rep("sani",d)) table(PSA,status) PSA alto PSA basso malati sani 46 21 10 47 prop.test(table(PSA,status), alternative = "two.sided", correct=F) 2-sample test for equality of proportions without continuity correction data: table(PSA, status) X-squared = 32.4889, df = 1, p-value = 1.199e-08 alternative hypothesis: two.sided 95 percent confidence interval: 0.3625105 0.6597466 sample estimates: prop 1 prop 2 0.6865672 0.1754386 127 Test di significatività per l’associazione di due fenomeni 3.6.3 Test di indipendenza Passo 1: Xm~Be(pm) e Xf~Be(pf) (≠ X~N(,2) !) e Xm e Xf osservate dicotomiche (non continue!) N.B.: Frequenze attese > 5 Esempio Passo 4: H0: pm = pf ; H1: pm ≠ pf (test a due code: ipotesi alternativa bidirezionale) Fenomeni: daltonismo e sesso Costruiamo il test “manualmente”: #Frequenze osservate a1<-38 #daltonici maschi b1<-6 #daltonici femmine c1<-442 #non daltonici maschi d1<-514 #non daltonici femmine obs1<-matrix(c(a1, c1, b1, d1), nrow=2, ncol=2, dimnames= list(c("daltonici", "normali"), c("maschi", "femmine"))); obs1 daltonici normali maschi femmine 38 6 442 514 #Frequenze attese n1<-a1+b1+c1+d1 ea1<-(a1+b1)*(a1+c1)/n1 eb1<-(a1+b1)*(b1+d1)/n1 ec1<-(c1+d1)*(a1+c1)/n1 ed1<-(c1+d1)*(b1+d1)/n1 exp1<-matrix(c(ea1, ec1, eb1, ed1), nrow=2, ncol=2, dimnames= list(c("daltonici", "normali"), c("maschi", "femmine"))); exp1 maschi femmine daltonici 21.12 22.88 normali 458.88 497.12 #test X2 x2<- sum((obs1-exp1)^2/exp1); x2 # x2 osservato = 27.13874 px2 <- 2*(1-pnorm(sqrt(x2))); px2 # p-value = 1.893646e-07 128 Rifiutiamo H0 Alternativamente e automaticamente… : chisq.test(obs1, correct=F) Pearson's Chi-squared test data: obs1 X-squared = 27.1387, df = 1, p-value = 1.894e-07 Test di significatività non parametrici 3.6.4 Sull’uguaglianza di due variabili casuali (Test U di Mann-Whitney) attraverso le mediane (X0.5) Passo 1: XE~??? e XNe~??? (XE e XNe ≠ ~N(,2) !) e XE e XNe osservate numeriche; n<30. Passo 4: H0: XE)=XNe) → EX0.5=NeX0.5; H1: EX0.5 ≠ bidirezionale) NeX0.5 (test a due code: ipotesi alternativa Esposti<-c(14.4, 14.2, 14.8, 14.5, 14.1, 16.6, 14.9, 15.6, 14.1, 15.3, 15.7, 14.4, 14.7, 14.3, 19) Non_esposti<- c(17.4, 16.2, 17.1, 17.5, 12, 16, 16.9, 13.5, 16.3, 16.8) Per eseguire questo test è necessario installare e caricare il pacchetto exactRankTests: install.packages("exactRankTests") library(exactRankTests) Il commando wilcox.exact applica il test wilcox.exact(Esposti, Non_esposti) Exact Wilcoxon rank sum test data: Esposti and Non_esposti W = 41, p-value = 0.06016 alternative hypothesis: true mu is not equal to 0 129 3.6.5 Sulla normalità di una distribuzione (Test di Shapiro-Wilk) Passo 1: X~??? (≠ X~N(,2) ?) e X osservata numerica Passo 4: H0: X)= N(,2); H1: X) ≠ N(,2) (test a due code: ipotesi alternativa bidirezionale) shapiro.test(Non_esposti) Shapiro-Wilk normality test data: Non_esposti W = 0.7814, p-value = 0.008621 130 Esercitazione 2 Test di significatività e intervalli di confidenza Esercizio 1 Importare in R il dataset del file altezze.csv relativo alla statura (in cm) di un campione costituito da 90 studenti di una scuola media superiore e risolvere i seguenti punti: a) verificare la normalità della distribuzione della variabile Altezza nella popolazione di riferimento, b) conoscendo la varianza della variabile Altezza nella popolazione di riferimento (2 = 25 cm2), è possibile affermare con una confidenza del 95% che la statura media degli studenti delle scuole medie superiori è uguale a 170 cm? c) non conoscendo la varianza della variabile Altezza nella popolazione di riferimento, è possibile affermare con una confidenza del 90% che la statura media degli studenti delle scuole medie superiori è uguale a 170 cm? Soluzione: Importo in R il dataset del file altezze.csv, visualizzo le etichette delle variabili ed eseguo l’attach(): altezze <- read.csv2 (file.choose(), header = T) colnames (altezze) attach (altezze) Punto a: Verifico la normalità della distribuzione della variabile Altezza nella popolazione di riferimento mediante il test di Shapiro-Wilk: H0: X)= N(,2); H1: X) ≠ N(,2) shapiro.test(Altezza) Shapiro-Wilk normality test data: Altezza W = 0.9841, p-value = 0.3406 p=0.3406>0.05: non posso rifiutare H0: la variabile è distribuita normalmente. 131 Punto b: Dovendo fare inferenza statistica sulla media () di una variabile casuale normale con 2 noto e disponendo dei dati rilevati su un singolo campione, applico il comando del test Z a un campione, con: H0: = 170 cm; H1: ≠ 170 cm (test a due code: ipotesi alternativa bidirezionale) per ottenere l’IC 95% necessario a risolvere l’esercizio. install.packages("BSDA") # Installo il pacchetto "BSDA" (Basic Statistics and Data Analysis) library(BSDA) # Carico il pacchetto appena installato z.test(Altezza, mu = 170, sigma.x = 5, alternative = "two.sided", conf.level = 0.95) One-sample z-Test data: Altezza z = 9.9085, p-value < 2.2e-16 alternative hypothesis: true mean is not equal to 170 95 percent confidence interval: 174.1892 176.2552 sample estimates: mean of x 175.2222 Il valore 170 (cm) non ricade nell’IC 95% (174.189; 176.255) e quindi non è una stima verosimile per la statura media degli studenti delle scuole medie superiori. Inoltre ho una decisiva evidenza contro H0: Altezza = 170 cm (p<0.001) e quindi rifiuto l’ipotesi nulla in un test a due code. Punto c: Dovendo fare inferenza statistica sulla media () di una variabile casuale normale con 2 ignoto e disponendo dei dati rilevati su un singolo campione, applico il comando del test T a un campione, con: H0: = 170 cm; H1: ≠ 170 cm (test a due code: ipotesi alternativa bidirezionale) per ottenere l’IC 90% necessario a risolvere l’esercizio. t.test(Altezza, mu = 170, alternative = "two.sided", conf.level = 0.90) One Sample t-test data: Altezza t = 9.943, df = 89, p-value = 4.198e-16 alternative hypothesis: true mean is not equal to 170 90 percent confidence interval: 174.3492 176.0952 sample estimates: mean of x 175.2222 132 Il valore 170 (cm) non ricade nell’IC 90% (174.35; 176.095) e quindi non è una stima verosimile per la statura media degli studenti delle scuole medie superiori. Inoltre ho una decisiva evidenza contro H0: Altezza = 170 cm (p<0.001) e quindi la rifiuto in un test a due code. detach (altezze) 133 Esercizio 2 Importare in R il dataset del file stroke in young.txt e risolvere i seguenti punti: a) è possibile affermare che esiste un’associazione significativa tra il fumo di tabacco e l’ipertensione arteriosa? b) è possibile affermare con un livello confidenza del 99% che nella popolazione di riferimento le fumatrici donne sono pari al 20%? c) benché non ci siano evidenze in letteratura, è possibile affermare che nella popolazione di riferimento i fumatori hanno una probabilità maggiore di manifestare ipercolesterolemia rispetto ai non fumatori? Informazioni supplementari per l’esercizio 2: Legenda delle variabili presenti nel dataset: Id = id code; cc = condizione di salute [1 = malato, 0 = sano]; sex = sesso [1 = maschi, 2 = femmine]; age = età in anni; bmi = Body Mass Index (BMI) in Kg/m2; hyp = ipertensione arteriosa [1 = NO, 2 = SI]; dm = diabete mellito [1 = NO, 2 = SI]; smoke = fumatore [1 = NO, 2 = SI]; hypercho = ipercolesterolemia [1 = NO, 2 = SI]; ii = fattore II G20210A [1 = GG, 2 = GA, 3 = AA]; v = fattore V G1691A [1 = NO, 2 = SI]; MTHFR = gene MTHFR [1 = CC, 2 = CT, 3 = TT]; APOE = gene APOE [diviso per categorie]. Soluzione: Importo in R il dataset del file stroke in young.txt, visualizzo i dati e le etichette delle variabili ed eseguo l’attach(): dati <- read.table (file.choose(), sep = "", header = TRUE, dec = ".", na.strings = ".") colnames(dati) # Ricavo i nomi delle variabili del dataset importato. attach(dati) # Accedo alle variabili digitando il loro nome. Punto a: Comunico al software la natura qualitativa delle variabili oggetto di studio (essendo codificate numericamente, sono di default riconosciute da R come quantitative anche se per il ricercatore non lo sono): HYP <- factor(hyp) # Considero la variabile hyp come qualitativa e le assegno il nome HYP. 134 SMOKE <- factor(smoke) # Considero la variabile smoke come qualitativa e le assegno il nome SMOKE. Le variabili considerate sono qualitative dicotomiche. Per testarne la significatività dell’associazione, bisogna applicare il test di significatività per l’associazione di due fenomeni (test di indipendenza), con: H0: phyp=SI|smoke=SI = phyp=SI|smoke=NO; H1: phyp=SI|smoke=SI ≠ phyp=SI|smoke=NO (test a due code: ipotesi alternativa bidirezionale). Innanzitutto è necessario creare un oggetto contenente la tabella 2×2 delle due variabili in esame: Tabella <- table (SMOKE, HYP); Tabella HYP SMOKE 1 1 194 2 96 2 16 21 Eseguo quindi il test di indipendenza: chisq.test (Tabella, correct = F) Pearson's Chi-squared test data: Tabella X-squared = 7.9896, df = 1, p-value = 0.004705 Ho una consistente evidenza contro H0 (p=0.005<0.05): phyp=SI|smoke=SI = phyp=SI|smoke=NO, per cui rifiuto l’ipotesi nulla H0 e affermo che esiste un’associazione significativa tra il fumo e l’ipertensione arteriosa. Punto b: Comunico al software la natura qualitativa delle variabili oggetto di studio (essendo codificate numericamente, sono di default riconosciute da R come quantitative anche se per il ricercatore non lo sono): SEX <- factor(sex) # Considero la variabile sex come qualitativa e le assegno il nome SEX. Tabulo le due variabili considerate: addmargins (table (SEX, SMOKE)) SEX 1 2 Sum SMOKE 1 2 91 78 119 39 210 117 Sum 169 158 327 Il comando addmargins() aggiunge le frequenze marginali alla tabella. Le fumatrici femmine sono 39 su un totale di 158 femmine presenti nel campione. 135 Dovendo fare inferenza su una proporzione (pfumatrici.femmine) ed essendo la numerosità campionaria > 30 soggetti, posso calcolare mediante approssimazione normale, un IC 90% su proporzione che sarà associato a un test Z con: H0: pfumatrici.femmine = ; H1: pfumatrici.femmine ≠ (test a due code: ipotesi alternativa bidirezionale). prop.test (39, 158, p = 0.20, alternative = "two.sided", correct = F, conf.level = 0.99) 1-sample proportions test without continuity correction data: 39 out of 158, null probability 0.2 X-squared = 2.1661, df = 1, p-value = 0.1411 alternative hypothesis: true p is not equal to 0.2 99 percent confidence interval: 0.1698814 0.3441949 sample estimates: p 0.2468354 La probabilità 0.20 ricade nell’IC 90% (0.169; 0.344) e quindi è una stima verosimile per la proporzione di donne fumatrici nella popolazione. Inoltre non ho evidenza contro H0: pfumatrici.femmine = (p=0.141>0.05) e quindi non la posso rifiutare in un test a due code. Punto c: Comunico al software la natura qualitativa delle variabili oggetto di studio (essendo codificate numericamente, sono di default riconosciute da R come quantitative anche se per il ricercatore non lo sono): HYPERCO <- factor(hypercho) # Considero qualitativa e le assegno il nome HYPERCO. la variabile hypercho come Creo un oggetto contenente la tabella 2×2 delle due variabili in esame: Tabella <- table (SMOKE, HYPERCO); Tabella HYPERCO SMOKE 1 2 1 166 44 2 84 33 Su 77 ipercolesterolemici presenti nel campione, 33 sono fumatori e 44 sono non fumatori. Dovendo fare inferenza sulla differenza di due proporzioni (pfumatori – pnon.fumatori) ed essendo la numerosità campionaria > 30 soggetti, posso eseguire un test di significatività mediante approssimazione normale e precisamente un test Z su differenza di proporzioni, con: H0: pfumatori – pnon.fumatori = ; H1: pfumatori – pnon.fumatori ≠ (test a due code: ipotesi alternativa bidirezionale). prop.test (Tabella, alternative = "two.sided", correct = F) 136 2-sample test for equality of proportions without continuity correction data: Tabella X-squared = 2.1955, df = 1, p-value = 0.1384 alternative hypothesis: two.sided 95 percent confidence interval: -0.02585098 0.17090593 sample estimates: prop 1 prop 2 0.7904762 0.7179487 Non ho nessuna evidenza contro H0 (p=0.1384>0.05): pfumatori – pnon.fumatori = per cui non rifiuto H0 e quindi non posso affermare che i fumatori hanno una probabilità maggiore di manifestare ipercolesterolemia (benché nel campione tale probabilità era maggiore: 0.28 (1-0.72) vs. 0.21 (10.79)) detach (dati) 137 Esercizio 3 Importare in R il dataset del file Metabolismo.csv e risolvere i seguenti punti: a) dopo aver controllato se la variabilità della colesterolemia totale tra i fumatori è uguale a quella tra i non fumatori, sapendo che i livelli medi di colesterolemia totale tra i primi non sono mai minori, verificare se sono più alti. La variabile coltot segue una distribuzione normale in entrambe le popolazioni di riferimento, b) verificare se gli uomini che praticano attività fisica hanno una glicemia media diversa di quella degli uomini che non la praticano. La variabile glicemia segue una distribuzione normale con 2 = 169 mg2/dl2 in entrambe le popolazioni di riferimento. Fornire quindi un IC 95% e la sua interpretazione, c) è raro che le donne abbiano una colesterolemia HDL media più bassa di quella degli uomini. E’ possibile affermare che la colesterolemia HDL media delle donne è più alta? La variabile HDL segue una distribuzione normale con 2 ignote e diverse in entrambe le popolazioni di riferimento. Calcolare quindi un intervallo di confidenza al 99% e da questo decidere se è possibile rifiutare un’ipotesi nulla H0: HDLdonne - HDLuomini = 3 mg/dl (formulare una ipotesi alternativa H1 bidirezionale) a un livello di significatività dell’1%. N.B. = i valori mancanti nel dataset sono codificati con n.n. Informazioni supplementari per l’esercizio 3: Legenda delle variabili presenti nel dataset: id = codice identificativo personale; azienda = azienda per cui ogni soggetto lavora; sesso = sesso [M = maschi, F = femmine]; età = età in anni; peso = peso in Kg; altezza = altezza in cm; BMI = Body Mass Index (BMI) in Kg/m2; esiti.BMI = valutazione del BMI [Sottopeso, Normopeso, Sovrappeso, Obeso]; addome = circonferenza addominale in cm; PAS = pressione arteriosa sistolica in mmHg; PAD = pressione arteriosa diastolica in mmHg; glicemia = glicemia in mg/dl; insulinemia = insulinemia in mU/l; tgl = trigliceridemia in mg/dl; coltot = colesterolemia totale in mg/dl; HDL = colesterolemia HDL in mg/dl; LDL = colesterolemia LDL in mg/dl; uricemia = uricemia in mg/dl; PCR = Proteina C Reattiva in mg/dl; fumo = fumo [Sì, No]; attività.fisica = attività fisica [Sì, No]; diabete.mellito = diabete mellito [Sì, No]. 138 Soluzione: Importo in R il dataset del file Metabolismo.csv, visualizzo i dati e le etichette delle variabili: Metabolismo <- read.csv2 (file.choose(), sep = ";", dec = ".", header = T, na.strings = "n.n.") head(Metabolismo) colnames(Metabolismo) importato # Ricavo i nomi delle variabili del dataset attach(Metabolismo) summary(Metabolismo[,2:22]) #statistiche di sintesi in maniera compatta, leggerle “con buon senso” Punto a: Dovendo fare inferenza statistica sulla variabilità del colesterolo per valutarne l’equivalenza nelle due popolazioni (fumatori e non), applico il test F per due campioni indipendenti, con: H0: fumatorinon.fumatori= 1; H1: fumatorinon.fumatori≠ 1 (test a due code: ipotesi alternativa biderezionale). Dapprima rendo logica la variabile fumo: assegno 1 alla categoria non fumatori e 0 alla fumatori: in questo modo la modalità 0 sarà sempre considerata “prima”, es. al numeratore del rapporto di varianze o come primo membro nella differenza di medie. FUMO<-1*(fumo=="No") var.test (coltot~FUMO, ratio = 1, alternative = "two.sided") F test to compare two variances data: coltot by FUMO F = 1.0726, num df = 566, denom df = 1719, p-value = 0.2984 alternative hypothesis: true ratio of variances is not equal to 1 95 percent confidence interval: 0.9398417 1.2297627 sample estimates: ratio of variances 1.072592 Verifico il valore del rapporto: var(coltot[fumo=="Sì"],na.rm=T) / var(coltot[fumo=="No"], na.rm=T) Comunque, in ogni caso, non ho nessuna evidenza (p=0.2984>0.05) contro H0: fumatorinon.fumatori= 1, per cui non rifiuto l’ipotesi nulla H0 e considero le due varianze uguali. 139 Ora, dovendo fare inferenza statistica sulla differenza tra medie (fumatorinon.fumatori) di due variabili casuali normali con 2 ignote ma uguali (appena verificato) e disponendo dei dati rilevati su due campioni, applico il test T per due campioni indipendenti, con: H0: fumatorinon.fumatori= 0 mg/dl; H1: fumatorinon.fumatori> 0 mg/dl (test a una coda: ipotesi alternativa unidirezionale). t.test (coltot~FUMO, mu = 0, var.equal = TRUE, alternative = "greater") Two Sample t-test data: coltot by FUMO t = 0.6027, df = 2285, p-value = 0.2734 alternative hypothesis: true difference in means is greater than 0 95 percent confidence interval: -1.792548 Inf sample estimates: mean in group 0 mean in group 1 200.3069 199.2709 Anche qui non ho nessuna evidenza (p=0.2734>0.05) contro H0: fumatorinon.fumatori= 0 mg/dl, per cui non rifiuto l’ipotesi nulla H0 e quindi il livello medio di colesterolo tra i fumatori non è significativamente più alto. Punto b: Creo due sottoinsiemi del dataset Metabolismo, ognuno dei quali corrisponde a una delle due popolazioni di riferimento: maschi.sportivi <- subset (Metabolismo, (Metabolismo$sesso == "M") & (Metabolismo$attività.fisica == "Sì")) # uomini che praticano attività fisica. maschi.sedentari <- subset (Metabolismo, (Metabolismo$sesso == "M") & (Metabolismo$attività.fisica == "No")) # uomini che non praticano attività fisica. Dovendo fare inferenza statistica sulla differenza tra medie (uomini.sportiviuomini.sedentari) di due variabili casuali normali con 2 note e uguali e disponendo dei dati rilevati su due campioni, applico il test Z per due campioni indipendenti, con: H0: maschi.sportivimaschi.sedentari= 0 mg/dl; H1: uomini.sportiviuomini.sedentari≠ 0 mg/dl (test a due code: ipotesi alternativa bidirezionale). library (BSDA) # Carico il pacchetto BSDA z.test (maschi.sportivi$glicemia, maschi.sedentari$glicemia, mu = 0, sigma.x = 13, sigma.y = 13, alternative = "two.sided", conf.level = 0.95) 140 Two-sample z-Test data: maschi.sportivi$glicemia and maschi.sedentari$glicemia z = -2.0855, p-value = 0.03702 alternative hypothesis: true difference in means is not equal to 0 95 percent confidence interval: -2.95835258 -0.09181371 sample estimates: mean of x mean of y 84.51705 86.04213 Ho una moderata evidenza (P= 0.037<0.05) contro H0: uomini.sportiviuomini.sedentari= 0 mg/dl, per cui rifiuto l’ipotesi nulla H0. I livelli medi di glicemia nelle due popolazioni non sono significativamente diversi. Punto c: Dapprima rendo logica la variabile sesso: assegno 1 alla categoria uomini e 0 alle donne: in questo modo la modalità 0 sarà sempre considerata “prima”, es. al numeratore del rapporto di varianze o come primo membro nella differenza di medie. SESSO<-1*(sesso=="M") Dovendo fare inferenza statistica sulla differenza tra medie (donneuomini) di due variabili casuali normali con 2 ignote e diverse e disponendo dei dati rilevati su due campioni, applico il test T per due campioni indipendenti, con: H0: donneuomini= 0 mg/dl; H1: donneuomini> 0 mg/dl (test a una coda: ipotesi alternativa unidirezionale). t.test (HDL~SESSO, mu = 0, var.equal = FALSE, alternative = "greater", conf.level = 0.95) Welch Two Sample t-test data: HDL by SESSO t = 23.463, df = 1367.54, p-value < 2.2e-16 alternative hypothesis: true difference in means is greater than 0 95 percent confidence interval: 12.23658 Inf sample estimates: mean in group 0 mean in group 1 62.88550 49.72573 Ho una decisiva evidenza (p<0.001) contro H0: donneuomini= 0 mg/dl, per cui rifiuto l’ipotesi nulla H0. I livelli di colesterolemia HDL sono significativamente più alti nelle donne. Calcolo ora l’intervallo di confidenza la 99%. t.test (HDL~SESSO, mu = 0, var.equal = FALSE, alternative = "two.sided", conf.level = 0.99) 141 Welch Two Sample t-test data: HDL by SESSO t = 23.463, df = 1367.54, p-value < 2.2e-16 alternative hypothesis: true difference in means is not equal to 0 99 percent confidence interval: 11.71303 14.60650 sample estimates: mean in group 0 mean in group 1 62.88550 49.72573 Con un livello di confidenza del 99% è verosimile affermare che le donne hanno un livello di colesterolemia HDL maggiore degli uomini e che tale differenza va da 11.71303 mg/dl a 14.6065 mg/dl. In altri termini, c’è una probabilità del 99% che l’intervallo di valori da 11.71303 mg/dl a 14.6065 mg/dl contenga la vera medie delle differenza. Inoltre siccome il valore di H0=3 non è contenuto nell’IC 99% posso rifiutarlo automaticamente a un livello di significatività dell’1% poiché l’IC contiene tutti i valori di ipotesi nulla che non vengono rifiutati da un test a due code con un livello di significatività 100%-99% (si ricordi che il livello di significatività è uguale al complemento a 100 del livello di confidenza). 142 Esercizio 4 Considerando solo i primi 25 soggetti del dataset stabilire se una regolare attività fisica influenza il livello plasmatico di colesterolo HDL. Soluzione: Dapprima rendo logica la variabile attività fisica: assegno 1 se il soggetto non la pratica e 0 altrimenti: in questo modo la modalità 0 sarà sempre considerata “prima”, es. al numeratore del rapporto di varianze o come primo membro nella differenza di medie. AF<-1*( attività.fisica=="No") Avendo una numerosità campionaria < 30, non è possibile applicare un test di ipotesi parametrico. La variabile HDL è continua, stiamo considerando due popolazioni e quindi è possibile fare inferenza statistica sull’uguaglianza delle distribuzioni () di due variabili casuali attraverso la mediana (X0.5); applicando il test U di Mann-Whitney, con: H0: sportivisedentari; → spX0.5 = seX0.5; H1: spX0.5 ≠ seX0.5 (test a due code: ipotesi alternativa bidirezionale). library(exactRankTests) wilcox.exact(HDL[1:25]~AF[1:25]) Exact Wilcoxon rank sum test data: HDL[1:25] by AF[1:25] W = 74, p-value = 0.3824 alternative hypothesis: true mu is not equal to 0 Non c’è nessuna evidenza (p=0.3824) contro H0: sportivisedentari → spX0.5 = seX0.5 per cui non rifiuto l’ipotesi nulla H0. Le mediane e quindi le due distribuzioni sono uguali: l’attività fisica non influenza il livello plasmatico di colesterolo HDL. 143 Esercizio 5 Importare in R il dataset del file Dieta.csv relativo alla glicemia (mg/dl) misurata in 42 soggetti prima (tempo 0) e dopo (tempo 1) una dieta ipocalorica di 30 giorni. Stabilire se al tempo 0 la glicemia media del campione è più alta di quella al tempo 1 (ipotesi alternativa H1). Nella popolazione di riferimento, la glicemia segue una distribuzione normale con varianza ignota ma uguale nelle due misurazioni (tempo 0 e tempo 1). Calcolare un IC 95% e interpretarlo. N. B.: i valori mancanti nel dataset sono codificati con n.n. Soluzione: Importo in R il dataset del file Dieta.csv, visualizzo i dati e le etichette delle variabili ed eseguo l’attach(): Dieta <- read.csv2 (file.choose(), sep = ";", dec = ".", header = T, na.strings = "n.n.") fix(Dieta) # Visualizzo i dati con un editor di R “user-friendly”. colnames(Dieta) # Ricavo i nomi delle variabili del dataset importato. attach (Dieta) Dovendo fare inferenza statistica sulla differenza tra medie (prima dopo) di due variabili casuali normali con ignoti ma uguali e disponendo dei dati rilevati in uno stesso campione prima e dopo un trattamento, applico il test T per due campioni appaiati, con H0: prima dopo = 0 mg/dl; H1: prima dopo > 0 mg/dl (test a una coda: ipotesi alternativa unidirezionale). t.test (glicemia~tempo, mu = 0, alternative = "greater", paired = T, conf.level = 0.95) Paired t-test data: glicemia by tempo t = 8.3007, df = 41, p-value = 1.285e-10 alternative hypothesis: true difference in means is greater than 0 95 percent confidence interval: 72.11405 Inf sample estimates: mean of the differences 90.45238 Ho una decisiva evidenza (p<0.001) contro H0: prima dopo = 0 mg/dl, per cui rifiuto l’ipotesi nulla H0. La dieta ipocalorica funziona (media delle differenze = +90.4523) e produce una significativa diminuzione dei livelli medi di glicemia. 144 Ora calcolo l’IC 95%: t.test (glicemia~tempo, mu = 0, alternative = "two.sided", paired = T, conf.level = 0.95) Paired t-test data: glicemia by tempo t = 8.3007, df = 41, p-value = 2.57e-10 alternative hypothesis: true difference in means is not equal to 0 95 percent confidence interval: 68.44543 112.45933 sample estimates: mean of the differences 90.45238 Con un livello di confidenza del 95% è verosimile affermare che la dieta fa diminuire il livello medio di glicemia da 112.5 a 68.4 mg/dl. In altri termini, c’è una probabilità del 95% che l’intervallo di valori da 68.4 mg/dl a 112.5 mg/dl contenga la vera media delle differenze. Inoltre l’IC 95% contiene tutti quei valori di ipotesi nulla che non vengono rifiutati da un test a due code a un livello di significatività del 5%. detach (Dieta) 145 Esercitazione 3 Analisi della varianza (ANOVA), regressione lineare e correlazione Schema riassuntivo: Variabile di risposta (y) Quantitativa continua Quantitativa continua Quantitativa continua Quantitativa continua o qualitativa ordinale Variabile esplicativa (x) Qualitativa Tipo di relazione MODELLO Causale Quantitativa continua Quantitativa continua Quantitativa continua o qualitativa ordinale Causale *Analisi della varianza (ANOVA) *Regressione lineare *Correlazione di Pearson Simmetrica Simmetrica Correlazione di Spearman * = Ipotesi di normalità Sommario: 1) 2) 3) 4) 5) 6) 7) analisi della varianza -ANOVA- a una via, confronti multipli secondo Tukey, analisi della varianza -ANOVA- non parametrica a una via: test di Kruskal-Wallis, analisi della varianza -ANOVA- a una via con blocchi, analisi della varianza -ANOVA- a due vie con repliche e interazione, modello di regressione lineare semplice, correlazione (Pearson e Spearman). 146 Esercizio 1 (Analisi della varianza -ANOVA- a una via) Miller e Vanhoutte hanno condotto una ricerca sperimentale su un campione di 18 cani femmine adulte a cui erano state precedentemente asportate le ovaie (ovariectomizzate). I 18 cani del campione sono stati casualmente assegnati a uno dei quattro trattamenti previsti dalla sperimentazione: trattamento 1 (controllo, cioè nessun trattamento), trattamento 2 (estrogeni), trattamento 3 (progesterone) e trattamento 4 (estrogeni + progesterone). I dati della sperimentazione sono raccolti nel dataset del file anova1_1.csv. Determinare se i trattamenti hanno o meno effetti diversi sulla concentrazione sierica di progesterone espressa in ng/dl (variabile risposta). Soluzione: Importo in R il dataset anova1_1.csv, ne visualizzo un estratto, le dimensioni (numero di righe, numero di colonne) e le etichette delle variabili: data_estrogeni <- read.csv2 (file.choose(), header = TRUE, sep = ";", dec = ",", na.strings = " ") head (data_estrogeni) 1 2 3 4 5 6 un..sperimentale 1 2 3 4 5 6 risposta 117 124 40 88 40 440 trattamento 1 1 1 1 1 2 dim (data_estrogeni) [1] 18 3 colnames (data_estrogeni) [1] "un..sperimentale" "risposta" "trattamento" Per il ricercatore, la variabile trattamento è una variabile qualitativa. Essendo però codificata numericamente, R la interpreta di default come una variabile quantitativa. Devo quindi creare, all’interno del data.frame importato, la variabile qualitativa TRATTAMENTO, allo scopo di comunicare al software la natura qualitativa della variabile originaria: data_estrogeni$TRATTAMENTO <- factor (data_estrogeni$trattamento) Eseguo poi l’attach() del del data.frame importato: attach (data_estrogeni) 147 Visualizzo le statistiche di sintesi delle variabili risposta e TRATTAMENTO: summary (risposta) # Capisco che risposta è una variabile quantitativa continua, perché il comando summary(risposta) fornisce il valore del minimo, del massimo, del primo e del terzo quartile, della mediana e della media della variabile stessa. Min. 40.0 1st Qu. 127.0 Median 412.5 Mean 848.2 3rd Qu. 1312.0 Max. 3584.0 summary (TRATTAMENTO) # Capisco che TRATTAMENTO è una variabile qualitativa, perché il comando summary restituisce le frequenze assolute di ogni modalità assunta dalla variabile stessa. 1 5 2 4 3 4 4 5 Visualizzo graficamente (mediante un boxplot e un violinplot affiancati) le variabili risposta e TRATTAMENTO: par (mfrow = c(1,2)) # Divido la finestra grafica in due settori. plot (TRATTAMENTO,risposta) install.packages("vioplot") # Installo il pacchetto vioplot. library (vioplot) # Carico il pacchetto appena installato. vioplot (risposta [TRATTAMENTO == 1], risposta [TRATTAMENTO == 2], risposta [TRATTAMENTO == 3], risposta [TRATTAMENTO == 4], names = c("1","2","3","4")) 148 Graficamente, le quattro distribuzioni appaiono approssimativamente simmetriche e non uguali in mediana: in particolare il gruppo 4 fa riscontrare valori nettamente superiori a quelli degli altri gruppi. La variabilità tra i gruppi sembra diversa. Ho dunque a che fare con una variabile di risposta (risposta) quantitativa continua e una variabile esplicativa (TRATTAMENTO) qualitativa. Lo sperimentatore suppone che le due variabili siano in relazione causale (TRATTAMENTO risposta) e quindi, per analizzarle, posso applicare il modello di analisi della varianza (ANOVA). In particolare, avendo un’unica variabile esplicativa, applico il modello di analisi della varianza (ANOVA) a una via, con: H0: μ1 = μ2 = μ3 = μ4 (la concentrazione sierica media di progesterone è uguale per tutti i quattro trattamenti), H1: μ1 ≠ μ2 ≠ μ3 ≠ μ4 (non tutte le μk sono uguali, almeno un trattamento dà una risposta media diversa). anova (lm(risposta ~ TRATTAMENTO)) Analysis of Variance Table Response: risposta Df Sum Sq Mean Sq F value Pr(>F) TRATTAMENTO 3 15865083 5288361 27.364 4.089e-06 *** Residuals 14 2705585 193256 --Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Alternativamente posso usare i seguenti comandi: aov (lm(risposta ~ TRATTAMENTO)) Call: aov(formula = lm(risposta ~ TRATTAMENTO)) Terms: Sum of Squares Deg. of Freedom TRATTAMENTO Residuals 15865083 2705585 3 14 Residual standard error: 439.609 Estimated effects may be unbalanced summary (aov (lm(risposta ~ TRATTAMENTO))) Df Sum Sq Mean Sq F value Pr(>F) TRATTAMENTO 3 15865083 5288361 27.36 4.09e-06 *** Residuals 14 2705585 193256 --Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 149 Il p-value è pari a 4.09 ∙ 106, cioè è < 0.05, per cui rifiuto l’ipotesi nulla H0: μ1 = μ2 = μ3 = μ4 e posso affermare che almeno uno dei quattro trattamenti considerati determina diverse concentrazioni sieriche medie di progesterone. Verifico che siano rispettati i tre assunti necessari per l’applicazione dell’ANOVA. Eseguo dapprima una verifica qualitativa, eseguendo una diagnostica grafica del modello ANOVA applicato: par (mfrow settori. = c(2,2)) # Divido la finestra grafica in quattro plot (aov(lm(risposta ~ TRATTAMENTO))) Considerando soltanto la prima riga di grafici, dal primo grafico possiamo constatare che la media dei residui è approssimativamente pari a 0 e che l’omoschedasticità (uguale varianza dei residui tra gruppi) non sembra garantita dal trattamento 4 (ultima colonna di punti). Per quanto riguarda la distribuzione dei residui (secondo grafico) si può notare che quelli centrali seguono approssimativamente un andamento normale, mentre per le code c’è uno scostamento da tale ipotesi distributiva. 150 Eseguo quindi una diagnostica quantitativa dei tre assunti: 1) normalità dei residui entro gruppi: Verifico (quantitativamente) la normalità dei residui all’interno di ciascuno del quattro trattamenti dividendo in quattro gruppi i seguenti residui: resid (aov(lm(risposta ~ TRATTAMENTO))) # Visualizzo i residui per ogni unità statistica componente il campione. 1 2 3 4 5 6 7 8 35.20 42.20 -41.80 6.20 -41.80 174.75 -1.25 -44.25 9 -129.25 10 82.25 11 12 103.25 -137.75 13 -47.75 14 15 16 322.80 -263.20 1242.80 17 18 -801.20 -501.20 ovvero: shapiro.test (resid(aov(lm(risposta == "1"]) Shapiro-Wilk normality test ~ TRATTAMENTO)))[TRATTAMENTO data: resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO == "1"] W = 0.8451, p-value = 0.1794 shapiro.test (resid(aov(lm(risposta == "2"]) Shapiro-Wilk normality test ~ TRATTAMENTO)))[TRATTAMENTO data: resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO == "2"] W = 0.9489, p-value = 0.7096 shapiro.test (resid(aov(lm(risposta == "3"]) Shapiro-Wilk normality test ~ TRATTAMENTO)))[TRATTAMENTO data: resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO == "3"] W = 0.9065, p-value = 0.4641 shapiro.test (resid(aov(lm(risposta == "4"]) Shapiro-Wilk normality test ~ TRATTAMENTO)))[TRATTAMENTO data: resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO == "4"] W = 0.9289, p-value = 0.5889 151 L’ipotesi di normalità è confermata da tutti i quattro test. 2) omoschedasticità dei residui entro gruppi: install.packages("car") # Installo il pacchetto car. library(car) leveneTest (resid(aov(lm(risposta ~ TRATTAMENTO))), TRATTAMENTO) # Verifica quantitativa dell’omoschedasticità dei residui. Levene's Test for Homogeneity of Variance (center = median) Df F value Pr(>F) group 3 3.2539 0.05379 . 14 --Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Considerando un livello = 0.05, il test di Levene risulta ai limiti della significatività (p-value = 0.053), come era possibile apprezzare qualitativamente osservando i violinplot. Tuttavia è possibile affermare che siamo in presenza di omoschedasticità. 3) indipendenza dei residui entro gruppi: install.packages("lmtest") # Installo il pacchetto lmtest. library(lmtest) dwtest (aov(lm(risposta ~ TRATTAMENTO))) # Verifica quantitativa dell’indipendenza dei residui. Durbin-Watson test data: aov(lm(risposta ~ TRATTAMENTO)) DW = 2.671, p-value = 0.7862 alternative hypothesis: true autocorrelation is greater than 0 Anche in questo caso, non è possibile rifiutare l’ipotesi nulla di incorrelazione tra i residui. Quindi anche il terzo assunto (indipendenza dei residui) risulta valido. I tre assunti sono rispettati e quindi il risultato dell’ANOVA “Il p-value è pari a 4.09 ∙ 106, cioè è < 0.05, per cui rifiuto l’ipotesi nulla H0: μ1 = μ2 = μ3 = μ4 e posso affermare che almeno uno dei quattro trattamenti considerati determina diverse concentrazioni sieriche medie di progesterone” è valido. 152 Esercizio 2 (Confronti multipli secondo Tukey) Con l’analisi della varianza (ANOVA) a una via applicata ai dati dell’esercizio 1 abbiamo ottenuto un p-value < 0.05 e quindi abbiamo potuto affermare che almeno uno dei quattro trattamenti considerati ha effetti diversi sulla concentrazione sierica di progesterone espressa in ng/dl (variabile risposta). Determinare quale/i dei quattro trattamenti ha/hanno reso significativa l’ANOVA, cioè quale/i ha/hanno un effetto diverso rispetto agli altri sulla concentrazione sierica di progesterone. Soluzione: Riprendiamo il modello di analisi della varianza (ANOVA) a una via applicato ai dati dell’esercizio 1, assegnandogli il nome anova.estrogeni: anova.estrogeni <- aov (lm(risposta ~ TRATTAMENTO)) anova.estrogeni Call: aov(formula = lm(risposta ~ TRATTAMENTO)) Terms: Sum of Squares Deg. of Freedom TRATTAMENTO Residuals 15865083 2705585 3 14 Residual standard error: 439.609 Estimated effects may be unbalanced …e confrontiamo i trattamenti due a due mediante i confronti multipli secondo Tukey, con: H0(2-1): 2 = 1 vs. H1(2-1): 2 ≠ 1; H0(3-1): 3 = 1 vs. H1(3-1): 3 ≠ 1; H0(4-1): 4 = 1 vs. H1(4-1): 4 ≠ 1; H0(3-2): 3 = 2 vs. H1(3-2): 3 ≠ 2; H0(4-2): 4 = 2 vs. H1(4-2): 4 ≠ 2; H0(4-3): 4 = 3 vs. H1(4-3): 4 ≠ 3. 153 TukeyHSD (anova.estrogeni) Tukey multiple comparisons of means 95% family-wise confidence level Fit: aov(formula = lm(risposta ~ TRATTAMENTO)) $TRATTAMENTO diff 2-1 183.45 3-1 440.95 4-1 2259.40 3-2 257.50 4-2 2075.95 4-3 1818.45 lwr -673.6928 -416.1928 1451.2781 -646.0078 1218.8072 961.3072 upr 1040.593 1298.093 3067.522 1161.008 2933.093 2675.593 p adj 0.9232880 0.4658803 0.0000061 0.8401641 0.0000311 0.0001282 Otteniamo p-values < 0.05 solo nei confronti in cui è presente il trattamento 4, per cui possiamo rifiutare solo le ipotesi nulle concernenti il trattamento 4, vale a dire H0(4-1): 4 = 1, H0(4-2): 4 = 2 e H0(4-3): 4 = 3. Possiamo quindi concludere che l’ANOVA applicata ai dati dell’esercizio 1 è stata resa significativa dal trattamento 4. Il trattamento 4 ha un effetto diverso rispetto agli altri sulla concentrazione sierica di progesterone. Visualizzo graficamente i risultati: plot (TukeyHSD(anova.estrogeni)) Possiamo vedere che i confronti in cui è presente il gruppo 4 fanno sempre emergere la significatività (rispetto a un livello = 0.05). detach (data_estrogeni) # Disattivo il comando attach (). rm (list = objects()) # nell’area di lavoro di R. Cancello tutti gli oggetti presenti 154 Esercizio 3 (Analisi della varianza -ANOVA- non parametrica a una via: test di Kruskal-Wallis) Altri ricercatori hanno condotto una ricerca sperimentale analoga a quella di Miller e Vanhoutte su un campione di 120 cani femmine adulte a cui erano state precedentemente asportate le ovaie (ovariectomizzate). I 120 cani del campione sono stati casualmente assegnati a uno dei quattro trattamenti previsti dalla sperimentazione: trattamento 1 (controllo, cioè nessun trattamento), trattamento 2 (estrogeni), trattamento 3 (progesterone) e trattamento 4 (estrogeni + progesterone). I dati della sperimentazione sono raccolti nel dataset del file data_KW.csv. Determinare se i trattamenti hanno o meno effetti diversi sulla concentrazione sierica di progesterone espressa in ng/dl (variabile risposta). Soluzione: Importo in R il dataset data_KW.csv, ne visualizzo un estratto, le dimensioni (numero di righe, numero di colonne) e le etichette delle variabili: data_KW <- read.csv2 (file.choose(), header = TRUE, sep = ";", dec = ",", na.strings = " ") head (data_KW) 1 2 3 4 5 6 unità 1 2 3 4 5 6 trattamento 1 1 1 1 1 1 risposta 795.2401 776.7010 697.1153 803.2520 808.8335 751.3667 dim (data_KW) [1] 120 3 colnames (data_KW) [1] "unità" "trattamento" "risposta" Per il ricercatore, la variabile trattamento è una variabile qualitativa. Essendo però codificata numericamente, R la interpreta di default come una variabile quantitativa. Devo quindi creare, all’interno del data.frame importato, la variabile qualitativa TRATTAMENTO, allo scopo di comunicare al software la natura qualitativa della variabile originaria: data_KW$TRATTAMENTO <- factor (data_KW$trattamento) 155 Eseguo poi l’attach() del del data.frame importato: attach (data_KW) Visualizzo le statistiche di sintesi delle variabili risposta e TRATTAMENTO: summary (risposta) # Capisco che risposta è una variabile quantitativa continua, perché il comando summary(risposta) fornisce il valore del minimo, del massimo, del primo e del terzo quartile, della mediana e della media della variabile stessa. Min. 2.473 1st Qu. 551.600 Median 749.700 Mean 617.900 3rd Qu. 849.700 Max. 972.000 summary (TRATTAMENTO) # Capisco che TRATTAMENTO è una variabile qualitativa, perché il comando summary restituisce le frequenze assolute di ogni modalità assunta dalla variabile stessa. 1 30 2 30 3 30 4 30 Ho dunque a che fare con una variabile di risposta (risposta) quantitativa continua e una variabile esplicativa (TRATTAMENTO) qualitativa. Lo sperimentatore suppone che le due variabili siano in relazione causale (TRATTAMENTO risposta) e quindi, per analizzarle, posso applicare il modello di analisi della varianza (ANOVA). In particolare, avendo un’unica variabile esplicativa, applico il modello di analisi della varianza (ANOVA) a una via, con: H0: μ1 = μ2 = μ3 = μ4 (la concentrazione sierica media di progesterone è uguale per tutti i quattro trattamenti), H1: μ1 ≠ μ2 ≠ μ3 ≠ μ4 (non tutte le μk sono uguali, almeno un trattamento dà una risposta media diversa). anova (lm(risposta ~ TRATTAMENTO)) Analysis of Variance Table Response: risposta Df Sum Sq Mean Sq F value Pr(>F) TRATTAMENTO 3 11950757 3983586 1270.1 < 2.2e-16 *** Residuals 116 363837 3137 --Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Finora abbiamo applicato l’ANOVA a una via come nell’esercizio 1. 156 Ora passiamo direttamente alla verifica dell’assunzione di normalità: normalità dei residui entro gruppi: shapiro.test == "1"]) (resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO Shapiro-Wilk normality test data: resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO == "1"] W = 0.959, p-value = 0.2922 shapiro.test == "2"]) (resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO Shapiro-Wilk normality test data: resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO == "2"] W = 0.967, p-value = 0.461 shapiro.test == "3"]) (resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO Shapiro-Wilk normality test data: resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO == "3"] W = 0.981, p-value = 0.8515 shapiro.test == "4"]) (resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO Shapiro-Wilk normality test data: resid(aov(lm(risposta ~ TRATTAMENTO)))[TRATTAMENTO == "4"] W = 0.7533, p-value = 1.03e-05 L’ipotesi di normalità non è confermata per tutti i quattro gruppi. Applichiamo quindi un’ANOVA non parametrica a una via, cioè il test di Kruskal-Wallis con: H0: Med1 = Med2 = Med3 = Med4 (la concentrazione sierica “mediana” di progesterone è uguale per tutti i quattro trattamenti), H1: Med1 ≠ Med2 ≠ Med3 ≠ Med4 (non tutte le Medk sono uguali, almeno un trattamento dà una risposta “mediana” diversa). kruskal.test (risposta ~ TRATTAMENTO) 157 Kruskal-Wallis rank sum test data: risposta by TRATTAMENTO Kruskal-Wallis chi-squared = 109.4817, df = 3, p-value < 2.2e-16 Il p-value è pari a 2.2 ∙ 1016, cioè < 0.05, per cui rifiuto l’ipotesi nulla H0: Med1 = Med2 = Med3 = Med4 e posso affermare che i quattro trattamenti considerati hanno effetti diversi sulla concentrazione sierica “mediana” di progesterone. 158 Esercizio 4 (Analisi della varianza -ANOVA- a una via) Azoulay e Dupuis hanno condotto una ricerca sperimentale su un campione di 20 topi femmina infettati da Streptococcus pneumoniae, allo scopo di studiare l’efficacia di cinque farmaci per debellare l’infezione polmonare sostenuta da questo batterio. I 20 topi del campione sono stati casualmente assegnati a uno dei sei trattamenti previsti dalla sperimentazione: trattamento 1 (controllo, cioè nessun trattamento), trattamento 2 (Amoxicillina: iniezione di 50 mg/kg), trattamento 3 (Eritromicina: iniezione di 50 mg/kg), trattamento 4 (Temafloxacina: iniezione di 50 mg/kg), trattamento 5 (Ofloxacina: iniezione di 100 mg/kg) e trattamento 6 (Ciprofoloxacina: iniezione di 100 mg/kg). I dati della sperimentazione sono raccolti nel dataset del file anova1_2.csv. Determinare se i trattamenti hanno o meno effetti diversi sul numero di batteri nelle vie aeree espresso in Log cfu/ml di polmone omogeneizzato (variabile risposta). Soluzione: Importo in R il dataset anova1_2.csv, ne visualizzo un estratto, le dimensioni (numero di righe, numero di colonne) e le etichette delle variabili: data_topi <- read.csv2 (file.choose(), header = TRUE, sep = ";", dec = ",", na.strings = " ") # Importa dataset "anova1_2.csv" head (data_topi) 1 2 3 4 5 6 un..sperimentale 1 2 3 4 5 6 risposta 8.8 8.6 8.1 8.4 8.8 2.6 trattamento 1 1 1 1 1 2 dim (data_topi) [1] 20 3 Per il ricercatore, la variabile trattamento è una variabile qualitativa. Essendo però codificata numericamente, R la interpreta di default come una variabile quantitativa. Devo quindi creare, all’interno del data.frame importato, la variabile qualitativa TRATTAMENTO, allo scopo di comunicare al software la natura qualitativa della variabile originaria: data_topi$TRATTAMENTO <- factor (data_topi$trattamento) Eseguo poi l’attach() del del data.frame importato: attach (data_topi) 159 Visualizzo le statistiche di sintesi delle variabili risposta e TRATTAMENTO: summary (risposta) # Capisco che risposta è una variabile quantitativa continua, perché il comando summary(risposta) fornisce il valore del minimo, del massimo, del primo e del terzo quartile, della mediana e della media della variabile stessa. Min. 2.600 1st Qu. 2.600 Median 4.950 Mean 5.254 3rd Qu. 7.920 Max. 8.800 summary (TRATTAMENTO) # Capisco che TRATTAMENTO è una variabile qualitativa, perché il comando summary restituisce le frequenze assolute di ogni modalità assunta dalla variabile stessa. 1 5 2 3 3 3 4 3 5 3 6 3 Visualizzo graficamente (mediante un boxplot e un violinplot affiancati) le variabili risposta e TRATTAMENTO: par (mfrow = c(1,2)) # Divido la finestra grafica in due settori. plot (TRATTAMENTO,risposta) install.packages("vioplot") # Installo il pacchetto vioplot. library (vioplot) # Carico il pacchetto appena installato. vioplot (risposta [TRATTAMENTO == 1], risposta [TRATTAMENTO == 2], risposta [TRATTAMENTO == 3], risposta [TRATTAMENTO == 4], risposta [TRATTAMENTO == 5], risposta [TRATTAMENTO == 6], names = c("1","2","3","4","5","6")) Graficamente, le quattro distribuzioni appaiono non simmetriche e non uguali in mediana. La variabilità tra i gruppi sembra diversa. 160 Ho dunque a che fare con una variabile di risposta (risposta) quantitativa continua e una variabile esplicativa (TRATTAMENTO) qualitativa. Lo sperimentatore suppone che le due variabili siano in relazione causale (TRATTAMENTO risposta) e quindi, per analizzarle, posso applicare il modello di analisi della varianza (ANOVA). In particolare, avendo un’unica variabile esplicativa, applico il modello di analisi della varianza (ANOVA) a una via, con: H0: μ1 = μ2 = μ3 = μ4 = μ5 = μ6 (il numero medio di batteri nelle vie aeree è uguale per tutti i quattro trattamenti), H1: μ1 ≠ μ2 ≠ μ3 ≠ μ4 ≠ μ5 ≠ μ6 (non tutte le μk sono uguali, almeno un trattamento dà una risposta media diversa). anova (lm(risposta ~ TRATTAMENTO)) Analysis of Variance Table Response: risposta Df Sum Sq Mean Sq F value Pr(>F) TRATTAMENTO 5 126.901 25.3802 41.19 6.916e-08 *** Residuals 14 8.626 0.6162 --Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Il p-value è pari a 6.916 ∙ 108, cioè è < 0.05, per cui rifiuto l’ipotesi nulla H0: μ1 = μ2 = μ3 = μ4 = μ5 = μ6 e posso affermare che i sei trattamenti considerati hanno effetti diversi sul numero medio di batteri nelle vie aeree. detach(data_topi) 161 Esercizio 5 (Analisi della varianza -ANOVA- a una via con blocchi) E’ stato condotto un esperimento su un campione di 10 soggetti per saggiare gli effetti di quattro farmaci (trattamenti) diversi sul tempo di coagulazione del sangue (in minuti). Ogni soggetto corrisponde a un blocco (variabile blocco). Il campione di sangue di ogni soggetto è stato diviso in quattro sotto-campioni uguali: i quattro sotto-campioni sono stati destinati a caso ad essere saggiati con uno dei quattro trattamenti considerati (variabile trattamento), in modo tale che, all’interno di ogni blocco, fossero testati tutti i quattro trattamenti. I dati dell’esperimento sono raccolti nel dataset del file anova1_4 BLOCCO.csv. I quattro farmaci testati hanno effetti differenti sul tempo di coagulazione del sangue espresso in minuti (variabile risposta)? Soluzione: Importo in R il dataset anova1_4 BLOCCO.csv, ne visualizzo un estratto, le dimensioni (numero di righe, numero di colonne) e le etichette delle variabili: data_coagulazione <- read.csv2 (file.choose(), header = TRUE, sep = ";", dec = ",", na.strings = " ") head (data_coagulazione) 1 2 3 4 5 6 blocco risposta trattamento 1 1.5 1 2 1.4 1 3 1.8 1 4 1.3 1 5 2.0 1 6 1.1 1 dim (data_coagulazione) [1] 40 3 colnames (data_coagulazione) [1] "blocco" "risposta" "trattamento" Per il ricercatore, le variabili blocco e trattamento sono variabili qualitative. Essendo però codificate numericamente, R le interpreta di default come variabili quantitative. Devo quindi creare, all’interno del data.frame importato, le variabili qualitative BLOCCO e TRATTAMENTO, allo scopo di comunicare al software la natura qualitativa delle variabili originarie: 162 data_coagulazione$BLOCCO <- factor (data_coagulazione$blocco) data_coagulazione$TRATTAMENTO <- factor (data_coagulazione$trattamento) Eseguo poi l’attach() del del data.frame importato: attach (data_coagulazione) Visualizzo le statistiche di sintesi delle variabili BLOCCO, TRATTAMENTO e risposta: summary (BLOCCO) # Capisco che BLOCCO è una variabile qualitativa, perché il comando summary restituisce le frequenze assolute di ogni modalità assunta dalla variabile stessa. 1 2 3 4 5 6 7 8 9 10 4 4 4 4 4 4 4 4 4 4 summary (TRATTAMENTO) # Capisco che TRATTAMENTO è una variabile qualitativa, perché il comando summary restituisce le frequenze assolute di ogni modalità assunta dalla variabile stessa. 1 2 3 4 10 10 10 10 summary (risposta) # Capisco che risposta è una variabile quantitativa continua, perché il comando summary(risposta) fornisce il valore del minimo, del massimo, del primo e del terzo quartile, della mediana e della media della variabile stessa. Min. 1.000 1st Qu. 1.300 Median 1.500 Mean 1.535 3rd Qu. 1.700 Max. 2.300 Ho dunque a che fare con una variabile di risposta (risposta) quantitativa continua, una variabile esplicativa (TRATTAMENTO) qualitativa e una variabile qualitativa di blocco (BLOCCO). Lo sperimentatore suppone che le prime due variabili siano in relazione causale (TRATTAMENTO risposta) e quindi, per analizzarle, posso applicare il modello di analisi della varianza (ANOVA). In particolare, avendo un’unica variabile esplicativa e una di blocco, applico il modello di analisi della varianza (ANOVA) a una via con blocchi, con: H0: 1 = 2 = 3 = 4 = 0 (gli scostamenti dei trattamenti dalla media complessiva sono uguali e nulli → gli effetti dei trattamenti sono uguali e nulli), H1: 1 ≠ 2 ≠ 3 ≠ 4 ≠ 0 (non tutti le τ j sono uguali, almeno uno scostamento dalla media complessiva è diverso → almeno un trattamento dà una risposta media diversa). 163 anova (lm(risposta ~ TRATTAMENTO + BLOCCO)) Analysis of Variance Table Response: risposta Df Sum Sq Mean Sq F value Pr(>F) TRATTAMENTO 3 0.363 0.12100 14.392 8.568e-06 *** BLOCCO 9 3.341 0.37122 44.154 7.547e-14 *** Residuals 27 0.227 0.00841 --Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Il p-value relativo alla variabile TRATTAMENTO è pari a 8.568 ∙ 106, cioè è < 0.05, per cui rifiuto l’ipotesi nulla H0: 1 = 2 = 3 = 4 = 0 e posso affermare che gli effetti dei trattamenti non sono uguali e nulli. L’ipotesi nulla e il P-value relativi alla variabile BLOCCO non vengono considerati, poiché tale variabile è meramente strumentale ed è inserita nel disegno dello studio solo per controllare a priori una fonte di variabilità che può agire sulla variabile risposta e confondere i risultati relativamente alla variabile TRATTAMENTO. detach(data_coagulazione) 164 Esercizio 6 (Analisi della varianza -ANOVA- a due vie con repliche e interazione) Il valore nutritivo di un certo frutto commestibile è stato valutato su un campione di 72 esemplari del frutto in esame. I 72 frutti del campione appartengono a quattro varietà diverse (variabile varietà), provenienti da tre zone geografiche distinte (variabile zona): ogni zona geografica ha fornito 6 esemplari di frutto per ogni varietà. Determinare, tenendo conto dell’interazione tra le variabili zona e varietà, se le diverse zone geografiche e le diverse varietà hanno o meno effetti diversi sulla concentrazione di polveri sottili nei frutti espressa in ppm (variabile risposta). Soluzione: Importo in R il dataset anova2_1R.csv, ne visualizzo un estratto, le dimensioni (numero di righe, numero di colonne) e le etichette delle variabili: data_frutti <- read.csv2 (file.choose(), header = TRUE, sep = ";", dec = ",", na.strings = " ") head(data_frutti) 1 2 3 4 5 6 zona 1 1 1 1 1 1 risposta 6.9 11.8 6.2 9.2 9.2 6.2 varietà 1 1 1 1 1 1 dim(data_frutti) [1] 72 3 colnames(data_frutti) [1] "zona" "risposta" "varietà" Per il ricercatore, le variabili zona e varietà sono variabili qualitative. Essendo però codificate numericamente, R le interpreta di default come variabili quantitative. Devo quindi creare, all’interno del data.frame importato, le variabili qualitative ZONA e VARIETà, allo scopo di comunicare al software la natura qualitativa delle variabili originarie: data_frutti$ZONA <- factor (data_frutti$zona) data_frutti$VARIETà <- factor (data_frutti$varietà) 165 Eseguo poi l’attach() del del data.frame importato: attach (data_frutti) Visualizzo le statistiche di sintesi delle variabili ZONA, VARIETà e risposta: summary (ZONA) # Capisco che ZONA è una variabile qualitativa, perché il comando summary restituisce le frequenze assolute di ogni modalità assunta dalla variabile stessa. 1 24 2 24 3 24 summary (VARIETà) # Capisco che VARITETà è una variabile qualitativa, perché il comando summary restituisce le frequenze assolute di ogni modalità assunta dalla variabile stessa. 1 18 2 18 3 18 4 18 summary (risposta) # Capisco che risposta è una variabile quantitativa continua, perché il comando summary(risposta) fornisce il valore del minimo, del massimo, del primo e del terzo quartile, della mediana e della media della variabile stessa. Min. 5.000 1st Qu. 7.075 Median 9.200 Mean 9.457 3rd Qu. 12.100 Max. 14.100 Grafico un interaction plot: interaction.plot (VARIETà, ZONA, risposta, fixed = TRUE, col = c ("red", "green", "blue", "black")) 166 Ho dunque a che fare con una variabile di risposta (risposta) quantitativa continua e due variabili esplicative (ZONA e VARIETà) qualitative che interagiscono (:) tra loro. Lo sperimentatore suppone che le due variabili esplicative e la loro interazione siano in relazione causale con la variabile di risposta (ZONA, VARIETà, ZONA:VARIETà risposta) e quindi, per analizzarle, posso applicare il modello di analisi della varianza (ANOVA). In particolare, avendo due variabili esplicative che interagiscono tra loro, applico il modello di analisi della varianza (ANOVA) a due vie con repliche e interazione, con: H0(VARIETà): 1 = 2 = 3 = 4 = 0 (gli effetti della variabile varietà sulla concentrazione media di polveri sottili nei frutti sono uguali e nulli per tutte le quattro varietà), H1(VARIETà): 1 ≠ 2 ≠ 3 ≠ 4 ≠ 0 (non tutti gli effetti sono uguali, almeno una varietà ha un effetto diverso sulla concentrazione media di polveri sottili nei frutti); e con: H0(ZONA): 1 = 2 = 3 = 0 (gli effetti della variabile zona sulla concentrazione media di polveri sottili nei frutti sono uguali e nulli per tutte le tre zone geografiche), H1(ZONA): 1 ≠ 2 ≠ 3 ≠ 0 (non tutti gli effetti sono uguali, almeno una zona geografica ha un effetto diverso sulla concentrazione media di polveri sottili nei frutti); e con: H0(VARIETà:ZONA): 11 = 12 = … = ij = 0 (gli effetti congiunti di varietà e zona sulla concentrazione media di polveri sottili nei frutti sono uguali e nulli), H1(VARIETà:ZONA): 11 ≠ 12 ≠ … ≠ ij ≠ 0 (gli effetti congiunti di varietà e zona sulla concentrazione media di polveri sottili nei frutti sono diversi). anova (lm(risposta ~ VARIETà + ZONA + VARIETà:ZONA)) Analysis of Variance Table Response: risposta Df Sum Sq Mean Sq F value Pr(>F) VARIETà 3 325.57 108.525 37.7431 7.828e-14 ZONA 2 31.51 15.753 5.4788 0.006525 VARIETà:ZONA 6 33.17 5.529 1.9228 0.091676 Residuals 60 172.52 2.875 --Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 *** ** . ‘.’ 0.1 ‘ ’ 1 Il p-value relativo alla variabile VARIETà è pari a 7.828 ∙ 1014, cioè è < 0.05, per cui rifiuto l’ipotesi nulla H0(VARIETà): 1 = 2 = 3 = 4 = 0 e posso affermare che le quattro varietà considerate hanno effetti diversi sulla concentrazione media di polveri sottili nei frutti. Il p-value relativo alla variabile ZONA è pari a 0.006525, cioè è < 0.05, per cui rifiuto l’ipotesi nulla H0(ZONA): 1 = 2 = 3 = 0 e posso affermare che le tre zone considerate hanno effetti diversi sulla concentrazione media di polveri sottili nei frutti. Il p-value relativo all’interazione tra la variabile VARIETà e la variabile ZONA è pari a 0.091676, cioè è > 0.05, per cui non rifiuto l’ipotesi nulla H0(VARIETà:ZONA): 11 = 12 = … = ij = 0 e non posso affermare che le due variabili interagiscono nell’influenzare la concentrazione media di polveri sottili nei frutti. detach(data_frutti) 167 Esercizio 7 (Modello di regressione lineare semplice) Importare in R il dataset data_lm.csv. Lo sperimentatore ipotizza che tra le variabili colesterolo e glicemia esista una relazione causale (colesterolo glicemia). Testare e quantificare tale relazione. Soluzione: Importo in R il dataset data_lm.csv, ne visualizzo un estratto, le dimensioni (numero di righe, numero di colonne), le etichette delle variabili ed esguo l’attach(): data_lm <- read.csv2 (file.choose(), header = TRUE, sep = ";") head (data_lm) colesterolo 1 188.3131 2 242.2862 3 195.6349 4 196.6998 5 100.5295 6 207.8452 glicemia 88.58131 81.02835 123.40325 129.35414 86.12813 85.31602 dim (data_lm) [1] 100 2 colnames (data_lm) [1] "colesterolo" "glicemia" attach (data_lm) Visualizzo le statistiche di sintesi di entrambe le variabili: summary (data_lm) colesterolo Min. : 100.5 1st Qu.: 181.3 Median : 194.1 Mean : 198.4 3rd Qu.: 218.3 Max. : 262.6 glicemia Min. : 47.62 1st Qu.: 72.15 Median : 86.11 Mean : 86.29 3rd Qu.: 102.15 Max. : 129.35 Capisco che entrambe le variabili sono quantitative continue, perché il comando summary() fornisce il valore del minimo, del massimo, del primo e del terzo quartile, della mediana e della media delle variabili stesse. 168 Ho dunque a che fare con una variabile di risposta y (glicemia) quantitativa continua e una variabile esplicativa x (colesterolo) anch’essa quantitativa continua. Lo sperimentatore suppone che le due variabili siano in relazione causale (colesterolo glicemia) e quindi, per analizzarle, posso applicare il modello di regressione lineare semplice (y = + x + ), con: H0: = 0 H1: ≠ 0 e con: H0: colesterolo = 0 H1: colesterolo ≠ 0 m1 <- lm (glicemia ~ colesterolo) summary (m1) Call: lm(formula = glicemia ~ colesterolo) Residuals: Min 1Q -38.227 -14.540 Median -0.782 3Q 15.653 Max 43.030 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 90.78290 13.86906 6.546 2.73e-09 *** colesterolo -0.02267 0.06918 -0.328 0.744 --Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 20.12 on 98 degrees of freedom Multiple R-squared: 0.001094, Adjusted R-squared: -0.009098 F-statistic: 0.1074 on 1 and 98 DF, p-value: 0.7438 Calcolo gli intervalli di confidenza dei coefficienti e : confint (m1) (Intercept) colesterolo 2.5 % 63.2601928 -0.1599524 97.5 % 118.3055975 0.1146145 Il p-value relativo alla stima dell’intercetta Intercept (cioè del coefficiente dell’equazione della regressione lineare semplice y = + x + ) è pari a 2.73 ∙ 109, cioè < 0.05, per cui rifiuto l’ipotesi nulla H0: = 0 e posso affermare che nell’equazione del modello, il coefficiente è diverso da zero. Il P-value relativo alla variabile colesterolo (cioè alla stima del coefficiente dell’equazione della regressione lineare semplice y = + x + ) è pari a 0.744, cioè > 0.05, per cui non posso rifiutare l’ipotesi nulla H0: colesterolo = 0. Posso concludere che le due variabili glicemia e colesterolo non sono legate da una relazione lineare (livello di significatività considerato = 169 0.05): anche se all’aumentare di un’unità di colesterolo la glicemia decresce di – 0.03, tale variazione non risulta significativamente diversa da zero (test a due code). Verifico che siano rispettati i tre assunti necessari per l’applicazione del modello di regressione lineare semplice: 1) normalità dei residui: qqnorm (residuals(m1)) qualitativa (grafica). ; qqline shapiro.test (residuals(m1)) (residuals(m1)) # Verifica # Verifica quantitativa. Shapiro-Wilk normality test data: residuals(m1) W = 0.9839, p-value = 0.2652 2) omoschedasticità dei residui: install.packages ("lmtest") # Installo il pacchetto lmtest. library (lmtest) # Carico il pacchetto appena installato. bptest (glicemia ~ colesterolo) # Test di Breusch-Pagan, con H0: gli errori sono omoschedastici. studentized Breusch-Pagan test data: glicemia ~ colesterolo BP = 0.0119, df = 1, p-value = 0.9132 170 3) indipendenza dei residui: dwtest (glicemia ~ colesterolo) Durbin-Watson test data: glicemia ~ colesterolo DW = 2.1878, p-value = 0.8277 alternative hypothesis: true autocorrelation is greater than 0 I tre assunti sono rispettati: in tutti i tre test non si rifiutano le rispettive ipotesi nulle. 171 Esercizio 8 (Correlazione) Consideriamo i dati utilizzati nell’esercizio 7. Questa volta lo sperimentatore ipotizza che tra le variabili glicemia e colesterolo esista una relazione simmetrica (glicemia colesterolo). Testare e quantificare tale relazione. Soluzione: La relazione simmetrica tra due variabili viene testata e quantificata mediante la correlazione. Distinguiamo: - la correlazione di Pearson (si applica a variabili quantitative continue normali), - la correlazione di Spearman (si applica a variabili quantitative continue o qualitative ordinali “ranghizzate”). Correlazione di Pearson Come dimostrato nell’esercizio 7, le variabili glicemia e colesterolo sono entrambe quantitative continue. Ho dunque a che fare con due variabili quantitative continue. Lo sperimentatore suppone che le due variabili siano in relazione simmetrica (glicemia colesterolo) e quindi, per analizzarle, applico la correlazione di Pearson, con: cor (glicemia, Pearson. colesterolo) # Ottengo il valore del rho di - 0.03308315 Diagnostica per la correlazione di Pearson: shapiro.test (glicemia) Shapiro-Wilk normality test data: glicemia W = 0.9842, p-value = 0.2779 shapiro.test (colesterolo) Shapiro-Wilk normality test data: colesterolo W = 0.9799, p-value = 0.13 Entrambe le variabili risultano distribuite normalmente (p-values non significativi) e quindi è corretto eseguire una correlazione di Pearson. Applico un test di significatività alla correlazione di Pearson, con: H0: = 0 e H1: ≠ 0. 172 cor.test (glicemia, colesterolo, method = "pearson") Pearson's product-moment correlation data: glicemia and colesterolo t = -0.3277, df = 98, p-value = 0.7438 alternative hypothesis: true correlation is not equal to 0 95 percent confidence interval: -0.2280196 0.1644033 sample estimates: cor -0.03308315 Il p-value risulta pari a 0.7438, cioè > 0.05, per cui non posso rifiutare l’ipotesi nulla H0: = 0 (livello di significatività = 0.05). Posso concludere che la correlazione di Pearson non è significativamente diversa da zero. Correlazione di Spearman Se la diagnostica della correlazione di Pearson non fosse andata a buon fine, cioè una o entrambe le variabili considerate non fossero risultate normalmente distribuite, avrei dovuto applicare la correlazione di Spearman: cor (glicemia, colesterolo, valore del rho di Spearman. method = "spearman") # Ottengo il 0.009144914 Applico un test di significatività alla correlazione di Spearman, con: H0: = 0 e H1: ≠ 0. cor.test(glicemia, colesterolo, method = "spearman") Spearman's rank correlation rho data: glicemia and colesterolo S = 165126, p-value = 0.928 alternative hypothesis: true rho is not equal to 0 sample estimates: rho 0.009144914 Il p-value risulta pari a 0.928, cioè > 0.05, per cui non posso rifiutare l’ipotesi nulla H0: = 0 (livello di significatività = 0.05). Posso concludere che la correlazione di Spearman non è significativamente diversa da zero. 173