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")
Tabella di frequenza: variabile Città
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")
Tabella di frequenza: variabile Anno
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")
Tabella di frequenza: variabile Mese
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")
Statistiche descrittive per variabili quantitative
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")
Coefficiente di variazione delle variabili
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")
Tabella di Frequenza: Listing
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")
Tabella di Frequenza: Sales per Listing rate
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")
Statistiche Descrittive di Sales e Volume considerando la variabile City
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")
Statistiche Descrittive di Sales e Volume considerando la variabile Year
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")
Statistiche Descrittive di Sales e Volume considerando la variabile Month
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à.