Preambolo
Riprendiamo il data frame AutoBi del pacchetto
insuranceData, considerando alcune delle operazioni svolte
nella precedente lezione
ATTORNEY con livelli
yes e noCLMSEX con livelli
M e Fmarried,
single, widowed e divorced (o
nella versione con widowed e divorced
accorpati nella classe previouslymarried)CLMAGEclass, contenente l’età
resa come categoriale (livelli 0-15, 16-24,
25-36, 37-50, 51-95)library(insuranceData)
data("AutoBi")
AutoBi$ATTORNEY <- factor(AutoBi$ATTORNEY)
levels(AutoBi$ATTORNEY) <- c("yes", "no")
AutoBi$CLMSEX <- factor(AutoBi$CLMSEX)
levels(AutoBi$CLMSEX) <- c("M", "F")
AutoBi$MARITAL <- factor(AutoBi$MARITAL)
levels(AutoBi$MARITAL) <- c("married", "single", "previouslymarried", "previouslymarried")
CLMAGEclass <- cut(AutoBi$CLMAGE, breaks = c(-1, 15, 24, 36, 50, 95))
AutoBi <- cbind(AutoBi, CLMAGEclass)table()La funzione table() conta quante unità del dataset
assumono ciascuna modalità di un fattore, restituendo la
distribuzione di frequenza assoluta.
Ad esempio, considerando la variabile ATTORNEY.
#>
#> yes no
#> 685 655
L’oggetto restituito è di classe table — di fatto un
array nominato — e può essere manipolato come un vettore:
#> 'table' int [1:2(1d)] 685 655
#> - attr(*, "dimnames")=List of 1
#> ..$ : chr [1:2] "yes" "no"
#> yes
#> 685
#> yes
#> 685
Mentre per la variabile MARITAL, si ha
#>
#> married single previouslymarried
#> 624 650 50
Si noti che il comando summary riporta anche il numero di valori NA presenti
#> married single previouslymarried NA's
#> 624 650 50 16
prop.table()Le frequenze relative si ottengono dividendo le frequenze assolute di ogni modalità per il totale di unità statistiche.
⚠️ In presenza di valori mancanti (
NA), usarelength()come denominatore è errato: conta anche gli NA e restituisce frequenze relative che non sommano a 1.
# Metodo errato in presenza di NA
freqrel_errata <- table(AutoBi$MARITAL) / length(AutoBi$MARITAL)
sum(freqrel_errata) # non fa 1!#> [1] 0.9880597
La soluzione corretta usa margin.table() per ottenere il
totale dei soli casi validi:
#> [1] 1324
#>
#> married single previouslymarried
#> 0.47129909 0.49093656 0.03776435
#> [1] 1
Il modo più diretto è usare direttamente
prop.table():
#>
#> married single previouslymarried
#> 0.47129909 0.49093656 0.03776435
⚠️ Non ha senso applicare
table()direttamente a una variabile quantitativa continua: si ottengono tante righe quante sono le osservazioni distinte. Occorre prima creare le classi concut().
# Poco utile: ogni età compare come categoria separata
# table(AutoBi$CLMAGE)
# Molto più leggibile dopo la classificazione
table(CLMAGEclass)#> CLMAGEclass
#> (-1,15] (15,24] (24,36] (36,50] (50,95]
#> 144 280 269 299 159
#> CLMAGEclass
#> (-1,15] (15,24] (24,36] (36,50] (50,95]
#> 0.125 0.243 0.234 0.260 0.138
💡 Mediante
round(x, k)possiamo aumentare la leggibilità di una informazione (contenuta in x) perchè ci permette di arrotondare alla k-esima cifra decimale
Quando si filtra un fattore, i livelli originali rimangono presenti
nell’oggetto table, anche se vuoti. Ad esempio, estraiamo
il data frame solo_maschi che contiene il genere per i soli
individui maschi.
solo_maschi <- AutoBi[AutoBi$CLMSEX == "M", ]$CLMSEX
table(solo_maschi) # il livello "F" compare con frequenza 0#> solo_maschi
#> M F
#> 586 0
#>
#> M
#> 586
💡 L’uso di
table()su un fattore (anziché su un vettore character) rende espliciti i livelli vuoti. Questo è utile per individuare categorie non rappresentate nei dati filtrati. Con il comandodroplevels()si eliminano i livelli vuoti
Esercizio 1
UsandoAutoBi:
1. Costruisci la tabella di frequenza assoluta diCLMSEX.
2. Calcola le frequenze relative corrispondenti conprop.table().
3. Verifica che la somma delle frequenze relative sia 1.
4. Costruisci la tabella di frequenza diLOSSclass(usa i seguenti intervalli : (0-0.5]; (0.5-2]; (2-4]; (4-8]; (8-1100]), dopo averla inclusa nel data frame, e calcola le frequenze relative cumulate concumsum().
#>
#> M F
#> 586 742
#>
#> M F
#> 0.4412651 0.5587349
#> [1] 1
# 4.
AutoBi$LOSSclass <- cut(AutoBi$LOSS, breaks = c(0, 0.5, 2, 4, 8, 1100))
freq_loss <- prop.table(table(AutoBi$LOSSclass))
cumsum(freq_loss)#> (0,0.5] (0.5,2] (2,4] (4,8] (8,1.1e+03]
#> 0.2149254 0.4567164 0.7522388 0.8977612 1.0000000
Passando due argomenti a table() si ottiene una
tabella di contingenza (o tabella a doppia entrata):
ogni cella contiene il numero di unità che presentano contemporaneamente
una coppia di modalità. Ad esempio la distribuzione congiunta di genere
e tutela legale. Dalla tabell sotto vediamo ad esempio che 325 individui
sono maschi e rappresntati da un avvocato.
#>
#> yes no
#> M 325 261
#> F 352 390
#> [1] "M" "F"
#> [1] "yes" "no"
💡 Le righe e le colonne corrispondono rispettivamente alle modalità del primo e del secondo argomento di
table().
Sommando per riga o per colonna si ottengono le distribuzioni marginali, cioè le distribuzioni di frequenza di ciascuna variabile presa singolarmente:
#>
#> M F
#> 586 742
#>
#> yes no
#> 677 651
#> [1] 1328
Possiamo verificare che il risultato coincida con quello ottenuto mediante su singola variabile
#>
#> M F
#> 586 742
#>
#> yes no
#> 685 655
prop.table() accetta un secondo argomento
margin che specifica il tipo di frequenza relativa da
calcolare:
| Chiamata | Risultato | Somme |
|---|---|---|
prop.table(tab) |
Frequenze relative congiunte | Tutta la tabella somma a 1 |
prop.table(tab, 1) |
Frequenze relative di riga | Ogni riga somma a 1 |
prop.table(tab, 2) |
Frequenze relative di colonna | Ogni colonna somma a 1 |
Quindi otteniamo le frequenze relative congiunte, l’elemento [1,1] ci dice che il 24.5% degli individui è di genere maschile ed è rappresentato da un avvocato.
#>
#> yes no
#> M 0.245 0.197
#> F 0.265 0.294
Quando invece esiami le frequenze relative di riga (di colonna) stiamo esaminando la distribuzione condizionata. Nell’esempio genere-tutela legale, le frequenze di riga ci danno informazioni della tutela legale per genere. Degli individui di genere femminile, il 47.4% è rappresentato da un legale, mentre il 52.6% non è rappresentato da un avvocato.
#>
#> yes no
#> M 0.555 0.445
#> F 0.474 0.526
Invece, analizzando le frequenze di colonna valutiamo la distribuzione del genere nei livelli della variabile tutela legale. Quindi di coloro che sono rappresentati da un avvocato, il 55.5% è di genere maschile e il 44.5% è di genere femminile.
# Distribuzione di CLMSEX condizionata ad ATTORNEY (lettura per colonna)
round(prop.table(tab1, 2), 3)#>
#> yes no
#> M 0.480 0.401
#> F 0.520 0.599
Quando due variabili (\(X\) e \(Y\)) sono su scala nominale parliamo di analisi dell’associazione (quando sono su scala ordinale si parla di analisi della cograduazione, quando abbiamo due continue si parla di analisi della correlazione).
E’ importante distinguere tra:
| Ruolo | Denominazione alternativa | Significato |
|---|---|---|
| Variabile risposta | Variabile dipendente | La variabile che vogliamo spiegare |
| Variabile esplicativa | Variabile indipendente | La variabile la cui conoscenza ci aiuta a spiegare |
Svilupperemo il discorso considerando una relazione di tipo asimmetrico.
Una tabella a doppia entrata è utile per indagare se due variabili sono associate. La tabella da esaminare è quella delle frequenze condizionate rispetto alla variabile esplicativa.
⚠️ Il confronto va fatto utilizzando le frequenze relative.
⚠️ La parola “simili” lascia aperta la questione di quando le differenze osservate siano sufficientemente grandi da escludere l’indipendenza. Rispondere in modo rigoroso richiede strumenti di statistica inferenziale.
ATTORNEY e LOSSCi aspettiamo che il ricorso all’avvocato (ATTORNEY,
variabile risposta) dipenda dall’ammontare del danno subito
(LOSS, variabile esplicativa).
#>
#> yes no
#> 0.511194 0.488806
#>
#> (0,0.5] (0.5,2] (2,4] (4,8] (8,1.1e+03]
#> yes 49 104 263 147 122
#> no 239 220 133 48 15
# Frequenze condizionate: ATTORNEY | LOSSclass (colonne)
prof_col <- prop.table(tabella_al, 2)
# Affiancate alla distribuzione marginale di ATTORNEY
cbind(round(prof_col, 3), marginale = round(tot, 3))#> (0,0.5] (0.5,2] (2,4] (4,8] (8,1.1e+03] marginale
#> yes 0.17 0.321 0.664 0.754 0.891 0.511
#> no 0.83 0.679 0.336 0.246 0.109 0.489
💡 Interpretazione: la proporzione di “yes” cresce sistematicamente al crescere del danno — dal ~17% per danni sotto i 500$ all’89% per danni superiori agli 8000$. Le due variabili sono chiaramente associate. Si ricorre molto più frequentemente all’avvocato se il danno è maggiore.
Può essere utile, in questa fase esplorativa analizzare le deviazioni dei profili colonna dalla marginale di colonna
dev_prof_col <- prof_col -
matrix(rep(tot,ncol(prof_col)),
nrow(prof_col), ncol(prof_col),
byrow = F)
dev_prof_col#>
#> (0,0.5] (0.5,2] (2,4] (4,8] (8,1.1e+03]
#> yes -0.3410551 -0.1902064 0.1529474 0.2426521 0.3793169
#> no 0.3410551 0.1902064 -0.1529474 -0.2426521 -0.3793169
Risulta evidente, ancor più chiaramente di prima, che il ricorso all’avvocato varia a seconda dell’ammontare del danno subito. Le differenze più marcate dal profilo medio si riscontrano nelle due classi estreme.
tabella_sa <- table(AutoBi$CLMSEX, CLMAGEclass)
prof_col <- prop.table(tabella_sa, 2)
round(prof_col, 3)#> CLMAGEclass
#> (-1,15] (15,24] (24,36] (36,50] (50,95]
#> M 0.462 0.396 0.476 0.411 0.459
#> F 0.538 0.604 0.524 0.589 0.541
💡 Interpretazione: le distribuzioni condizionate del sesso per classe di età non mostrano variazioni sistematiche marcate. Le due variabili appaiono quasi indipendenti.
dev_prof_col <- prof_col -
matrix(rep(tot,ncol(prof_col)),
nrow(prof_col), ncol(prof_col),
byrow = F)
dev_prof_col#> CLMAGEclass
#> (-1,15] (15,24] (24,36] (36,50] (50,95]
#> M -0.04965557 -0.11551058 -0.03553860 -0.10041962 -0.05207453
#> F 0.04965557 0.11551058 0.03553860 0.10041962 0.05207453
⚠️ Se si invertisse il ruolo delle variabili si avrebbe una lettura diversa. Tuttavia nel caso vi fosse indipendenza, essa esisterebbe qualunque sia la lettura.
Esercizio 2
Costruisci la tabella congiunta diCLMSEXeMARITAL:
1. Calcola le distribuzioni marginali di entrambe le variabili.
2. Calcola le frequenze condizionate diMARITALdatoCLMSEX(ogni riga somma a 1).
3. Affianca le frequenze condizionate alla distribuzione marginale diMARITALconrbind().
4. Le due variabili sembrano associate?
#>
#> M F
#> 580 736
#>
#> married single previouslymarried
#> 622 644 50
#>
#> married single previouslymarried
#> M 0.467 0.509 0.024
#> F 0.477 0.474 0.049
# 3.
marginale_marital <- round(prop.table(table(AutoBi$MARITAL)), 3)
rbind(cond, marginale = marginale_marital)#> married single previouslymarried
#> M 0.467 0.509 0.024
#> F 0.477 0.474 0.049
#> marginale 0.471 0.491 0.038
# 4. Le distribuzioni condizionate di MARITAL per sesso
# non differiscono molto dalla marginale → variabili tendenzialmente indipendentiEsercizio 3 — Donne al volante, pericolo costante?
Esplora se il sesso del richiedente è associato all’ammontare del danno subito.
- Crea
LOSSclass_qsuddividendoLOSSin base ai quartili (quantile()), coninclude.lowest = TRUE.
- Costruisci la tabella congiunta di
CLMSEXeLOSSclass_q.
- Calcola le frequenze di
CLMSEXcondizionate aLOSSclass_q(colonne).
- Calcola le frequenze di
LOSSclass_qcondizionate aCLMSEX(righe).
- Confronta le distribuzioni condizionate con le rispettive marginali. Le variabili sono associate?
#>
#> M F
#> 586 742
#>
#> M F
#> 0.4412651 0.5587349
# 2.
AutoBi$LOSSclass_q <- cut(AutoBi$LOSS,
breaks = quantile(AutoBi$LOSS),
include.lowest = TRUE)
levels(AutoBi$LOSSclass_q)#> [1] "[0.005,0.64]" "(0.64,2.33]" "(2.33,3.99]" "(3.99,1.07e+03]"
#>
#> [0.005,0.64] (0.64,2.33] (2.33,3.99] (3.99,1.07e+03]
#> M 149 140 156 141
#> F 184 191 176 191
#>
#> [0.005,0.64] (0.64,2.33] (2.33,3.99] (3.99,1.07e+03]
#> M 0.447 0.423 0.470 0.425
#> F 0.553 0.577 0.530 0.575
#>
#> [0.005,0.64] (0.64,2.33] (2.33,3.99] (3.99,1.07e+03]
#> M 0.254 0.239 0.266 0.241
#> F 0.248 0.257 0.237 0.257
# 6.
marginale_loss <- round(prop.table(table(AutoBi$LOSSclass_q)), 3)
rbind(round(prop.table(tab_sq, 1), 3),
marginale = marginale_loss)#> [0.005,0.64] (0.64,2.33] (2.33,3.99] (3.99,1.07e+03]
#> M 0.254 0.239 0.266 0.241
#> F 0.248 0.257 0.237 0.257
#> marginale 0.251 0.249 0.250 0.250
# Le distribuzioni condizionate di LOSSclass per sesso
# sono molto simili alla marginale → le variabili sembrano indipendentiCon tre argomenti, table() restituisce un array
tridimensionale: viene mostrata una tabella a due entrate per
ogni livello della terza variabile.
#> 'table' int [1:2, 1:5, 1:2] 25 103 52 83 127 55 65 14 56 6 ...
#> - attr(*, "dimnames")=List of 3
#> ..$ : chr [1:2] "yes" "no"
#> ..$ : chr [1:5] "(0,0.5]" "(0.5,2]" "(2,4]" "(4,8]" ...
#> ..$ : chr [1:2] "M" "F"
#> , , = M
#>
#>
#> (0,0.5] (0.5,2] (2,4] (4,8] (8,1.1e+03]
#> yes 25 52 127 65 56
#> no 103 83 55 14 6
#>
#> , , = F
#>
#>
#> (0,0.5] (0.5,2] (2,4] (4,8] (8,1.1e+03]
#> yes 24 52 131 81 64
#> no 133 136 78 34 9
#> [1] 55
⚠️ La lettura di tabelle a più di tre entrate diventa rapidamente complessa. In pratica si va raramente oltre le tre variabili.
I dati seguenti riportano la distribuzione percentuale di uno studio sull’incidenza dell’abitudine a bere caffè nello svilupparsi del cancro al polmone. Le variabili in gioco sono:
| Simbolo | Variabile |
|---|---|
| \(C\) | abitudine a bere caffè |
| \(T\) | avere il cancro al polmone |
| \(F\) | abitudine al fumo |
Anche in questo caso i dati a tre variabili si rappresentano naturalmente come un array tridimensionale \(2 \times 2 \times 2\): le prime due dimensioni corrispondono a Cancro e Caffè, la terza all’abitudine al fumo.
# Costruiamo l'array 3D: dim = c(Cancro, Caffe, Fumo)
# Cella [i, j, k] = conteggio con Cancro=i, Caffe=j, Fumo=k
caffe <- array(
data = c(
# Fumatori
41, 6, # cancro sì: caffè sì, caffè no
8, 1, # cancro no: caffè sì, caffè no
# Non fumatori
4, 4, # cancro sì: caffè sì, caffè no
17, 19 # cancro no: caffè sì, caffè no
),
dim = c(2, 2, 2),
dimnames = list(
Cancro = c("sì", "no"),
Caffe = c("sì", "no"),
Fumo = c("sì", "no")
)
)
caffe#> , , Fumo = sì
#>
#> Caffe
#> Cancro sì no
#> sì 41 8
#> no 6 1
#>
#> , , Fumo = no
#>
#> Caffe
#> Cancro sì no
#> sì 4 17
#> no 4 19
Sommando sulla terza dimensione (abitudine al fumo) otteniamo la tabella marginale:
#> Caffe
#> Cancro sì no
#> sì 45 25
#> no 10 20
#> [1] 100
#> Caffe
#> Cancro sì no
#> sì 0.45 0.25
#> no 0.10 0.20
# Profili colonna: distribuzione di Cancro per abitudine al caffè
round(prop.table(tab_TC, margin = 2), 2)#> Caffe
#> Cancro sì no
#> sì 0.82 0.56
#> no 0.18 0.44
📌 Dalla tabella sembra evidente una forte dipendenza: il 82% dei bevitori di caffè ha il cancro al polmone, contro il 56% dei non bevitori. L’abitudine al caffè sembrerebbe una “causa” del cancro.
Controllando per la variabile fumo, il quadro cambia radicalmente:
#> Caffe
#> Cancro sì no
#> sì 41 8
#> no 6 1
#> Caffe
#> Cancro sì no
#> sì 4 17
#> no 4 19
#> Caffe
#> Cancro sì no
#> sì 87.2 88.9
#> no 12.8 11.1
#> Caffe
#> Cancro sì no
#> sì 50 47.2
#> no 50 52.8
📌 Nelle due sottopopolazioni il cancro al polmone e l’abitudine al caffè sono quasi indipendenti: tra i fumatori il cancro colpisce l’87% dei bevitori di caffè e l’89% dei non bevitori; tra i non fumatori il 50% e il 47% rispettivamente. Le differenze sono trascurabili in entrambi i gruppi.
Vediamo la distribuzione dell’abitudine al fumo per abitudine al caffè
#> Fumo
#> Caffe sì no
#> sì 47 8
#> no 9 36
#> Fumo
#> Caffe sì no
#> sì 85.5 14.5
#> no 20.0 80.0
La variabile confondente è l’abitudine al fumo (\(F\)): i bevitori di caffè sono molto più spesso fumatori rispetto ai non bevitori, e il fumo è la vera causa del cancro al polmone. Nella tabella marginale questo effetto si trasferisce artificialmente al caffè.
Il cancro (\(T\)) e il caffè (\(C\)) sono marginalmente dipendenti, ma indipendenti condizionatamente all’abitudine al fumo (\(F\)).
⚠️ Dipendenza non è causalità. Anche in assenza di paradossi come questo, una associazione osservata nei dati non implica che una variabile sia “causa” dell’altra. Può esistere semplicemente un legame statistico mediato da una terza variabile confondente. È la conoscenza del problema — non i soli dati — a permettere di non incorrere in errori interpretativi come quello storico sul caffè e il cancro al polmone.
barplot()Il diagramma a barre è la rappresentazione grafica
standard per una variabile qualitativa. Si costruisce applicando
barplot() a una tabella di frequenze. Come alternativa si
può usare il grafico a torta pie, ma sebbene diffusissimo
ha diversi limiti (si veda la Note in help(pie))
| Grafico | Variabile | Funzione principale |
|---|---|---|
| Diagramma a barre | Qualitativa | barplot() |
| Grafico a torta | Qualtitativa | pie() |
Continuiamo con il data frame AutoBi di
InsuranceData.
Per rappresentare le frequenze della variabile relativa alla tutela legale abbiamo
tabella_att <- table(AutoBi$ATTORNEY)
barplot(tabella_att,
main = "Ricorso all'avvocato",
xlab = "Avvocato",
ylab = "Frequenza assoluta",
col = c("darkblue", "darkred"))Con le frequenze relative l’asse delle ordinate diventa direttamente interpretabile come proporzione:
barplot(prop.table(tabella_att),
main = "Ricorso all'avvocato",
xlab = "Avvocato",
ylab = "Frequenza relativa",
col = c("darkblue", "darkred"),
ylim = c(0, 0.7))Con horiz = TRUE le barre diventano orizzontali — utile
quando le etichette delle modalità sono lunghe:
barplot(sort(prop.table(table(AutoBi$MARITAL)), decreasing = TRUE),
main = "Stato civile",
xlab = "Frequenza relativa",
col = c("darkgreen", "darkblue", "darkred"),
horiz = TRUE,
cex.names = 0.45,
las = 1) # las=1: tutte le etichette orizzontali💡 Ordinare le barre (
sort()) rende il confronto tra modalità più immediato, soprattutto quando le frequenze sono simili.
Per una tabella a doppia entrata possiamo visualizzare le frequenze
assolute (o relative) congiunte sempre mediante barplot.
Con beside = TRUE le barre sono
affiancate; con beside = FALSE (default)
sono impilate.
tab2 <- table(AutoBi$CLMSEX, AutoBi$ATTORNEY)
barplot(tab2,
beside = TRUE,
main = "Ricorso all'avvocato per genere",
xlab = "Avvocato",
ylab = "Frequenza assoluta",
ylim = c(0,500),
col = c("darkblue", "darkred"),
legend = rownames(tab2),
args.legend = list(
title = "Genere",
x = "topright",
bty = "n"
))barplot(prop.table(tab2),
beside = TRUE,
main = "Ricorso all'avvocato per sesso",
xlab = "Avvocato",
ylab = "Frequenza relativa",
ylim = c(0,0.5),
col = c("darkblue", "darkred"),
legend = rownames(tab2),
args.legend = list(
title = "Sesso",
x = "topright",
bty = "n"
))Tuttavia il confronto più interessante può essere fatto utilizzando le distribuzioni condizionate, ad esempio consideriamo il barplot con barre impilate per rappresentare la distribuzione del genere per tutela legale.
# Barre impilate con frequenze condizionate di colonna
tab_cond <- prop.table(tab2, 2)
barplot(tab_cond,
beside = FALSE,
main = "Distribuzione del sesso per avvocato",
xlab = "Avvocato",
ylab = "Frequenza relativa",
ylim = c(0, 1.35),
col = c("darkblue", "darkred"),
legend = rownames(tab_cond),
args.legend = list(title = "Sesso", bty = "n"))💡 Il barplot impilato con frequenze condizionate è il complemento grafico della tabella di frequenze condizionate: le colonne di altezza uguale indicherebbero indipendenza tra le variabili.
Il diagramma a torta rappresenta la distribuzione di una variabile qualitativa attraverso settori circolari proporzionali alle frequenze relative. Può essere una scelta quando le categorie sono poche e si vuole enfatizzare il contributo di ciascuna al totale.
freq_marital <- prop.table(table(AutoBi$MARITAL))
pie(freq_marital,
main = "Stato civile",
col = c("darkgreen", "darkblue", "darkred", "darkorange"),
labels = paste0(names(freq_marital), "\n",
round(freq_marital * 100, 1), "%"))💡 Con
paste0()si costruiscono etichette informative che combinano il nome della categoria e la percentuale corrispondente direttamente sul grafico, evitando la necessità di una legenda separata.
⚠️ Il diagramma a torta rende difficile confrontare visivamente settori di dimensione simile — in questi casi il diagramma a barre è generalmente preferibile.
Esercizio 4
Usando il datasetCars93(MASS):
1. Costruisci il barplot della variabileType.
2. Ordina le barre in senso decrescente di frequenza.
3. Costruisci un barplot affiancato che mostri la distribuzione diTypeseparatamente perOrigin(USA vs non-USA).
💡 Usalegend = TRUEnel barplot per aggiungere automaticamente la legenda.
# 3.
tab_ot <- table(Cars93$Origin, Cars93$Type)
barplot(tab_ot,
beside = TRUE,
main = "Tipo di auto per origine",
legend = TRUE,
args.legend = list(bty = "n"))# O in alternativa
tab_to <- table(Cars93$Type, Cars93$Origin)
barplot(tab_to,
beside = TRUE,
main = "Tipo di auto per origine",
legend = TRUE,
args.legend = list(bty = "n"))| Grafico | Funzione | Variabili |
|---|---|---|
| Barre semplice | barplot(table(x)) |
1 qualitativa |
| Barre affiancate | barplot(table(x,y), beside=TRUE) |
2 qualitative |
| Barre impilate condizionate | barplot(prop.table(table(x,y),2), beside=FALSE) |
2 qualitative |
# TABELLA DI FREQUENZA SEMPLICE
table(x) # frequenze assolute
prop.table(table(x)) # frequenze relative
margin.table(table(x)) # totale validi (senza NA)
cumsum(prop.table(table(x))) # frequenze relative cumulate
droplevels(x) # rimuove livelli vuoti
# TABELLA A DOPPIA ENTRATA
tab <- table(x, y) # frequenze assolute congiunte
margin.table(tab, margin = 1) # marginale di x (riga)
margin.table(tab, margin = 2) # marginale di y (colonna)
prop.table(tab) # frequenze relative congiunte
prop.table(tab, margin = 1) # frequenze condizionate di riga
prop.table(tab, margin = 2) # frequenze condizionate di colonna
# AFFIANCARE CONDIZIONATE E MARGINALE
cbind(prop.table(tab, 2), marginale = prop.table(table(x)))
rbind(prop.table(tab, 1), marginale = prop.table(table(y)))
# TABELLA A TRE ENTRATE
tab3 <- table(x, y, z) # array 3D
tab3[,,k]; tab3[,j,k]; tab3[i,j,k]
apply(tab3, c(1,2), sum) # sommare su terza dimensione
# ── BARPLOT ────────────────────────────────────────────────────────────────
barplot(table(x)) # frequenze assolute
barplot(sort(table(x), decreasing=TRUE)) # barre ordinate per frequenza
barplot(table(x), horiz=TRUE, las=1) # in orizzontale con ruotamento etichette
barplot(prop.table(table(x))) # frequenze relative
# Doppia entrata
tab <- table(x, y)
# Barplot affiancati
barplot(tab, beside=TRUE, legend=rownames(tab),
args.legend=list(bty="n", title="Gruppo"))
# Barplot impilati (per condizionate)
barplot(prop.table(tab, 2), beside=FALSE,
legend=rownames(tab))
# Opzioni grafiche comuni
barplot(..., col=c("darkblue","darkred"), main="Titolo",
xlab="x", ylab="y", ylim=c(0, 0.8))
# Grafico a torta
pie(prop.table(table(x)))
# Arrotondamento
round(x, k) # Arrotondamento x a k decimali