


































































Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Gli appunti comprendono come fare tutti gli esercizi sul software R. Corso di Business Data Analytics. Gli appunti sono stati presi partecipando a tutte le esercitazioni del corso. Sono compresi anche alcuni spunti teorici.
Tipologia: Schemi e mappe concettuali
1 / 74
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!



































































Test di Shapiro (Per numerosità<5000) shapiro.test(col)
H0 : X~N vs H1: dati NON gaussiani P-value alto (>0.05): accetto H0, i dati provengono da una distribuzione normale. P-value basso: rifiutiamo l'ipotesi di normalità dei dati.
Graficamente t = seq(min(col), max(col), length.out = 1000) f = dnorm(t, mean = mu_hat, sd = sd_hat) # densità normale a cui dò in input t, media e sd quartz() hist(col, breaks = 15, probability = T) lines(t, f, type = "l", lwd = 3)
Confronto graficamente se i dati hanno una distribuzione simile alla rispettiva normale.
Graficamente quartz() qqnorm(col) qqline(col, lwd=2)
Confronto graficamente i quantili empirici con quelli teorici. In caso di normalità perfetta, i dati giacciono esattamente sulla retta.
CASO 1 : popolazione distribuita normalmente: t-test Uso funzione t.test t.test(dati$Colesterolo, mu = 200, alternative = "less") UNILATERO A SINISTRA t.test(dati$Colesterolo, mu = 200, alternative = "greater") UNILATERO A DESTRA t.test(dati$Colesterolo, mu = 200, alternative = "two.sided") BILATERO H0 test bilatero: mu=200. Se p-value alto, accetto H0, quindi mu è circa uguale a 200.
Oppure a mano: Test unilatero a sinistra (H0: mu >=200 vs H1: mu<200) mu_0 = 200 n = length(dati$Colesterolo) media_campionaria = mean(dati$Colesterolo) dev_std_campionaria = sd(dati$Colesterolo) t = (media_campionaria - mu_0)*sqrt(n)/dev_std_campionaria pval = pt(t, df = n-1) pval
P-value alto: accetto H0. P-value basso: rifiuto H
Test di Shapiro (Per numerosità<5000) shapiro.test(colesterolo_uomini) shapiro.test(colesterolo_donne)
H0 : X~N vs H1: dati NON gaussiani P-value alto: accetto H0, i dati provengono da una distribuzione distribuita normalmente. P-value basso: rifiutiamo l'ipotesi di normalità dei dati.
Caso a varianze non note Le VARIANZE nelle due sottopopolazioni sono UGUALI? O DIVERSE? Esistono dei testi approssimati per l'uguaglianza tra varianze di due campioni, come ad esempio il test di Fisher ( basta saper leggere il p-value ) var.test(colesterolo_uomini, colesterolo_donne) t.test(colesterolo_uomini,colesterolo_donne, var.equal = T) Oppure a mano: X = colesterolo_donne Y = colesterolo_uomini nX = length(X) nY = length(Y) s2x = var(X) s2Y = var(Y) s2p = 1/(nX + nY - 2) * ((nX-1)s2x + (nY-1)s2Y) sp = sqrt(s2p) t = (mean(X) - mean(Y)) / sp / sqrt (1/nX + 1/nY) pval = 2*(1 - pt(t, df = nX + nY -2)) Risultati coerenti pval
P-value alto: accetto H0, le due medie sono uguali P-value basso: rifiuto H0, le due medie sono diverse
Caso a varianze note var_M = 150 var_F = 110 differenza_medie = mean(colesterolo_uomini) - mean(colesterolo_donne) n_uomini = length(colesterolo_uomini) n_donne = length(colesterolo_donne) z = differenza_medie / sqrt(var_M/n_uomini + var_F/n_donne) pvalue = 2*(1-pnorm(abs(z))) pvalue
P-value alto: accetto H0, le due medie sono uguali P-value basso: rifiuto H0, le due medie sono diverse
Verifica che tutti i g gruppi abbiano la stessa media (H0), altrimenti ne esiste almeno uno con media diversa (H1).
Specie in presenza di pochi dati, è bene accertarsi che le classi siano ragionevolmente bilanciate. table(dati_polli$feed)
tapply(dati_polli$weight, dati_polli$feed, shapiro.test) La funzione tapply suddivide i valori di una variabile quantitativa per i livelli di una variabile qualitativa e, per ogni livello, applica una particolare funzione (ad esempio: mean, max, shapiro.test,...) sui dati. Per ogni sottogruppo verifico che la distribuzione sia normale (p-value>0.05)
Ovvero che le varianze in ogni gruppo possano essere assunte uguali. Test di Bartlett bartlett.test(dati_polli$weight ~ dati_polli$feed) p-value alto: tutti i gruppi hanno varianza simile p-value basso: almeno uno dei gruppi ha varianza diversa dagli altri.
Ricordiamo la parametrizzazione mu_j = mu + tau_j , con tau_1 = 0 Quindi il modello è X_ji = mu + tau_j + epsilon_ij, epsilon_ij ~ N(0, sigma^2) H0: tau_j = 0 per ogni j VS H1: esiste j tale che tau_j!=
Anova_polli = aov(weight ~ feed, data = dati_polli) summary(Anova_polli) Numero di livelli del fattore feed: numero di gruppi: g Df del feed: gradi di libertà della variabile feed: g- Dimensione del dataset: numero di osservazioni: n Df dei Residuals: gradi di libertà dei residui: n-g Il p-value è indicato nel summary, nella cella (feed; Pr(>F)). p-value alto: accetto H0 (e la variabile categorica feed non dà distinzioni tra i gruppi). p-value basso: rifiuto H0.
Stima della comune varianza S , cioè la varianza stimata per tutte le popolazioni. S = sum(Anova_polli$residuals ^ 2) / Anova_polli$df.residual S
Anova_polli$df.residuals sono i gradi di libertà dei residui.
Intervalli di confidenza alpha = 0.05 (Intervallo di confidenza al 95%)
source("Confronti_multipli_da_anova.R") intervalli_anova = Confronti_multipli_da_anova(Anova_polli, alpha = alpha) names(intervalli_anova) intervalli = intervalli_anova$intervals
Riduce il numero di variabili che descrivono un insieme di dati, limitando il più possibile la perdita di informazioni. library(GGally) library(ggfortify)
turisti_obs = turisti[ ,-c(1,2)]
Se c’è correlazione forte tra le variabili, allora ha senso fare PCA. Graficamente library(GGally) quartz() ggpairs(turisti_obs) Con matrice di correlazione cor(turisti_obs) Se tutti gli elementi della matrice sono vicini a 1, allora la struttura di correlazione è abbastanza forte, quindi c’è omogeneità, si può fare PCA.
Matrice di covarianza cov(turisti_obs) Se le varianze assumono valori molto diversi, allora c’è forte disomogeneità.
Se c’è forte disomogeneità, data da matrice di correlazione e/o di covarianza, allora bisogna standardizzare il dataframe (ogni dato avrà media=0 e varianza=1). turisti_obs_scaled = data.frame(scale(turisti_obs)) Si nota che così matrice di correlazione e di covarianza sono uguali.
I principal component sono i vettori lungo cui si sviluppano maggiormente i dati, estrapolati dal campione X, costituito da n osservazioni distribuite normalmente con media mu e matrice di covarianza sig. PC = princomp(X) Deviazioni standard di ogni PC var_props = (PC$sdev^2) / sum(PC$sdev^2) Percentuale di varianza (percentuale di variabilità) di ogni PC cumsum(var_props) Restituisce la percentuale di varianza cumulata summary(PC) PC, var_props, cumsum(var_props)
Loadings : quanto quella variabile influisce su quel principal component. PC$loadings Dove non c'è valore vuol dire che è 0 Scores : valore dei dati proiettati lungo le 3 direzioni principali PC$scores
quartz() plot(cumsum(PC$sd^2)/sum(PC$sd^2), type='b', axes=F, xlab='number of components', ylab='contribution to the total variance', ylim=c(0,1), lwd=2) abline(h=1, col='red', lwd=1.5) abline(h= x , lty=2, col='blue') box() axis(2,at=0:10/10,labels=0:10/10) axis(1,at=1:ncol(turisti),labels=1:ncol(turisti),las=2)
Posso così visualizzare il contributo di ogni componente alla variabilità totale. Posso ottenere così il numero minimo di componenti principali da considerare per spiegare almeno x% della variabilità del dataset (prendo le componenti fino a quella che supera la linea blu).
Varianze in ordine decrescente variances = diag(cov(turisti_obs)) sort(variances, decreasing = TRUE)
library(ggfortify) autoplot(PC_tour_scaled) Visualizza gli scores sul piano PC1-PC2, cioè tutti i dati
Biplot : autoplot(PC_tour_scaled, loadings = TRUE, loadings.label = TRUE) Mostra sul piano PC1-PC2 come ogni variabile influisce su PC1 e PC
Per specificare quale PC vogliamo sugli assi: autoplot(PC_tour_scaled, x = 2, y = 3, loadings = TRUE, loadings.label = TRUE)
Grafico loadings delle prime 3 PC par(mar = c(1,4,0,2), mfrow = c(3,1)) for(i in 1:3)barplot(load.food[,i], ylim = c(-1, 1))
Costruisco un dataframe con gli scores, che ha come colonne le PC e, in più, le variabili categoriche. Scores = data.frame(PC_tour_scaled$scores) names(Scores) = paste0("Comp",1:8) Scores = cbind(Scores,turisti_lab)
Boxplot di PC1 rispetto alla variabile categorica dei mesi. quartz() boxplot(Scores$Comp1 ~ Scores$Month)
Grafico della within sum of squares (tot.withinss) tot.withinss = NULL for(k in 1:10) tot.withinss = c(tot.withinss, kmeans(nidi, k, nstart=20)$tot.withinss)
quartz() plot(1:10, tot.withinss, type='b', xlab='K') Si cerca un gomito in corrispodenza del K dopo cui il guadagno è trascurabile.
Si noti che a volte, si preferisce guardare al grafico della tot.withinss normalizzandolo rispetto alla total sum of squares ovvero la variabilità totale. Si ottiene una curva del tutto equivalente ai fini interpretativi, che ha però il pregio di assumere valori tra 0 e 1: la si può interpretare come frazione della variabilità totale dovuta alla variabilità intra-cluster. ratio = NULL for(i in 1:10){ kmeans_out = kmeans(data,i,nstart=20) ratio = c(ratio, kmeans_out$tot.withinss/kmeans_out$totss) } quartz() plot(1:10, ratio, type='b', xlab='K', ylab = "tot.withinss/totss", lwd=2) L'andamento della curva è esattamente identico: ogni suo punto è semplicemente stato diviso per una costante, la variabilità totale. Ricordiamo infatti che, mentre sia betweenss che tot.withinss sono proprietà della clusterizzazione, la loro somma, cioè la variabilità totale, dipende solo dai dati. Questa curva può essere interpretata come frazione della variabilità totale dovuta alla variabilità intra-cluster.
Grafico della silhouette per k = 3 e k = 2 Si ricorda che:
quartz() par(mfrow = c(2,2)) for ( i in 2:5){ km.output = kmeans(data, centers = i, nstart = 20) silhouettekm = silhouette(km.output$cluster , dist(data)) plot(silhouettekm, col = 1:i, main=paste("Silhouette per k =", i, sep=" ")) abline(v = mean(silhouettekm[,3]), lwd=3, col='red4') }
Devo prendere il K che ha average silhouette width più vicina a 1.
library(cluster)
Il comando dist calcola una matrice metrica (triangolare inferiore), in forma vettoriale per evitare ridondanze, seguendo una distanza specificata dall'utente. Il default è la distanza euclidea.
metric = dist(pioppi) Sarebbe equivalente a metric = dist(pioppi, method="euclidean") Altrimenti si può anche usare, ad esempio, il metodo manhattan.
dist(pioppi[1:7, ]) R non rappresenta la matrice metrica in forma matriciale, per evitare di ripetere elementi che sono uguali per definizione, ma questo non è un problema, poichè utilizzeremo tale oggetto passandolo direttamente agli algoritmi di clustering gerarchico.
Clustering gerarchico a partire da una matrice metrica: comando hclust. Occorre anche passare il metodo di linkage desiderato: Complete Linkage: distanza tra cluster è distanza tra i punti più lontani hc.complete = hclust(metric, method="complete") Average Linkage: distanza tra cluster è distanza tra i centroidi hc.average = hclust(metric, method="average") Single Linkage: distanza tra cluster è distanza tra i punti più vicini hc.single = hclust(metric, method="single")
quartz() par(mfrow=c(1,3)) plot(hc.complete, main="Complete Linkage", xlab="", sub="", cex=.9, labels = F) plot(hc.average, main="Average Linkage", xlab="", sub="", cex=.9, labels = F) plot(hc.single, main="Single Linkage", xlab="", sub="", cex=.9, labels = F)
Mostra come funziona graficamente il clustering gerarchico: in basso ci sono i singoli dati che vengono raggruppati a due a due, a loro volta raggruppati e così via. Le zone dove sono più lunghi i rettangoli sono zone di stabilità. Il numero di gruppi che si vogliono identificare è tendenzialmente in una zona di stabilità molto alta.
Si deve scegliere il tipo di clustering con zona di stabilità più alta.
library(GGally) library(MASS) library(car) library(rgl)
first_model = lm(Income ~ Education, data = data) summary(first_model) Il regressore è Education.
quartz() par(mfrow = c(2,2)) plot(first_model)
names(first_model) first_model$coefficients Valori stimati dei beta first_model$residuals Residui : epsilon_hat first_model$rank p + 1 first_model$fitted.values Valori fittati: y_hat first_model$df.residual Gradi di liberta' del modello: n - p - 1 first_model$model Il data frame dei dati sigma2_hat = sum(first_model$residuals^2)/first_model$df.residual Stima della varianza
vcov(first_model) Matrice di covarianza dei beta rstandard(first_model) Residui standardizzati
alpha = 0. confint(first_model, level = 1 - alpha)
confint(first_model, level = 1 - alpha/2) In generale: 1 - alpha/(p+1)
x_0 = 16. Intervallo per la media: predict(first_model, data.frame(Education = x_0), interval = "confidence", level = 1 - alpha)
Intervallo di predizione: predict(first_model, data.frame(Education = x_0), interval = "prediction", level = 1- alpha)
X0 = data.frame(Education = seq(10, 22, length=100)) Creiamo 100 "nuovi" punti e interpoliamo Conf = predict(first_model, X0, interval='confidence') Pred = predict(first_model, X0, interval='prediction')
quartz() plot(data$Education, data$Income, pch=19, xlab = 'Education', ylab = 'Income') lines(X0[,1], Conf[,'fit'], lwd=1.5) lines(X0[,1], Conf[,'lwr'], lty=2, col='red', lwd=3) lines(X0[,1], Conf[,'upr'], lty=2, col='red', lwd=3)
lines(X0[,1], Pred[,'lwr'], lty=3, col='deepskyblue', lwd=3) lines(X0[,1], Pred[,'upr'], lty=3, col='deepskyblue', lwd=3)
legend('topleft', legend = c('Fit', 'Confidence Interval', 'Prediction Interval'), lwd=2, lty = c(1,2,3) , col = c('black', 'red', 'deepskyblue') )
library(GGally) library(MASS) library(car) library(rgl) Adesso facciamo regressione lineare multipla mettendo anche un altro regressore: l'anzianità. Quindi il modello e' y_i = beta_0 + beta_1Education + beta_2Seniority + eps_i
second_model = lm(Income ~ Education + Seniority, data = data) summary(second_model)
I regressori sono Education e Seniority. Ha senso aggiungere un regressore se il p-value relativo alla sua significatività (Pr(>|t|)) è basso. I regressori con (Pr(>|t|)) alto non sono significativi: si possono togliere.
shapiro.test(second_model$residuals)
quartz() par(mfrow = c(2,2)) plot(second_model)
Controllo che omoschedasticità sia ok e che gli effetti di leva non siano forti. Bisogna sempre fare diagnostica sui residui e sulla retta di regressione, non limitarsi a guardare SOLO R2.
Modello: Average_Score = beta_0 + beta_1 * Years_Service + Eps, Eps ~ N (0, sigma^2) Si vuole cioè includere una variabile categorica nel modello lineare.
result = lm(Average_Score ~ Years_Service, data = work) summary(result)
work$Sex = as.factor(work$Sex) Importante farlo: la categorica deve diventare di tipo factor str(work) quartz() plot(work$Years_Service, work$Average_Score, main='Scatterplot di Y vs X', lwd=2, pch=19, xlab='Years of Service', ylab='Average Score', col = ifelse(work$Sex == "Male", "blue","red"))
Costruiamo una variabile dummy , ovvero una variabile binaria (solo valori 0 o 1) che codifica l'appartenenza ad una categoria. La variabile avrà infatti valore: 1 se l'osservazione è della categoria maschi, 0 altrimenti (femmine) - categoria di riferimento E' chiaro quindi che per una categorica con K livelli ci serviranno sempre K-1 variabili dummies.
Definisco la dummy e la inserisco nel dataset: work$dummy = ifelse(work$Sex == "Male",1,0) work$dummy
Il nostro modello con l'inclusione della dummy avrà la seguente forma: Average_Score = beta0 + beta1dummy + beta2Years_Service + beta3dummyYears_Service + eps
Notate che possiamo raccogliere Years_Service: Average_Score = beta0 + beta1dummy + (beta2 + beta3dummy)*Years_Service + eps Ovvero:
Average_Score = B0[g] + B1[g]*Years_Service + eps with B0[g]=beta0 se l'unità è nel gruppo per cui dummy=0 (females) B0[g]=beta0+beta1 se l'unità è nel gruppo per cui dummy=1 (males) B1[g]=beta2 se l'unità è nel gruppo per cui dummy=0 (females) B1[g]=beta2+beta3 se l'unità è nel gruppo per cui dummy=1 (males)
Fittiamo il modello: model = lm(Average_Score ~ dummy + Years_Service + dummy:Years_Service, data = work) ) Basta fare questo: model = lm(Average_Score ~ Sex + Years_Service + Sex:Years_Service, data = work) summary(model)
La dummy è rilevante se ha p-value basso. L’effetto della dummy sulla pendenza della retta si determina dal p-value di beta (dummy:Years_Service). Se è basso allora ha effetto rilevante. Se è alto allora si può togliere.
Eliminazione di una variabile non rilevante model = lm(Average_Score ~ dummy + Years_Service, data = work) summary(model)
Interpretazione del modello: modello per le donne: Y = 7.035 + 0.097 X + eps modello per gli uomini: Y = 7.035 - 2.59 + 0.097 X + eps = 4.44 + 0.097 X + eps
coefficienti = model$coefficients beta_0_donne = coefficienti[1] beta_1_donne = beta_1_uomini = coefficienti[3] beta_0_uomini = coefficienti[1] + coefficienti[2]
quartz(width = 14, height = 8) par(mfrow=c(2,2)) plot(model)
shapiro.test(model$residuals)
Guarda 6.0, Esempio 2.
first = lm(depth ~ lat + long, data = data) summary(first)
quartz() par(mfrow = c(2,2)) plot(first)
shapiro.test(first$residuals)
data$zone = as.factor(data$zone) second = lm(depth ~ lat + long + zone + zone:lat + zone:long, data = data) summary(second)
Diagnosi dei residui quartz() par(mfrow = c(2,2)) plot(second)
fourth = lm(depth ~ lat + long + I(lat^2) + I(long^2) + I(latlong) + zone + zone:lat + zone:long + zone:I(lat^2) + zone:I(long^2) + zone : I(latlong) , data = data) summary(fourth)
shapiro.test(fourth$residuals) quartz(width = 14, height = 8) par(mfrow = c(2,2)) plot(fourth)
Considerazioni:
Il processo di selezione e riduzione del modello puo' essere reso automatico con alcuni algoritmi! Utilizziamo stepAIC che procede con la stepwise selection nelle sue tre forme, a seconda dell'opzione direction specificata, e restituisce il modello che, in termini di AIC, non poteva essere ulteriormente migliorato (la regola è quella di preferire i modelli con l'AIC più basso). Si ricorda agli studenti che tra gli algoritmi di scelta delle variabili abbiamo:
"backward"): elimina predittori in sequenza dal modello iniziale. Produce una sequenza di modelli di complessita' decrescente fino ad ottenere il modello ottimo."forward"): aggiunge predittori in sequenza, usando quelli disponibili nell'argomento data di lm. Produce una sequenza di modelli di complessità crescente fino a raggiungere il modello ottimo."both"): una ricerca forward-backward che, ad ogni step, decide se includere o escludere un predittore. A differenza delle modalità precedenti, un predittore che era stato incluso/escluso in uno step precedente, può essere escluso/incluso in uno step successivo. Stepwise forward selection Definisco il modello minimo con solo l'intercetta, passando però tutto il dataset alla funzione questo permetterà a stepAIC di sapere dove prendere le variabili da aggiungere fino a raggiungere l'upper bound. miminal_model = lm(depth ~ 1, data = data)
forward = stepAIC(miminal_model, direction="forward", scope=list(lower=miminal_model, upper=fourth)) forward$anova summary(forward) quartz(width = 14, height = 8) par(mfrow = c(2,2)) plot(forward)
Parte dal modello base aggiungendo tutti i termini presenti in fourth tranne:
Stepwise backward selection backward = stepAIC(fourth, details = T, direction = "backward") backward$anova summary(backward) quartz(width = 14, height = 8) par(mfrow = c(2,2)) plot(backward)
Rimuove dal modello fourth:
Stepwise mixed selection both = stepAIC(fourth, details = T, direction = "both") both$anova summary(both) quartz(width = 14, height = 8) par(mfrow = c(2,2)) plot(both)