L’azienda Texas Realty Insights desidera analizzare le tendenze del mercato immobiliare nello stato del Texas, per fare ciò è stato fornito il dataset Real Estate Texas, il quale contiene dati storici relativi alle vendite di immobili. Le variabili all’interno del dataset sono le seguenti:
variables<-c(colnames(data))
variable_description<-c("città","anno di riferimento",
"mese di riferimento","numero totale di vendite",
"valore totale delle vendite in milioni di dollari",
"prezzo mediano di vendita in dollari",
"numero totale di annunci attivi",
"quantità di tempo necessaria per vendere tutte le inserzioni correnti al ritmo attuale delle vendite, espresso in mesi")
variable_type<-c("qualitativa nominale",
"quantitativa continua (da trattare come qualitativa
ordinale) ","qualitativa nominale (codificata in numeri)",
"quantitativa discreta","quantitativa continua (su scala di
rapporti)",
"quantitativa continua (su scala di rapporti)",
"quantitativa discreta",
"quantitativa continua (su scala di rapporti)")
summary_variable_tab<-cbind(variables,variable_description,variable_type)
colnames(summary_variable_tab)<-c("Variable","Descrizione Variabile","Tipo di Variabile")
summary_variable_tab %>%
kbl() %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| Variable | Descrizione Variabile | Tipo di Variabile |
|---|---|---|
| city | città | qualitativa nominale |
| year | anno di riferimento | quantitativa continua (da trattare come qualitativa ordinale) |
| month | mese di riferimento | qualitativa nominale (codificata in numeri) |
| sales | numero totale di vendite | quantitativa discreta |
| volume | valore totale delle vendite in milioni di dollari | quantitativa continua (su scala di rapporti) |
| median_price | prezzo mediano di vendita in dollari | quantitativa continua (su scala di rapporti) |
| listings | numero totale di annunci attivi | quantitativa discreta |
| months_inventory | quantità di tempo necessaria per vendere tutte le inserzioni correnti al ritmo attuale delle vendite, espresso in mesi | quantitativa continua (su scala di rapporti) |
Il dataset contiene un totale di otto variabili, è importante individuare il tipo di variabile in modo da riuscire a sintetizzare i dati tramite delle statistiche descrittive. Le prime tre, presentate nella tabella precedente, possono essere considerate varibili qualitative, per questo motivo è opportuno utilizzare delle tabelle di frequenza:
city_freq_df<-data.frame(
Città=names(table(data$city)),
"Frequenza Assoluta"=as.vector(table(data$city)),
"Frequenza Relativa"=round(as.vector(table(data$city)/nrow(data)), 3)
)
city_freq_df %>%
kbl(caption="Tabella di frequenza: variabile Città") %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| Città | Frequenza.Assoluta | Frequenza.Relativa |
|---|---|---|
| Beaumont | 60 | 0.25 |
| Bryan-College Station | 60 | 0.25 |
| Tyler | 60 | 0.25 |
| Wichita Falls | 60 | 0.25 |
year_freq_df<-data.frame(
Anno=names(table(data$year)),
"Frequenza Assoluta"=as.vector(table(data$year)),
"Frequenza Relativa"=round(as.vector(table(data$year)/nrow(data)), 3)
)
year_freq_df %>%
kbl(caption="Tabella di frequenza: variabile Anno") %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| Anno | Frequenza.Assoluta | Frequenza.Relativa |
|---|---|---|
| 2010 | 48 | 0.2 |
| 2011 | 48 | 0.2 |
| 2012 | 48 | 0.2 |
| 2013 | 48 | 0.2 |
| 2014 | 48 | 0.2 |
month_freq_df<-data.frame(
Mese=names(table(data$month)),
"Frequenza Assoluta"=as.vector(table(data$month)),
"Frequenza Relativa"=round(as.vector(table(data$month)/nrow(data)), 3)
)
month_freq_df$Mese<-month.name[as.integer(month_freq_df$Mese)]
month_freq_df %>%
kbl(caption="Tabella di frequenza: variabile Mese") %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| Mese | Frequenza.Assoluta | Frequenza.Relativa |
|---|---|---|
| January | 20 | 0.083 |
| February | 20 | 0.083 |
| March | 20 | 0.083 |
| April | 20 | 0.083 |
| May | 20 | 0.083 |
| June | 20 | 0.083 |
| July | 20 | 0.083 |
| August | 20 | 0.083 |
| September | 20 | 0.083 |
| October | 20 | 0.083 |
| November | 20 | 0.083 |
| December | 20 | 0.083 |
Possiamo concludere che tutte e tre le variabili qualitative sono ugualmente distribuite, ognuna di esse è distribuita uniformemente.
Le variabili quantitative, invece, sono sintetizzate dalle statistiche descrittive riportare nella seguente tabella:
summary_statistics<-describe(data[,-c(1:3)])[,-c(1,6,7,13)]
summary_statistics %>%
kbl(caption="Statistiche descrittive per variabili quantitative") %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| n | mean | sd | median | min | max | range | skew | kurtosis | |
|---|---|---|---|---|---|---|---|---|---|
| sales | 240 | 192.29167 | 79.651111 | 175.5000 | 79.000 | 423.000 | 344.000 | 0.7136206 | -0.3355200 |
| volume | 240 | 31.00519 | 16.651447 | 27.0625 | 8.166 | 83.547 | 75.381 | 0.8792182 | 0.1505673 |
| median_price | 240 | 132665.41667 | 22662.148687 | 134500.0000 | 73800.000 | 180000.000 | 106200.000 | -0.3622768 | -0.6427292 |
| listings | 240 | 1738.02083 | 752.707756 | 1618.5000 | 743.000 | 3296.000 | 2553.000 | 0.6454431 | -0.8101534 |
| months_inventory | 240 | 9.19250 | 2.303669 | 8.9500 | 3.400 | 14.900 | 11.500 | 0.0407194 | -0.1979448 |
Per individuare la variabile con volatilità più elevata bisogna utilizzare il coefficiente di variazione, ottenuto tramite il rapporto percuntuale tra deviazione standard e media:
CV_variable<-data.frame(
"Variabile"=rownames(summary_statistics),
"CV"=summary_statistics$sd/summary_statistics$mean*100)
CV_variable %>%
kbl(caption="Coefficiente di variazione delle variabili") %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| Variabile | CV |
|---|---|
| sales | 41.42203 |
| volume | 53.70536 |
| median_price | 17.08218 |
| listings | 43.30833 |
| months_inventory | 25.06031 |
La variabile Volume con il coefficiente di variazione maggiore e anche quella con l’asimmetria maggiore.
Prendendo in considerazione solo la variabile Listing, che identifica il numero di annunci attivi, è possibile suddividerla in classi e visualizzare la frequenza di queste ultime. Inoltre, per trarre conclusione, è possibile visualizzare un grafico a barre che mostra la frequenza di ogni classe:
n_classi<- round((summary(data$listings)[6]-summary(data$listings)[1])/250,0)
listing_ni<-table(cut(data$listings,breaks=n_classi, dig.lab=4))
listing_fi<-round(listing_ni/nrow(data),4)
listing_Ni<-cumsum(listing_ni)
listing_Fi<-cumsum(listing_fi)
freq_tab_listing<-as.data.frame(cbind("Frequenza Assoluta"=listing_ni,
"Frequenza Relativa"=listing_fi,
"Frequenza Assoluta Cumulata"=listing_Ni,
"Frequenza Relativa Cumulata"=listing_Fi))
freq_tab_listing %>%
kbl(caption="Tabella di Frequenza: Listing") %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| Frequenza Assoluta | Frequenza Relativa | Frequenza Assoluta Cumulata | Frequenza Relativa Cumulata | |
|---|---|---|---|---|
| (740.4,998.3] | 54 | 0.2250 | 54 | 0.2250 |
| (998.3,1254] | 20 | 0.0833 | 74 | 0.3083 |
| (1254,1509] | 20 | 0.0833 | 94 | 0.3916 |
| (1509,1764] | 67 | 0.2792 | 161 | 0.6708 |
| (1764,2020] | 19 | 0.0792 | 180 | 0.7500 |
| (2020,2275] | 1 | 0.0042 | 181 | 0.7542 |
| (2275,2530] | 2 | 0.0083 | 183 | 0.7625 |
| (2530,2785] | 15 | 0.0625 | 198 | 0.8250 |
| (2785,3041] | 24 | 0.1000 | 222 | 0.9250 |
| (3041,3299] | 18 | 0.0750 | 240 | 1.0000 |
labels<-rownames(freq_tab_listing)
freq_tab_listing$Classe<-factor(
rownames(freq_tab_listing),
levels=rownames(freq_tab_listing),
ordered=TRUE
)
ggplot(freq_tab_listing, aes(x=Classe, y=`Frequenza Relativa`)) +
geom_bar(stat="identity", fill="lightblue", color="black") +
labs(
title="Distribuzione degli annunci per classi",
x="Classi di numero di annunci",
y="Probabilità"
) +
theme_minimal() +
theme(axis.text.x=element_text(angle=45, hjust=1))
gini_index_listing<-(1-sum((freq_tab_listing$`Frequenza Relativa`)^2))/((nrow(freq_tab_listing)-1)/nrow(freq_tab_listing))
Possiamo quindi concludere che la classe con maggiore frequenza è quella tra 1510 e 1764 annunci al mese, queste classe contiene anche il valore mediano. Considerando le frequenze cumulate, possiamo concludere che il 1° quartile è nella seconda classe ((998.3,1254]), mentre l’ultimo quartile è nella 5° classe. La classe con minor frquenza è quella in cui il numero degli annunci è compreso tra 2021 e 2275. Infine, possiamo calcolare l’indice di Gini per comprendere se i dati sono distribuiti omogeneamente o meno. Il valore dell’indice di Gini è il seguente: \[G=\frac{1-\sum_{i=1}^Nf_i^2}{\frac{N-1}{N}}=\frac{1-0.1683458}{\frac{10-1}{10}}=0.9240602\] Quindi possiamo concludere che, essendo 0.9240602 vicino a 1, i dati sono relativamente equamente distribuiti nelle classi considerate.
Calcolando nuovamente l’indice di Gini, considerando la variabile City, esso ha il seguente valore: \[G=\frac{1-\sum_{i=1}^Nf_i^2}{\frac{N-1}{N}}=\frac{1-0.25}{\frac{4-1}{4}}=1\] Come già visto precedentemente, abbiamo la conferma che i dati abbiano etereogenità massima e che quindi siano equamente distribuiti.
La probabilità che presa casualmente una riga dal dataset, questa riporti Beaumont come valore della variabile City è del \(25\%\). Il calcolo utilizzato per arrivare a questo risultato è il seguente:
p1<-table(data$city)["Beaumont"]/nrow(data)
\[p_1=\frac{\text{# eventi favorevoli}}{\text{# eventi possibili}}=\frac{60}{240}=0.25\].
La probabilità che presa casualmente una riga dal dataset, la variabile month sia uguale a Luglio è dell’\(8.33\%\);
p2<-table(data$month)["7"]/nrow(data)
La probabilità che presa una riga a caso dal dataset e che appartenga al mese di dicembre 2012 è del \(1.66\%\).
p3<-table(data$year,data$month)["2012","12"]/nrow(data)
Per creare una variabile del prezzo medio è possibile moltiplicare la variabile Volume per 1 milione, andando a identificare le valore totale delle vendite espresse in dollari, per poi dividere il risultato per la variabile Sales, che indica il numero totale di vendite. In questo modo, partiamo dal presupposto che: \[\text{Volume}=\text{Sales} * \text{Price} \Rightarrow \text{Price}=\frac{\text{Volume}}{\text{Sales}}\] In questo caso il Prezzo che troviamo attraverso questa formula è esattamente il prezzo medio, in quanto è dato dal valore totale delle vendite (Volume) e dal numero di vendite registate (Sales) in un determinato periodo e città.
Una nuova colonna che può essere introdotta per valutare l’efficacia degli annunci delle vendite è data dal rapporto tra il numero di vendite e il numero di annunci attivi, in questo modo è possibile capire qual è la porzione di annunci attivi che sono effettivamente stati venduti. Questa nuova variabile è calcolata come segue: \[\text{Sales per listing rate}=\frac{\text{Sales}}{\text{Listing}}\] Considerando la tabella di frequenza e l’istogramma di questa nuova variabile, possiamo concludere che la moda, quindi la classe che si ripete con più frequenza è quella compresa tra 0.09828 e 0.1464. Perciò con maggior frequenza, la probabilità che gli annunci attivi si trasformino in vendite effettive è compresa tra il \(9.89\%\) e il \(14,64\%\). Inoltre, circa l’\(80\%\) degli annunci attivi ha una probabilità di trasformarsi in una vendita effettiva non superiore al \(14,64\%\). Questo risultato si ricava dalla tabella delle frequenze, in cui la frequenza cumulata della seconda classe è pari a \(0,8125\) e il limite superiore della classe è \(0.1464\).
data$sales_per_listing_rate<-data$sales/data$listings
n_classi<- round((summary(data$sales_per_listing_rate)[6]-summary(data$sales_per_listing_rate)[1])/0.05,0)
sales_per_listing_rate_ni<-table(cut(data$sales_per_listing_rate,breaks=n_classi, dig.lab=4))
sales_per_listing_rate_fi<-round(sales_per_listing_rate_ni/nrow(data),4)
sales_per_listing_rate_Ni<-cumsum(sales_per_listing_rate_ni)
sales_per_listing_rate_Fi<-cumsum(sales_per_listing_rate_fi)
freq_tab_sales_per_listing_rate<-as.data.frame(cbind("Frequenza Assoluta"=sales_per_listing_rate_ni,
"Frequenza Relativa"=sales_per_listing_rate_fi,
"Frequenza Assoluta Cumulata"=sales_per_listing_rate_Ni,
"Frequenza Relativa Cumulata"=sales_per_listing_rate_Fi))
freq_tab_sales_per_listing_rate %>%
kbl(caption="Tabella di Frequenza: Sales per Listing rate") %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| Frequenza Assoluta | Frequenza Relativa | Frequenza Assoluta Cumulata | Frequenza Relativa Cumulata | |
|---|---|---|---|---|
| (0.0498,0.09828] | 86 | 0.3583 | 86 | 0.3583 |
| (0.09828,0.1464] | 109 | 0.4542 | 195 | 0.8125 |
| (0.1464,0.1946] | 31 | 0.1292 | 226 | 0.9417 |
| (0.1946,0.2427] | 8 | 0.0333 | 234 | 0.9750 |
| (0.2427,0.2908] | 2 | 0.0083 | 236 | 0.9833 |
| (0.2908,0.339] | 3 | 0.0125 | 239 | 0.9958 |
| (0.339,0.3875] | 1 | 0.0042 | 240 | 1.0000 |
labels<-rownames(freq_tab_sales_per_listing_rate)
freq_tab_sales_per_listing_rate$Classe<-factor(
rownames(freq_tab_sales_per_listing_rate),
levels=rownames(freq_tab_sales_per_listing_rate),
ordered=TRUE
)
ggplot(freq_tab_sales_per_listing_rate, aes(x=Classe, y=`Frequenza Relativa`)) +
geom_bar(stat="identity", fill="lightblue", color="black") +
labs(
title="Distribuzione degli annunci per classi",
x="Classi di numero di annunci",
y="Probabilità"
) +
theme_minimal() +
theme(axis.text.x=element_text(angle=45, hjust=1))
Si possono creare delle statistiche descrittive di più variabili quantitative, condizionatamente a una variabile qualitativa, ecco alcuni esempi:
city_summary<-data %>%
group_by("City"=data$city) %>%
summarise("Sales Mean"=mean(data$sales),
"Sales Std Dev"=sd(data$sales),
"Volumes Mean"=mean(data$volume),
"Volumes Std Dev"=sd(data$volume))
city_summary %>%
kbl(caption="Statistiche Descrittive di Sales e Volume considerando la variabile City") %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| City | Sales Mean | Sales Std Dev | Volumes Mean | Volumes Std Dev |
|---|---|---|---|---|
| Beaumont | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| Bryan-College Station | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| Tyler | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| Wichita Falls | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
ggplot(city_summary, aes(x=City, y=`Sales Mean`)) +
geom_col(fill="skyblue") +
geom_errorbar(aes(ymin=`Sales Mean`-`Sales Std Dev`, ymax=`Sales Mean`+`Sales Std Dev`),
width=0.2, color="darkblue") +
labs(title="Sales per City (mean ± sd)", y="Sales", x="City") +
theme_minimal()
ggplot(city_summary, aes(x=City, y=`Volumes Mean`)) +
geom_col(fill="skyblue1") +
geom_errorbar(aes(ymin=`Volumes Mean`-`Volumes Std Dev`, ymax=`Volumes Mean`+`Volumes Std Dev`),
width=0.2, color="skyblue4") +
labs(title="Volume per City (mean ± sd)", y="Volume", x="City") +
theme_minimal()
year_summary<-data %>%
group_by("Year"=data$year) %>%
summarise("Sales Mean"=mean(data$sales),
"Sales Std Dev"=sd(data$sales),
"Volumes Mean"=mean(data$volume),
"Volumes Std Dev"=sd(data$volume))
year_summary %>%
kbl(caption="Statistiche Descrittive di Sales e Volume considerando la variabile Year") %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| Year | Sales Mean | Sales Std Dev | Volumes Mean | Volumes Std Dev |
|---|---|---|---|---|
| 2010 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 2011 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 2012 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 2013 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 2014 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
ggplot(year_summary, aes(x=Year)) +
geom_line(aes(y=`Sales Mean`, color="Media"), size=1) +
geom_point(aes(y=`Sales Mean`, color="Media"), size=2) +
geom_errorbar(aes(ymin=`Sales Mean` - `Sales Std Dev`,
ymax=`Sales Mean` + `Sales Std Dev`,
color="± Deviazione standard"),
width=0.2) +
labs(title="Sales per Year (mean ± sd)",
y="Sales",
x="Year",
color="Legenda") +
theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
ggplot(year_summary, aes(x=Year)) +
geom_line(aes(y=`Volumes Mean`, color="Media"), size=1) +
geom_point(aes(y=`Volumes Mean`, color="Media"), size=2) +
geom_errorbar(aes(ymin=`Volumes Mean` - `Volumes Std Dev`,
ymax=`Volumes Mean` + `Volumes Std Dev`,
color="± Deviazione standard"),
width=0.2) +
labs(title="Volume per Year (mean ± sd)",
y="Volume",
x="Year",
color="Legenda") +
theme_minimal()
month_summary<-data %>%
group_by("Month"=data$month) %>%
summarise("Sales Mean"=mean(data$sales),
"Sales Std Dev"=sd(data$sales),
"Volumes Mean"=mean(data$volume),
"Volumes Std Dev"=sd(data$volume))
month_summary %>%
kbl(caption="Statistiche Descrittive di Sales e Volume considerando la variabile Month") %>%
kable_styling(bootstrap_options=c("striped", "bordered"),
position="center")
| Month | Sales Mean | Sales Std Dev | Volumes Mean | Volumes Std Dev |
|---|---|---|---|---|
| 1 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 2 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 3 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 4 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 5 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 6 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 7 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 8 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 9 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 10 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 11 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
| 12 | 192.2917 | 79.65111 | 31.00519 | 16.65145 |
ggplot(month_summary, aes(x=factor(Month), y=`Sales Mean`)) +
geom_col(fill="lightgreen") +
geom_errorbar(aes(ymin=`Sales Mean` - `Sales Std Dev`, ymax=`Sales Mean` + `Sales Std Dev`),
width=0.2, color="darkgreen") +
labs(title="Sales per Month (mean ± sd)", y="Sales", x="Month") +
theme_minimal()
ggplot(month_summary, aes(x=factor(Month), y=`Volumes Mean`)) +
geom_col(fill="lightgreen") +
geom_errorbar(aes(ymin=`Volumes Mean` - `Volumes Std Dev`, ymax=`Volumes Mean` + `Volumes Std Dev`),
width=0.2, color="darkgreen") +
labs(title="Volume per Month (mean ± sd)", y="Volume", x="Month") +
theme_minimal()
In tutti e tre i casi, essendo le variabili quantitative equamente distribute, non vediamo differenza delle le statistiche descrittive tra le diverse modalità della variabile.
Tramite la visualizzazione di alcuni grafici possiamo andare ad arricchire ulteriormente le statistiche descrittive del dataset.
Possiamo utilizzare un boxplot per confrontare la distribuzione del prezzo mediano delle case tra le varie città:
ggplot(data, aes(x=city, y=median_price)) +
geom_boxplot(fill="white", linewidth=0.8) +
theme_minimal() +
theme(legend.position="none") +
labs(title="Boxplot Median Price by City",x="City", y="Median Price")
Possiamo concludere che la città con il prezzo mediano più alto è Bryan-College Station, mentre quella con il prezzo mediano più basso è Wichita Falls. La differenza tra queste due città è marcata, evidenziando una disparità significativa nel mercato immobiliare locale.
Osserviamo inoltre che tutte le città, tranne Tyler, presentano almeno un outlier, ovvero valori anomali che superano i limiti definiti dal Tukey fence. Questo suggerisce che in tali città esistono abitazioni con prezzi molto più alti rispetto alla distribuzione tipica della città.
Un altro aspetto interessante riguarda la variabilità interna: Wichita Falls non solo ha il prezzo mediano più basso, ma anche il range interquartile e l’ampiezza complessiva dei prezzi più elevati, indicando un mercato più eterogeneo. Al contrario, città come Beaumont e Tyler mostrano una distribuzione più compatta, con prezzi relativamente stabili attorno al valore mediano.
Il box può essere utilizzato anche per paragonare i dati considerando più di una variabile quantitativa, ad esempio possiamo paragonare il valore totale delle vendite considerando sia la città che l’anno:
ggplot(data, aes(x=city, y=sales, fill=factor(year))) +
geom_boxplot(position=position_dodge(width=0.8)) +
scale_fill_paletteer_d("nationalparkcolors::Arches") +
labs(
x="Città",
y="Valore totale vendite",
fill="Anno"
) +
theme_minimal()
Dal boxplot possiamo osservare che la città con la mediana del valore totale delle vendite più elevata, in tutti gli anni considerati, è Tyler, che si distingue nettamente rispetto alle altre città.
In generale, il valore totale delle vendite tende ad aumentare anno dopo anno per la maggior parte delle città: si nota una crescita graduale a Beaumont e a Bryan-College Station, dove dal 2010 al 2014 la distribuzione si sposta progressivamente verso valori più alti. Questo andamento suggerisce un mercato in espansione nel tempo.
Per Wichita Falls, al contrario, i valori rimangono pressoché stabili nel corso degli anni, con una mediana che non mostra variazioni significative. Ciò potrebbe indicare un mercato più statico.
Un altro aspetto rilevante riguarda la variabilità interna: città come Bryan-College Station e Tyler mostrano boxplot con ampiezza più elevata, segno di una maggiore eterogeneità nei valori delle vendite. Al contrario, Wichita Falls presenta box più compatti, riflettendo una distribuzione più omogenea e stabile.
Nel grafico a barre sovrapposte riportato sotto, viene paragonata la distribuzione delle vendite mensili per ogni anno e per ogni città.
data$month_as_factor<-factor(
data$month,
levels=1:12,
labels=month.name,
ordered=TRUE
)
ggplot(data, aes(x=month_as_factor, y=sales, fill=city)) +
geom_col() +
scale_fill_paletteer_d("nationalparkcolors::Arches") +
facet_wrap(~ year, ncol=2, scales="free_y") +
labs(
title="Distribuzione mensile delle vendite per città e anno",
x="Mese",
y="Totale vendite",
fill="Città"
) +
theme_minimal() +
theme(
axis.text.x=element_text(angle=45, hjust=1),
strip.text=element_text(size=12),
panel.spacing=unit(1, "lines")
)
Dal grafico possiamo osservare che il totale delle vendite presenta una chiara stagionalità, con un incremento nei mesi primaverili ed estivi e una riduzione progressiva verso la fine dell’anno. Questo andamento si ripete in tutti gli anni analizzati, suggerendo un ciclo stagionale stabile.
In generale, la città di Tyler presenta sistematicamente il volume di vendite più consistente, confermandosi come il mercato più rilevante. Al contrario, Wichita Falls mostra i livelli più bassi in ogni anno e mese considerato, confermando quanto già evidenziato nel boxplot precedente circa il suo peso ridotto nel contesto delle vendite complessive.
Infine, possiamo considerare un grafico a linee per vedere l’anadamento delle vendite:
data<-data %>%
mutate(date=as.Date(paste(year, month, "01", sep="-")))
ggplot(data, aes(x=date, y=sales, color=city, group=city)) +
geom_line(linewidth=1) +
scale_color_paletteer_d("nationalparkcolors::Arches") +
scale_x_date(
date_breaks="1 year",
date_labels="%Y"
) +
labs(
title="Andamento mensile delle vendite per città",
x="Anno",
y="Totale vendite",
color="Città"
) +
theme_minimal()
Questo grafico conferma quanto osservato in precedenza nel grafico a barre sovrapposte. Infatti, nel corso degli anni, Wichita Falls ha registrato il volume di vendite più basso, mentre Tyler ha mantenuto il volume più alto, ad eccezione del periodo subito prima dell’inizio del 2014, quando viene superata da Bryan-College Station.
Infine, anche da questo grafico si nota una flessione delle vendite all’inizio e alla fine dell’anno, mentre durante l’estate si osservano picchi più alti, confermando un andamento stagionale nelle diverse città.