library(ggplot2)
library(dplyr)
library(moments)
library(gghalves)

# Tipologia variabili
# city: categorica nominale → confronti tra mercati (boxplot, distribuzioni)
# year + month: variabili temporali discrete → trend e stagionalità
# sales, listings: quantitative discrete → intensità domanda/offerta
# volume, median_price, months_inventory: quantitative continue → valore economico, prezzi e equilibrio domanda/offerta

dati <- read.csv("realestate_texas.csv", sep = ",")
head(dati)
##       city year month sales volume median_price listings months_inventory
## 1 Beaumont 2010     1    83 14.162       163800     1533              9.5
## 2 Beaumont 2010     2   108 17.690       138200     1586             10.0
## 3 Beaumont 2010     3   182 28.701       122400     1689             10.6
## 4 Beaumont 2010     4   200 26.819       123200     1708             10.6
## 5 Beaumont 2010     5   202 28.833       123100     1771             10.9
## 6 Beaumont 2010     6   189 27.219       122800     1803             11.1
summary(dati)
##      city                year          month           sales      
##  Length:240         Min.   :2010   Min.   : 1.00   Min.   : 79.0  
##  Class :character   1st Qu.:2011   1st Qu.: 3.75   1st Qu.:127.0  
##  Mode  :character   Median :2012   Median : 6.50   Median :175.5  
##                     Mean   :2012   Mean   : 6.50   Mean   :192.3  
##                     3rd Qu.:2013   3rd Qu.: 9.25   3rd Qu.:247.0  
##                     Max.   :2014   Max.   :12.00   Max.   :423.0  
##      volume        median_price       listings    months_inventory
##  Min.   : 8.166   Min.   : 73800   Min.   : 743   Min.   : 3.400  
##  1st Qu.:17.660   1st Qu.:117300   1st Qu.:1026   1st Qu.: 7.800  
##  Median :27.062   Median :134500   Median :1618   Median : 8.950  
##  Mean   :31.005   Mean   :132665   Mean   :1738   Mean   : 9.193  
##  3rd Qu.:40.893   3rd Qu.:150050   3rd Qu.:2056   3rd Qu.:10.950  
##  Max.   :83.547   Max.   :180000   Max.   :3296   Max.   :14.900
boxplot(dati$median_price, main="Boxplot prezzo mediano")
abline(h=quantile(dati$median_price), col="red")
abline(h=quantile(dati$median_price,0.75)+1.5*IQR(dati$median_price), col="red")
abline(h=quantile(dati$median_price,0.25)-1.5*IQR(dati$median_price), col="red")

boxplot(median_price~city, data=dati, main="Prezzo mediano per città")

ggplot(dati, aes(x=city, y=median_price))+
  geom_boxplot()+
  facet_wrap(~ year)+
  theme_classic()+
  labs(title="Distribuzione median_price per città e anno", x="Città", y="Prezzo mediano")

ggplot(dati, aes(x = factor(month), y = median_price)) +
  geom_boxplot() +
  facet_grid(city ~ year) +
  theme_classic() +
  labs(title="Prezzo mediano per mese (city ~ year)", x = "Mese", y="Prezzo mediano")

ggplot(dati, aes(x = year, y = median_price, color = city, group = city)) +
  geom_line() +
  geom_point() +
  theme_classic() +
  labs(title="Andamento annuale del prezzo mediano per città",
       x="Anno", y="Prezzo mediano", color="Città")

ggplot(dati, aes(x = city, y = median_price)) +
  geom_boxplot(fill = "green") +
  stat_summary(fun = median, geom = "text",
               aes(label = paste("Median=", round(after_stat(y),1))),
               vjust = -0.7, color="red", size=4) +
  stat_summary(fun = function(x) quantile(x,0.25), geom="text",
               aes(label=paste("Q1=", round(after_stat(y),1))), vjust=1.5, size=3.5) +
  stat_summary(fun = function(x) quantile(x,0.75), geom="text",
               aes(label=paste("Q3=", round(after_stat(y),1))), vjust=-1, size=3.5) +
  theme_classic() +
  labs(title="Distribuzione del prezzo mediano per città", x="Città", y="Prezzo mediano")

ggplot(dati, aes(x = city, y = median_price, fill = factor(year))) +
  geom_bar(stat = "summary", fun = "median", position = "dodge") +
  theme_classic() +
  labs(title="Prezzo mediano (mediana) per città e anno", x="Città", y="Prezzo mediano", fill="Anno")

ggplot(dati, aes(x = city, y = volume, fill = factor(year))) +
  geom_boxplot() +
  theme_classic() +
  labs(title="Distribuzione volume per città e anno", x="Città", y="Volume", fill="Anno")

agg_mese_city_year <- dati %>%
  group_by(year, month, city) %>%
  summarise(volume_tot = sum(volume), .groups = "drop")

ggplot(agg_mese_city_year, aes(x = factor(month), y = volume_tot, fill = city)) +
  geom_col() +
  facet_wrap(~ year) +
  theme_classic() +
  labs(title="Totale volume vendite per mese (stacked)", x="Mese", y="Volume totale", fill="Città")

ggplot(agg_mese_city_year, aes(x = factor(month), y = volume_tot, fill = city)) +
  geom_col(position = "fill") +
  facet_wrap(~ year) +
  theme_classic() +
  labs(title="Totale volume vendite per mese (normalizzato)", x="Mese", y="Proporzione", fill="Città")

agg_sales_mese <- dati %>%
  group_by(year, month, city) %>%
  summarise(sales_tot = sum(sales), .groups="drop")

ggplot(agg_sales_mese, aes(x=factor(month), y=sales_tot, fill=city)) +
  geom_col() +
  facet_wrap(~year) +
  theme_classic() +
  labs(title="Totale vendite (sales) per mese, città e anno", x="Mese", y="Vendite totali")

dati$trimestre <- cut(dati$month, breaks=c(0,3,6,9,12),
                      labels=c("Trim1","Trim2","Trim3","Trim4"))
table(dati$trimestre)
## 
## Trim1 Trim2 Trim3 Trim4 
##    60    60    60    60
ggplot(dati, aes(x = trimestre, y = volume, fill = trimestre)) +
  geom_boxplot() +
  facet_wrap(~ city) +
  theme_classic() +
  labs(title="Volume per trimestre e città", x="Trimestre", y="Volume")

ggplot(dati, aes(x = trimestre, y = median_price)) +
  geom_boxplot(fill="orange") +
  facet_grid(city ~ year) +
  theme_classic() +
  labs(title="Prezzo mediano per trimestre (city ~ year)", x="Trimestre", y="Prezzo mediano")

agg_year <- aggregate(median_price ~ year, data = dati, FUN = median)

ggplot(agg_year, aes(x = year, y = median_price)) +
  geom_line() +
  geom_point() +
  theme_classic() +
  labs(title="Andamento complessivo del prezzo mediano", x="Anno", y="Prezzo mediano")

indici <- data.frame(
  variabile = c("sales","volume","median_price","listings","months_inventory"),
  media = c(mean(dati$sales), mean(dati$volume), mean(dati$median_price), mean(dati$listings), mean(dati$months_inventory)),
  mediana = c(median(dati$sales), median(dati$volume), median(dati$median_price), median(dati$listings), median(dati$months_inventory)),
  sd = c(sd(dati$sales), sd(dati$volume), sd(dati$median_price), sd(dati$listings), sd(dati$months_inventory)),
  IQR = c(IQR(dati$sales), IQR(dati$volume), IQR(dati$median_price), IQR(dati$listings), IQR(dati$months_inventory)),
  skewness = c(skewness(dati$sales), skewness(dati$volume), skewness(dati$median_price), skewness(dati$listings), skewness(dati$months_inventory)),
  kurtosis = c(kurtosis(dati$sales), kurtosis(dati$volume), kurtosis(dati$median_price), kurtosis(dati$listings), kurtosis(dati$months_inventory))
)
indici$CV <- indici$sd / indici$media
indici
##          variabile        media     mediana           sd        IQR    skewness
## 1            sales    192.29167    175.5000    79.651111   120.0000  0.71810402
## 2           volume     31.00519     27.0625    16.651447    23.2335  0.88474203
## 3     median_price 132665.41667 134500.0000 22662.148687 32750.0000 -0.36455288
## 4         listings   1738.02083   1618.5000   752.707756  1029.5000  0.64949823
## 5 months_inventory      9.19250      8.9500     2.303669     3.1500  0.04097527
##   kurtosis        CV
## 1 2.686824 0.4142203
## 2 3.176987 0.5370536
## 3 2.377038 0.1708218
## 4 2.208210 0.4330833
## 5 2.825552 0.2506031
dati$classi <- cut(dati$sales, breaks=5)
frequenze_sales <- table(dati$classi)
barplot(frequenze_sales, main="Distribuzione sales in classi", xlab="Classi sales", ylab="Frequenza", las=1)

gini.index <- function(x){
  ni <- table(x)
  fi <- ni/length(x)
  J <- length(ni)
  gini <- 1 - sum(fi^2)
  gini.normalizzato <- gini / ((J-1)/J)
  return(gini.normalizzato)
}
gini.index(dati$classi)
## [1] 0.9132812
prob_beaumont <- mean(dati$city == "Beaumont")
prob_luglio <- mean(dati$month == 7)
prob_dic2012 <- mean(dati$month == 12 & dati$year == 2012)

prob_beaumont
## [1] 0.25
prob_luglio
## [1] 0.08333333
prob_dic2012
## [1] 0.01666667
prob_and <- mean(dati$city == "Beaumont" & dati$month == 7 & dati$year == 2012)
prob_and
## [1] 0.004166667
dati$efficacia_annunci <- dati$sales / dati$listings
summary(dati$efficacia_annunci)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.05014 0.08980 0.10963 0.11874 0.13492 0.38713
ggplot(dati, aes(x = city, y = efficacia_annunci)) +
  geom_boxplot(fill="green") +
  theme_classic() +
  labs(title="Efficacia annunci per città", x="Città", y="Vendite / Annunci")

efficacia_city_year <- dati %>%
  group_by(year, city) %>%
  summarise(efficacia_media = mean(efficacia_annunci), .groups="drop")

ggplot(efficacia_city_year, aes(x=year, y=efficacia_media, color=city, group=city)) +
  geom_line() + geom_point() +
  theme_classic() +
  labs(title="Evoluzione efficacia annunci", x="Anno", y="Vendite/Annunci")

ggplot(dati, aes(x = city, y = efficacia_annunci, fill = city)) +
  geom_half_violin(side = "r", alpha = 0.6, color = NA) +
  geom_half_boxplot(side = "l", width = 0.2, outlier.shape = NA) +
  facet_wrap(~ year) +
  theme_classic() +
  theme(legend.position = "none") +
  labs(title="Distribuzione efficacia annunci per città e anno", x="Città", y="Vendite/Annunci")

Conclusioni

L’analisi del dataset evidenzia come il mercato presenti dinamiche eterogenee sia dal punto di vista territoriale sia temporale. Le differenze tra le città analizzate non si limitano ai livelli di prezzo, ma riguardano anche la stabilità del mercato, la variabilità dei volumi di vendita e l’efficienza del sistema di offerta.

In particolare, analizzando Bryan–College Station emerge come un mercato caratterizzato da prezzi medi più elevati e da una dispersione relativamente contenuta, segnale di una struttura più stabile e prevedibile. Questo profilo suggerisce un contesto adatto a strategie orientate alla continuità e alla valorizzazione nel medio-lungo periodo. Wichita Falls, al contrario, presenta valori medi inferiori e una maggiore variabilità, indicando un mercato più volatile, potenzialmente interessante in ottica di opportunità tattiche ma con un livello di rischio più elevato.

L’analisi degli indici di variabilità e forma mostra come il volume delle vendite sia la variabile più instabile e asimmetrica. La presenza di una marcata asimmetria positiva indica che i risultati economici del mercato sono trainati da pochi periodi di forte crescita, mentre la maggior parte delle osservazioni si concentra su valori più contenuti. Questo comportamento suggerisce che le performance complessive dipendono in modo significativo da fasi cicliche favorevoli, piuttosto che da una crescita costante nel tempo.

L’introduzione dell’indicatore di efficacia degli annunci di vendita, definito come rapporto tra vendite concluse e annunci attivi, consente una lettura più operativa del mercato. Città come Tyler e Beaumont mostrano valori medi più elevati di questo indicatore, mostrando una maggiore capacità di assorbimento dell’offerta e una migliore efficienza delle inserzioni. Al contrario, contesti con un numero elevato di annunci rispetto alle vendite suggeriscono una maggiore competizione tra operatori e tempi di vendita potenzialmente più lunghi.

Dal punto di vista manageriale, i risultati ottenuti forniscono indicazioni utili per una gestione differenziata delle strategie commerciali. In mercati più stabili è possibile puntare su politiche di prezzo e investimento più conservative, mentre nei contesti più variabili risulta strategico intervenire sulla qualità e sul posizionamento degli annunci, oltre che sulla tempistica di ingresso sul mercato.