Introduzione e analisi dei dati in R Cinzia Viroli Dipartimento di Scienze Statistiche Università di Bologna [email protected] Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 1 0. Premessa R è uno dei software statistici più utilizzati dalla comunità scientifica. La sua grande diffusione nasce dal fatto che si tratta di un ambiente di tipo open source ovvero disponibile gratuitamente sotto i vincoli della GPL (General Public Licence) per diversi sistemi operativi. Si tratta di un ambiente molto versatile e potente che permette di gestire basi di dati, di effettuare analisi statistiche e di produrre grafici di alto livello. Inoltre esso rappresenta un vero e proprio linguaggio di programmazione orientato ad oggetti che consente l'uso di strutture condizionali e cicliche, nonché di funzioni create dall'utente. Per informazioni sull'installazione del programma: http://cran.r-project.org/ Queste semplici note rappresentano uno schema molto sintetico e non esaustivo degli argomenti trattati a lezione. Per maggiori dettagli sull'uso di R si faccia riferimento al volume: A first course in Statistical programming with R, Braun and Murdoch, Cambridge University Press, 2008 (in inglese) oppure ai tanti manuali gratuiti scaricabili dal sito di R http://cran.r-project.org sotto la voce Contributed Documentation. 1. Introduzione al linguaggio R R è un linguaggio di programmazione ad oggetti. I possibili oggetti sono vettori, matrici, liste, basi di dati (dataframe), funzioni ecc. Sia in windows che in linux non esiste una interfaccia grafica al programma. Quando si apre R per la prima volta appare una semplice finestra bianca (chiamata console) con un cursore che indica la posizione in cui inserire un qualche comando. L'area di lavoro iniziale di R (chiamata workspace) è vuota. Per verificarlo si digiti: > ls() oppure > objects() Se si costruisce un semplice oggetto di nome pluto a cui si assegna il valore 3: > pluto=3 l'area di lavoro ora conterrà il nuovo oggetto. Si immagini ora di lavorare in R e alla fine della sessione di lavoro si vogliano salvare gli oggetti costruiti. Occorre quindi salvare il workspace in una determinata directory di lavoro. Alcuni comandi utili: > getwd() per conoscere la directory di lavoro > setwd(“directory”) per impostare la directory di lavoro > save.image(“nome.RData”) per salvare il workspace > load(“nome.RData”) per caricare il workspace > savehistory(“nome”) e loadhistory(“nome”) per salvare l'elenco dei comandi digitati nella console. e caricare Per uscire da R: q() Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 2 1.1 Lavorare con gli oggetti > x=2+(3-4*5)/2 #costruisci un oggetto > x #guardalo [1] -6.5 > x-2 #...utilizzalo [1] -8.5 > x=5 #...sovrascrivilo > y=2.5 #crea un altro oggetto > x/y #fai qualsiasi operazione con gli oggetti [1] 2 Il simbolo # è il commento e viene ignorato dall’ambiente. 1.1 Operatori logici > 2*2==4 [1] TRUE > 2*3==4 [1] FALSE > 2*2>=4 [1] TRUE > 2*3>4 [1] TRUE > 2*3>=4 [1] TRUE > 2*3!=4 [1] TRUE 1.2 Vettori > x=c(2,5,9.5,-3) #costruisci un vettore > x[2] #seleziona il suo secondo elemento [1] 5 > x[c(2,4)] #seleziona i suoi elementi nella posizione 2 e 4 [1] 5 -3 > x[x>0] #seleziona i sui elementi positivi [1] 2.0 5.0 9.5 > x[x>0]-1 [1] 1.0 4.0 8.5 > x[x>0][2] [1] 5 > x=1:10 > x [1] 1 2 3 4 5 6 7 8 9 10 > x1=seq(1,1000, length=10) #vettore da 1 a 1000 di ampiezza 10 > x1 [1] 1 112 223 334 445 556 667 778 889 1000 > x2=rep(2,times=10) #ripeti 2 10 volte > x2 [1] 2 2 2 2 2 2 2 2 2 2 > rep(c(1,3),times=4) #ripeti (1,3) 4 volte [1] 1 3 1 3 1 3 1 3 > rep(c(1,9),c(3,1)) #ripeti (1,9) 3 e 1 volta rispettivamente [1] 1 1 1 9 > length(c(x,x1,x2,3)) Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 3 [1] 31 1.3 Matrici > x=matrix(1:10,ncol=5) #costruisci una matrice > x [,1] [,2] [,3] [,4] [,5] [1,] 1 3 5 7 9 [2,] 2 4 6 8 10 > xx=t(x) #trasponila > x[,1] #seleziona la prima colonna [1] 1 2 > x[2,] #seleziona la seconda riga [1] 2 4 6 8 10 > x[3,2] #seleziona l’elemento [3,2] Error: subscript out of bounds > x[2,3] #...e quello [2,3] [1] 6 > x[,4:5] #seleziona solo le colonne 4 e 5 [,1] [,2] [1,] 7 9 [2,] 8 10 > x[,-c(2,4)] #seleziona le colonne 1, 3 e 5 [,1] [,2] [,3] [1,] 1 5 9 [2,] 2 6 10 > cbind(1:2,c(1,-2),c(0,9)) #dispone per colonne [,1] [,2] [,3] [1,] 1 1 0 [2,] 2 -2 9 > rbind(1:4,c(0,5,-4,6)) #dispone per righe [,1] [,2] [,3] [,4] [1,] 1 2 3 4 [2,] 0 5 -4 6 > diag(x[,4:5]) #estrae la diagonale principale [1] 7 10 > D=diag(1:3) #costruisce una matrice diagonale > A=matrix(0,3,3) # crea una matrice di zeri > A=edit(A) # inserisci dei valori nella matrice 1.4 Dataframe > X=data.frame(a=1:4, sesso=c("M","F","F","M")) #crea un dataframe #con una variabile ‘quantitativa’ e una ‘qualitativa’. > X a sesso 1 1 M 2 2 F 3 3 F 4 4 M > dim(X) [1] 4 2 > X$eta=c(2.5,3,5,6.2) #aggiungi una variabile > X Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 4 a 1 2 3 4 sesso eta 1 M 2.5 2 F 3.0 3 F 5.0 4 M 6.2 > X[X$sesso=="M","eta"] #guarda eta per i maschi [1] 2.5 6.2 > X$sesso[X$eta<=3] #guarda sesso per cui eta<=3 1.4 Array > a=array(1:24,c(3,4,2)) #crea un array > a #guardalo 1.4 Liste > lista=list(oggetto1=a,oggetto2=X) #crea una lista > lista$oggetto2 #guarda un oggetto della lista Esercizio Calcolare la media aritmetica e la varianza 1 n (xi − x )2 s2 = ∑ n − 1 i=1 delle vendite di un certo quotidiano di un edicolante in una settimana: lunedì martedì mercoledì giovedì venerdì sabato 50 84 44 43 40 65 2. Le funzioni In R esistono tantissime funzioni diverse. Ad esempio mean() summary() sum() var() Altre possono essere costruite e caricate. Per fare questo è comodo utilizzare un editor. In linux esistono diverse possibilità fra cui KATE e Emacs Speack Statistics (ESS). Proviamo a costruire la funzione che calcola la varianza. varianza=function(vettore) { numobs=length(vettore) varianza=sum((vettore-mean(vettore))^2) varianza=varianza/(numobs-1) return(varianza) } Una volta che la funzione è stata scritta su un editor per compilarla e quindi renderla disponibile in R si Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 5 può procedere in due modi: o con copia ed incolla, oppure occorre salvarla in un file chiamato ad esempio “varianza.R” e digitare nella console: source(“varianza.R”) Si può costruire anche una funzione che riporti in uscita più oggetti attraverso le liste. Vogliamo costruire una funzione che restituisca in output media e varianza: media.var=function(vettore) { numobs=length(vettore) media=mean(vettore) varianza=sum((vettore-media)^2) varianza=varianza/(numobs-1) return(list(media=media,var=varianza)) } Oppure si può costruire una funzione che prenda in entrata più oggetti. Ad esempio dato un certo capitale e un certo tasso di interesse mensile si vuole calcolare il montante dopo 6 mesi (capitalizzazione semplice) M=C(1+6i): calcola.montante=function(capitale,interesse,mesi=6) { montante=capitale*(1+interesse*mesi) return(montante) } Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 6 3. La programmazione in R Il ciclo for: for (name in vector) {commands} Esempio: i numeri di Fibonacci Calcolare i primi 12 numeri di Fibonacci. Fibonacci=rep(0,12) Fibonacci[1]=1 Fibonacci[2]=1 for (i in 3:12) Fibonacci[i]=Fibonacci[i-2]+Fibonacci[i-1] La condizione if: if (condition) {commands when TRUE} if (condition) {commands when TRUE} else {commands when FALSE} Esempio: il crivello di Eratostene Il crivello di Eratostene è un antico procedimento per il calcolo delle tabelle di numeri primi fino a un certo numero n prefissato. Il procedimento è il seguente: si scrivono tutti i naturali a partire da 2 fino n in un elenco detto setaccio. Poi si cancellano (setacciano) tutti i multipli del primo numero del setaccio (escluso lui stesso). Si prosegue così fino ad arrivare in fondo. I numeri che restano sono i numeri primi minori od uguali a n. Si può dimostrare che il procedimento di setacciatura per ricercare i primi fino ad un certo numero n cessa sempre quando si supera la radice quadrata di n. Eratostene=function(n) { if (n>=2) { sieve=seq(2,n) primi=c() for (i in seq(2,n)) { if (any(sieve==i)) { primi=c(primi,i) sieve=c(sieve[(sieve %% i) !=0],i) } } return(primi) } else { stop(“Il valore di n deve essere almeno 2”) } } L'istruzione while: while (condition) {statements} L'istruzione repeat: repeat {statements} if (condition) break Esempio: il metodo di Newton per trovare le radici di una funzione Si tratta di un algoritmo per determinare le radici di una funzione Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 7 f(x)=0 sulla base dell'approssimazione di Taylor. Se f'(x) è la derivata prima di f(x) allora l'algoritmo consiste nell'iterare (x0 scelta iniziale) xn=xn-1 – f(xn-1)/f'(xn-1) sino a convergenza. Esempio Si applichi l’algoritmo di Newton per determinare le radici della funzione f ( x) = x 3 + 2 x 2 − 7 ### Newton con while### newton.1=function(x0,tolerance=0.000001) { x=x0 f=x^3+2*x^2-7 while (abs(f)>tolerance) { f.prime=3*x^2+4*x x=x-(f/f.prime) f=x^3+2*x^2-7 } return(x) } ### Newton con repeat### newton.2=function(x0,tolerance=0.000001) { x=x0 repeat { f=x^3+2*x^2-7 if (abs(f) < tolerance) break f.prime=3*x^2+4*x x=x-(f/f.prime) } return(x) } Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 8 4. Simulazione 4.1 Generazione di numeri casuali Generazione di numeri pseudo-casuali Esistono diversi modi per generare una sequenza di numeri nell’intervallo [0,1] che ha tutte le caratteristiche di una sequenza casuale (ma non lo è perciò la si definisce pseudo-casuale). Un algoritmo molto semplice è il seguente. Si fissi un numero intero m e un numero intero b<m, non uno fra i divisori di m. Si scelga un valore di partenza indicato con x0 chiamato seed. Per generare una sequenza di numeri pseudo-casuali (u1,u2,…,un) si può procedere come segue: x1 = b x0 mod m u1 = x1/m dove u1 è il primo numero pseudo-casuale. Il secondo lo si ottiene come: x2 = b x1 mod m u2 = x2/m e così via. Esempio Costruire il programma che generi una sequenza di numeri casuali dati un seme (seed) e i valori per b ed m. Eseguire il programma con m=7 e b=3. genera.random=function(n,seme=1,m=100000,b=trunc(sqrt(m))) { num.casuali=rep(0,n) for (i in 1:n) {seme=(b*seme)%%m num.casuali[i]=seme/m } return(num.casuali) } Cosa succede se b è un divisore di m? Quale problema si può riscontrare quando m è un numero non elevato? Generazione di numeri (pseudo-)casuali da una uniforme runif(n,min=a,max=b) Esempio Generare 1000 osservazioni da due variabili aleatorie X1 e X2 distribuite secondo una uniforme in [0,1]. Farne uno scatterplot. Sono indipendenti? Costruirne poi la variabile somma e la variabile differenza e farne uno scatterplot. Misurare la correlazione fra le due coppie di variabili. set.seed(1) ## per fissare un punto di partenza comune x1=runif(1000) x2=runif(1000) plot(x1~x2) S=x1+x2 Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 9 D=x1-x2 plot(S~D) cor(x1,x2) cor(S,D) Generazione di numeri casuali da una bernoulli Una variabile aleatoria di Bernoulli ha due esiti possibili con probabilità rispettivamente p e (1-p). Esempio Una prova di esame consiste di 20 domande alle quali la mia preparazione mi consente di rispondere correttamente con una probabilità del 20%. Generare uno fra i possibili risultati all'esame. risposte=runif(20) risposte.corrette=(risposte<0.2) table(risposte.corrette) pie(table(risposte.corrette),col=c("red","green")) La variabile aleatoria binomiale La somma X di n prove indipendenti di Bernoulli ciascuna con probabilità p è la variabile binomiale. X rappresenta il numero di successi in n prove. dbinom(x,size,prob) # calcola la probabilità di avere “x” successi in # “size” prove ciascuna con probabilità “prob” pbinom(x,size,prob) # calcola la probabilità di avere al massimo “x” # successi ovvero P(X≤x) rbinom(n,size,prob) # genera n variabili binomiali Esempio Quale è la probabilità che in 100 lanci di una moneta non truccata si ottengano esattamente 50 teste e 50 croci? Sorprendentemente questa probabilità è alquanto bassa: dbinom(50,100,0.5) [1] 0.07958924 E in 20 lanci quale è la probabilità di ottenere 10 teste e 10 croci? Costruire il grafico che associa ad ogni possibile numero di teste in 20 lanci la sua probabilità. x=0:20 prob=rep(0,21) for (i in 1:21) prob[i]=dbinom(x[i],20,0.5) barplot(prob,names.arg=x) Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 10 Esempio Si sa che in un processo industriale il 10% delle tubi prodotte da una vecchia macchina risultano difettose. Si sa inoltre che vengono prodotti 15 tubi ogni ora. Si definisce un processo fuori controllo quando più di 4 tubi escono difettosi ogni ora. Simulare il numero di pezzi difettosi prodotti ogni ora nell'arco di 24 ore e contare i processi fuori controllo. pezzi.dif=rbinom(24,15,0.1) sum(pezzi.dif>4) La variabile aleatoria normale La variabile aleatoria normale è caratterizzata da due parametri: la media e la standard deviation. dnorm(x,mean,sd) # calcola la densità di probabilità pnorm(x,mean,sd) # calcola P(X≤x) chiamata funzione di ripartizione rnorm(n,mean,sd) # genera n variabili normali qnorm(p,mean,sd) # restituisce il valore di ascissa (quantile) in # corrispondenza del valore dell'integrale p Esempio Simulare 10000 realizzazioni da una distribuzione normale con media 50 e deviazione standard 5.2 e costruirne l'istogramma. x=rnorm(10000,50,5.2) hist(x,probability=TRUE) lines(density(x)) Esempio Calcolare la probabilità che le realizzazioni di una variabile aleatoria 'standardizzata' (ovvero con media zero e standard deviation 1) siano comprese nell'intervallo [-1.946, 1.946]. ## Primo modo ## prob=pnorm(-1.946) 1-2*prob ## in virtù della simmetria della distribuzione ## Secondo modo ## n=10000000 x=rnorm(n) compresi=(x>-1.946 & x<1.946) sum(compresi)/n Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 11 4.2 Integrazione di Monte Carlo Le realizzazioni dalle varie leggi distributive possono essere utilizzate per approssimare gli integrali del tipo: ∫ b a g (u )du Siano u1,u2,…,un n realizzazioni indipendenti da variabili aleatorie uniformi nell’intervallo [a,b]. Allora per la definizione di valore atteso di una variabile aleatoria si sa E [g (u )] = ∫ g (u ) b a 1 du b−a da cui, per la legge dei grandi numeri ∫ b a 1 n g (u )du = E [g (u )](b − a ) ≅ ∑ u i (b − a ) n i =1 Esempio Approssimare l’integrale 5 ∫ sin( x)dx (vero valore –0.7) 2 u=runif(10000,2,5) mean(sin(u))*(5-2) Esempio Approssimare l’integrale doppio 10 7 ∫ ∫ sin( x − y)dxdy 3 1 u=runif(10000,1,7) v=runif(10000,3,10) mean(sin(u-v))*(10-3)*(7-1) Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 12 5. Alcuni elementi di algebra lineare Prendiamo una matrice quadrata A: A=matrix(c(1,2,1.5,0.5),2,2) Alcune proprietà: det(A) # calcola il determinante di A dim(A) # restituisce le dimensioni della matrice diag(A) # restituisce gli elementi sulla diagonale principale di A sum(diag(A)) # calcola la traccia di A t(A) # restituisce la trasposta di A diag(diag(A)) # restituisce una matrice diagonale con gli elementi della diagonale principale di A eigen(A) # calcola autovalori e autovettori di A solve(A) # calcola l’inversa della matrice Prendiamo 2 matrici con le stesse dimensioni: A=matrix(c(1,2,1.5,0.5),2,2) B=matrix(c(0.3,1,1,-0.5),2,2) A+B A*B A%*%B # somma gli elementi delle due matrici # moltiplica a due a due fra gli elementi delle due matrici # fa il prodotto matriciale Esempio La funzione solve(A,b) restituisce la soluzione del sistema lineare Ax=b. Determinare x tale che H3 x=b con b=[1 2 3]T e H3 la matrice di Hilbert di ordine 3: H3=1/cbind(seq(1,3),seq(2,4),seq(3,5)) b=c(1,2,3) x=solve(H3,b) Esempio Trovare la scomposizione di Choleski e la scomposizione in valori singolari della matrice di Hilbert di ordine 3. H3.chol=chol(H3) t(H3.chol)%*%H3.chol H3.svd=svd(H3) H3.svd$u%*%diag(H3.svd$d)%*%t(H3.svd$v) Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 13 6. Ottimizzazione numerica 6.1 Il metodo golden search E’ un algoritmo numerico piuttosto semplice per trovare il minimo (supposto unico) di una funzione in una sola variabile in un intervallo [a,b] con a<b. Consideriamo per esempio la seguente funzione f ( x ) = x − 3 .5 + ( x − 2 ) 2 nell’intervallo [0,5]. Per visualizzare il grafico di questa funzione si può procedere in questo modo: f=function(x) {abs(x-3.5)+(x-2)^2} curve(f,from=1,to=5) L’algoritmo funziona in questo modo: 1. Si parte dall’intervallo [a,b] 2. Si restringe l’intervallo in modo iterativo in [a’,b’] in modo che esso continui a contenere al suo interno il punto di minimo 3. Ci si arresta quando b’-a’ è piccolo abbastanza e una buona approssimazione del punto di minimo è la media dei due estremi. Nel passo 2 dell’algoritmo si calcolano x1 e x2 interni all’intervallo di partenza ma tali che x1 < x2. Poiché abbiamo ipotizzato esserci un unico minimo se succede f(x1)> f(x2) significa che il minimo è contenuto nel nuovo intervallo [x1,b]; altrimenti se f(x1)< f(x2) significa che il minimo è contenuto nel nuovo intervallo [a,x2]. Si procede iterativamente. golden=function(f,a,b,tol=0.0000001) { c=100 x1=a+(b-a)/100 x2=b-(b-a)/100 f1=f(x1) f2=f(x2) while ( abs(b-a)>tol) if (f1>f2) {a=x1 ## b rimane b x1=a+(b-a)/100 x2=b-(b-a)/100 f1=f(x1) f2=f(x2) } else {b=x2 #a rimane a x1=a+(b-a)/100 x2=b-(b-a)/100 f1=f(x1) f2=f(x2)} return((a+b)/2)} Esempio Trovare il punto di minimo della funzione f ( x) = x − 3 + sin( x) − x − 2 . E se volessi individuarne il punto di massimo? Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 14 6.2 Il metodo di Newton-Raphson Se per la funzione da minimizzare esistono e si possono calcolare le prime due derivate, si può applicare l’algoritmo di Newton-Raphson che è molto più veloce del metodo precedente. Si basa sul metodo di Newton per trovare le radici di una funzione il cui criterio era: (x0 scelta iniziale) xn=xn-1 – f(xn-1)/f’(xn-1) e si sfrutta il fatto che trovare il minimo (o il massimo) di una funzione equivale a trovare le radici della sua derivata prima. Per questa ragione l’algoritmo di Newton-Raphson consiste nell’iterare: (x0 scelta iniziale) xn=xn-1 – f’(xn-1)/f ’’(xn-1) Esempio Trovare il punto di minimo della funzione f ( x) = e − x + x 4 . f=function(x) exp(-x)+x^4 curve(f,from=-1,to=2) fprime=function(x) –exp(-x)+4*x^3 fprimeprime=function(x) exp(-x) +12*x^2 ### Newton con while### newton=function(x0,fprime,fprimeprime,tolerance=0.00001) { x=x0 while (abs(fprime(x))>tolerance) x=x-(fprime(x)/fprimeprime(x)) return(x) } 6.3 Altri algoritmi In R sono implementati i maggiori algoritmi di ottimizzazione numerica nella funzione optim che prende come argomenti principali il valore di partenza e la funzione da ottimizzare. In automatico la funzione optim calcola le derivate qualora servano. help(optim) ## per vedere altre opzioni optim(0,f) La funzione optim è in grado di individuare il minimo di funzioni di più variabili. Esempio Trovare il punto di minimo della funzione f (a, b) = (a − 1) + b + 3 sin( a) − 2a cos(b) . f=function(x) (x[1]-1)+x[2]+3*sin(x[1])-2*x[1]*cos(x[2]) optim(c(1,1),f) Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 15 7. Analisi di un caso di studio: Who survived the Sinking of the Titanic? 7.1 Descrizione dei dati On April 14th, 1912, at 11.40 p.m., the Titanic, sailing from Southampton to New York, struck an iceberg and started to take on water. At 2.20 a.m. she sank; of the 2228 passengers and crew on board, only 705 survived. Data on Titanic passengers have been collected by many researchers. Primary references are the Encyclopedia Titanica at www.encyclopedia-titanica.org For 1309 passengers, these data record whether or not a particular passenger survived, along with the age, gender, ticket class, and the number of family members accompanying each passenger. The list of variables is described in the table: Name Labels pclass survived Survived name Name sex Levels NAs 1= First class 2= Second class 3= Third class 0 0=died; 1=survived 0 0 female; male 0 age Age (years) 263 sibsp Number of Siblings/Spouses Aboard 0 parch Number of Parents/Children Aboard 0 ticket Ticket Number 0 fare Passenger Fare (british pounds) 1 cabin 0 C=Cherbourg Q=Queenstown S=Southampton embarked boat body 2 0 Body Identification Number home.dest Home/Destination 1188 0 Per caricare questi dati si deve preventivamente copiare il file in formato txt sulla cartella di lavoro in cui la console di R lavora. Se non si è sicuri del percorso esatto lo si può visualizzare digitando nella console: getwd(). Se i dati si trovano nella directory di lavoro e il file si chiama titanic.txt per caricarlo nella workspace si utilizza il comando: dati=read.table("titanic.txt",header=TRUE) dove il comando opzionale header specifica se nella prima riga del file ci sono le etichette. Di default questo valore è impostato su FALSE. R non legge solo file di tipo txt ma anche file di excel, in formato csv e in generale i files provenienti da più comuni programmi scientifici. Si noti che, analogamente al comando read.table, esiste il comando write.table per scrivere su un file un oggetto contenuto nella workspace. Esempio: write.table(dati,"titanic.bis.txt") Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 16 Per avere alcune informazioni sul dati visualizzare la dimensione e la struttura dei dati si può procedere così: dim(dati) #restituisce il numero di righe e di colonne is.data.frame(dati) #restituisce vero se dati è un data.frame class(dati) #indica il tipo di oggetto dati[1:10,] #visualizza le informazioni sulle prime 10 persone 7.2 Sistemare i dati in modo che le variabili qualitative siano fattori La classe fattore è una particolare modalità di R di trattare quelle, che in statistica, sono le variabili qualitativi. Ad esempio: Maschio/Femmina, 1° classe/2° classe/3°classe ecc. Si tratta di modalità ripetute nell’insieme dei casi. Queste variabili potrebbero essere del tipo “character” ma è preferibile attribuire loro la classe factor poiché questo consente di fare eventuali elaborazioni statistiche. Le modalità sono chiamate livelli del fattore e ad ogni livello corrisponde internamente ad R un codice numerico. Infatti ad esempio vediamo cosa succede se applichiamo il comando summary all’età, alla classe e al sesso: is.double(dati$age) summary(dati$age) ## calcola alcune statistiche descrittive is.factor(dati$pclass) is.double(dati$pclass) summary(dati$age) is.factor(dati$sex) summary(dati$sex) Non ha senso calcolare la media e le altre statistiche per la classe! Si può fare solamente un semplice conteggio del numero dei casi: ecco perché è opportuno convertirla in fattore. Per far si che R riconosca la classe come una variabile qualitativa occorre digitare: dati$pclass=as.factor(dati$pclass) In generale possiamo controllare come sono state importate le classi di ciascuna colonna del dataset attraverso il comando: str(dati) #elenca il nome e il tipo di colonne e procedere ad una opportuna sistemazione dei dati in modo che: pclass deve essere un fattore; name deve essere un carattere; ticket deve essere un carattere; cabin deve essere un carattere; body deve essere un carattere; home destination deve essere un carattere; dati$pclass=as.factor(dati$pclass) dati$name=as.character(dati$name) dati$ticket=as.character(dati$ticket) dati$cabin=as.character(dati$cabin) dati$body=as.character(dati$body) dati$home=as.character(dati$home) Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 17 7.3 Calcolare alcune statistiche descrittive per le variabili del dataset. Il comando summary può essere ora applicato a tutto il dataset: summary(dati) Da un punto di vista grafico, il commando plot funziona anche per fattori; si digiti per esempio: plot(dati$pclass) Si voglia per esempio osservare l’età media separatamente per classe, oppure per sesso. Innanzitutto occorre osservare che mean(dati$age) non restituisce la media in quanto ci sono 263 valori mancanti codificati in R con NA. In caso di valori mancanti occorre aggiungere al comando un argomento opzionale: mean(dati$age,na.rm=TRUE) hist(dati$age) #per avere una idea grafica della distribuzione dell’età var(dati$age,na.rm=TRUE) # restituisce la varianza sd(dati$age,na.rm=TRUE) # restituisce lo scarto quadratico medio min(dati$age,na.rm=TRUE) # restituisce il minimo max(dati$age,na.rm=TRUE) # restituisce il massimo median(dati$age,na.rm=TRUE)# restituisce la mediana Se si vuole la media dell’età separatamente per classe si deve utilizzare il comando: by(dati$age,dati$pclass,mean,na.rm=TRUE) by(dati$age,dati$pclass,summary) plot(dati$age~dati$pclass) # grafico chiamato boxplot 7.4 Notare che esistono molti passeggeri con più di 3 figli o parenti. Creare 2 nuovi variabili che contengano le classi: 1,2,3, and “più di 3”. Le nuove variabili saranno fattori. Si può procedere in questo modo: sibsp2=dati$sibsp parch2=dati$parch sibsp2[dati$sibsp>3]=4 parch2[dati$parch>3]=4 dati$sibsp2=as.factor(sibsp2) dati$parch2=as.factor(parch2) 7.5 Creare una nuova variabile per l’età suddivisa nelle classi: [0-21), [21-28), [28-39), [39,80]. age2=dati$age age2[dati$age<21]=1 age2[dati$age>=21 & dati$age < 28]=2 age2[dati$age>=28 & dati$age < 39]=3 age2[dati$age>=39]=4 dati$age2=as.factor(age2) 7.6 Calcolare la proporzione di sopravvissuti per intervallo di età, classe e sesso. by(dati$survived,dati$age2,mean) by(dati$survived,dati$pclass,mean) by(dati$survived,dati$sex,mean) Questo consente di rispondere a una domanda del tipo: D1: “quale è stata la frazione dei sopravvissuti fra i maschi?”. Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 18 Un altro tipo di domanda poteva essere: D2: “quale è stata la frazione dei maschi fra i sopravvissuti?” E ancora D3: “quale è stata la frazione dei maschi sopravvissuti fra il totale dei passeggeri”? Sono 3 tipi di domande diverse a cui si risponde con informazioni diverse. Costruiamo innanzitutto una tabella doppia: tabella=table(dati$survived,dati$sex) barplot(tabella,beside=TRUE,legend=TRUE,col=c("violet","seagreen")) Il grafico mette in luce come il numero di donne sopravvissute sia più alto di quello dei maschi (attenzione si tratta di valore assoluti e non di percentuali). Il comando prop.table calcola le frequenze relative di una tabella a partire dalla tabella contente le frequenze assolute. D1: D2: D3: prop.table(tabella,2) # 19.09% prop.table(tabella,1) # 32.20% prop.table(tabella) # 12.29% 7.7 Indicare se la probabilità di sopravvivenza è influenzata da ciascuna delle seguenti caratteristiche: classe, età, sesso. A questa domanda si ricorre effettuando il test del Chi quadrato che verifica l’ipotesi nulla che i due caratteri via via considerati siano fra loro indipendenti. chisq.test(table(dati$survived,dati$pclass)) chisq.test(with(dati, table(survived,pclass))) # equivalente al precedente chisq.test(with(dati, table(survived,age2))) chisq.test(with(dati, table(survived,sex))) I risultati mettono in luce che il sesso e la classe hanno avuto una influenza significativa sulla probabilità di sopravvivenza. Cinzia Viroli, Dipartimento di Scienze Statistiche, [email protected] 19