1. Analisi delle variabili

City - Tipo: Qualitativa nominale
Year - Tipo: Quantitativa continua da trattare come qualitativa ordinale
Month - Tipo: Qualitativa nominale (ciclica) ma codificata in numeri
Sales - Tipo: Quantitativa discreta
Volume - Tipo: Quantitativa continua
Median_price - Tipo: Quantitativa continua
Listings - Tipo: Quantitativa discreta
Months_inventory - Tipo: Quantitativa continua

2. Caricamento del dataset

df <- read.csv("C:/Users/AlessandroTorrieri/Desktop/MasterDataScience/StatisticaDescrittiva/realestatetexas.csv")
str(df)
## 'data.frame':    240 obs. of  8 variables:
##  $ city            : chr  "Beaumont" "Beaumont" "Beaumont" "Beaumont" ...
##  $ year            : int  2010 2010 2010 2010 2010 2010 2010 2010 2010 2010 ...
##  $ month           : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ sales           : int  83 108 182 200 202 189 164 174 124 150 ...
##  $ volume          : num  14.2 17.7 28.7 26.8 28.8 ...
##  $ median_price    : num  163800 138200 122400 123200 123100 ...
##  $ listings        : int  1533 1586 1689 1708 1771 1803 1857 1830 1829 1779 ...
##  $ months_inventory: num  9.5 10 10.6 10.6 10.9 11.1 11.7 11.6 11.7 11.5 ...

3. Distribuzioni di frequenza

numeric_vars <- df %>% select_if(is.numeric)

cv_table <- numeric_vars %>%
  summarise(across(everything(), ~ sd(., na.rm = TRUE) / mean(., na.rm = TRUE))) %>%
  pivot_longer(everything(), names_to = "variabile", values_to = "cv")

cv_table <- cv_table %>%
  arrange(desc(cv))

knitr::kable(cv_table, digits = 3, caption = "Coefficiente di Variazione (CV) per ciascuna variabile numerica")
Coefficiente di Variazione (CV) per ciascuna variabile numerica
variabile cv
volume 0.537
month 0.532
listings 0.433
sales 0.414
months_inventory 0.251
median_price 0.171
year 0.001

3.1 Interpretazione del Coefficiente di Variazione (CV)

Il Coefficiente di Variazione (CV) è un indicatore statistico che consente di confrontare il grado di dispersione relativa di variabili espresse in unità o scale differenti. È particolarmente utile per identificare le variabili più instabili rispetto alla loro media.

Analisi per variabile

  • volume (CV = 0.537)
    È la variabile con la più alta variabilità relativa. Indica che il valore monetario complessivo delle transazioni immobiliari presenta forti oscillazioni tra le osservazioni, probabilmente dovute a differenze nei prezzi e nel numero di vendite.

  • month (CV = 0.532)
    Anche il mese mostra elevata variabilità, suggerendo una distribuzione non uniforme delle osservazioni nel corso dell’anno. Questo è compatibile con un mercato immobiliare influenzato da fenomeni stagionali.

  • listings (CV = 0.433) e sales (CV = 0.414)
    Entrambe mostrano una variabilità moderatamente alta, a conferma del fatto che il numero di annunci pubblicati e di vendite effettuate può cambiare significativamente tra località e periodi dell’anno.

  • months_inventory (CV = 0.251)
    Presenta una variabilità contenuta, indicando una certa stabilità nel tempo di vendita degli immobili, ovvero del numero di mesi necessari per esaurire l’inventario disponibile.

  • median_price (CV = 0.171)
    È una delle variabili più stabili, suggerendo che i prezzi mediani delle abitazioni variano poco rispetto alla media complessiva. Questo la rende un possibile indicatore strutturale del mercato.

  • year (CV = 0.001)
    Ha un coefficiente di variazione quasi nullo, come atteso per una variabile temporale con un numero limitato di modalità. La sua variabilità è trascurabile.

4. Deviazione standard e asimmetria

vars_sel <- df %>% select(sales, volume, listings)


indici_sel <- vars_sel %>%
  summarise(across(everything(), list(
    media = ~mean(., na.rm = TRUE),
    mediana = ~median(., na.rm = TRUE),
    moda = ~{
      ux <- unique(na.omit(.))
      ux[which.max(tabulate(match(., ux)))]
    },
    minimo = ~min(., na.rm = TRUE),
    massimo = ~max(., na.rm = TRUE),
    sd = ~sd(., na.rm = TRUE),
    varianza = ~var(., na.rm = TRUE),
    skewness = ~skewness(., na.rm = TRUE),
    kurtosis = ~kurtosis(., na.rm = TRUE)
  ), .names = "{.col}_{.fn}"))


indici_sel_long <- indici_sel %>%
  pivot_longer(everything(), names_to = c("variabile", "indice"), names_sep = "_") %>%
  pivot_wider(names_from = indice, values_from = value)

knitr::kable(indici_sel_long, digits = 3, caption = "Indici di posizione, variabilità e forma per Sales, Volume e Listings")
Indici di posizione, variabilità e forma per Sales, Volume e Listings
variabile media mediana moda minimo massimo sd varianza skewness kurtosis
sales 192.292 175.500 124.000 79.000 423.000 79.651 6344.300 0.718 2.687
volume 31.005 27.062 35.335 8.166 83.547 16.651 277.271 0.885 3.177
listings 1738.021 1618.500 1581.000 743.000 3296.000 752.708 566568.966 0.649 2.208

5. Distribuzione di Median Price per classi

breaks <- pretty(df$median_price, n = 6)
df$median_price_class <- cut(df$median_price, breaks = breaks, include.lowest = TRUE, right = FALSE)

freq_median_price <- as.data.frame(table(df$median_price_class))
colnames(freq_median_price) <- c("Classe", "Frequenza")

knitr::kable(freq_median_price, caption = "Distribuzione di frequenza di Median Price (classi)")
Distribuzione di frequenza di Median Price (classi)
Classe Frequenza
[6e+04,8e+04) 1
[8e+04,1e+05) 23
[1e+05,1.2e+05) 41
[1.2e+05,1.4e+05) 74
[1.4e+05,1.6e+05) 80
[1.6e+05,1.8e+05] 21
ggplot(freq_median_price, aes(x = Classe, y = Frequenza)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  theme_minimal() +
  labs(title = "Distribuzione di Median Price", x = "Classi di Prezzo Mediano", y = "Frequenza") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

6. Indice di Gini

gini.index <- function(x) {
  ni <- table(x)                
  fi <- ni / length(x)           
  fi2 <- fi^2
  J <- length(fi)                
  gini <- 1 - sum(fi2)
  gini.normalizzato <- gini / ((J - 1) / J)  
  return(gini.normalizzato)
}
gini_median_price <- gini.index(df$median_price_class)
gini_median_price
## [1] 0.8973333

L’indice di eterogeneità di Gini calcolato sulla variabile median_price_class è pari a 0.89 (valore normalizzato).

Questo valore, vicino a 1, indica una distribuzione altamente eterogenea: le osservazioni si distribuiscono in modo piuttosto uniforme tra le diverse classi di prezzo. Ciò suggerisce che il mercato immobiliare, in termini di prezzo mediano, copre una gamma ampia di valori senza una forte concentrazione in una sola fascia.

Questa elevata eterogeneità è coerente con un mercato diversificato, dove coesistono aree con prezzi molto diversi.

7. Probabilità empiriche

# 1. Probabilità che la città sia Beaumont
casi_fav_beaumont <- sum(df$city == "Beaumont")
casi_possibili <- nrow(df)
p_beaumont <- casi_fav_beaumont / casi_possibili

# 2. Probabilità che il mese sia luglio
casi_fav_july <- sum(df$month == 7)
p_july <- casi_fav_july / casi_possibili

# 3. Probabilità che sia dicembre 2012
casi_fav_december_2012 <- sum(df$month == 12 & df$year == 2012)
p_december_2012 <- casi_fav_december_2012 / casi_possibili

round(p_beaumont*100,2)
## [1] 25
round(p_july*100,2)
## [1] 8.33
round(p_december_2012*100,2)
## [1] 1.67

8. Prezzo medio ed efficacia degli annunci di vendita

df$avg_price <- df$volume / df$sales
summary(df$avg_price)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.09701 0.13294 0.15659 0.15432 0.17392 0.21323
df$listing_effectiveness <- df$sales / df$listings
summary(df$listing_effectiveness)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.05014 0.08980 0.10963 0.11874 0.13492 0.38713

Le due nuove variabili calcolate, avg_price e listing_effectiveness, forniscono informazioni utili per analizzare le performance dei prodotti e delle inserzioni:

Nel complesso, entrambe le variabili offrono strumenti quantitativi validi per supportare decisioni di marketing, pricing e ottimizzazione delle inserzioni.

9. Analisi condizionata

df <- df %>%
  filter(sales > 0, listings > 0) %>%
  mutate(
    avg_price = volume / sales,
    listing_effectiveness = sales / listings
  )

# Raggruppamento per città
summary_by_city <- df %>%
  group_by(city) %>%
  summarise(
    avg_price_mean = mean(avg_price, na.rm = TRUE),
    avg_price_sd = sd(avg_price, na.rm = TRUE),
    avg_price_cv = sd(avg_price, na.rm = TRUE) / mean(avg_price, na.rm = TRUE),
    
    effectiveness_mean = mean(listing_effectiveness, na.rm = TRUE),
    effectiveness_sd = sd(listing_effectiveness, na.rm = TRUE),
    effectiveness_cv = sd(listing_effectiveness, na.rm = TRUE) / mean(listing_effectiveness, na.rm = TRUE)
  )

# Raggruppamento per anno
summary_by_year <- df %>%
  group_by(year) %>%
  summarise(
    avg_price_mean = mean(avg_price, na.rm = TRUE),
    avg_price_sd = sd(avg_price, na.rm = TRUE),
    avg_price_cv = sd(avg_price, na.rm = TRUE) / mean(avg_price, na.rm = TRUE),
    
    effectiveness_mean = mean(listing_effectiveness, na.rm = TRUE),
    effectiveness_sd = sd(listing_effectiveness, na.rm = TRUE),
    effectiveness_cv = sd(listing_effectiveness, na.rm = TRUE) / mean(listing_effectiveness, na.rm = TRUE)
  )
 
# Raggruppamento per mese
summary_by_month <- df %>%
  group_by(month) %>%
  summarise(
    avg_price_mean = mean(avg_price, na.rm = TRUE),
    avg_price_sd = sd(avg_price, na.rm = TRUE),
    avg_price_cv = sd(avg_price, na.rm = TRUE) / mean(avg_price, na.rm = TRUE),
    
    effectiveness_mean = mean(listing_effectiveness, na.rm = TRUE),
    effectiveness_sd = sd(listing_effectiveness, na.rm = TRUE),
    effectiveness_cv = sd(listing_effectiveness, na.rm = TRUE) / mean(listing_effectiveness, na.rm = TRUE)
  )


knitr::kable(summary_by_city, caption = "Media, Deviazione Standard e CV per Città")
Media, Deviazione Standard e CV per Città
city avg_price_mean avg_price_sd avg_price_cv effectiveness_mean effectiveness_sd effectiveness_cv
Beaumont 0.1466404 0.0112321 0.0765964 0.1061332 0.0266852 0.2514316
Bryan-College Station 0.1835343 0.0151493 0.0825423 0.1473431 0.0728503 0.4944262
Tyler 0.1676768 0.0123505 0.0736566 0.0934894 0.0234561 0.2508960
Wichita Falls 0.1194300 0.0113985 0.0954406 0.1280140 0.0247173 0.1930830
knitr::kable(summary_by_year, caption = "Media, Deviazione Standard e CV per Anno")
Media, Deviazione Standard e CV per Anno
year avg_price_mean avg_price_sd avg_price_cv effectiveness_mean effectiveness_sd effectiveness_cv
2010 0.1501886 0.0232795 0.1550021 0.0997350 0.0337487 0.3383838
2011 0.1482506 0.0249384 0.1682177 0.0926772 0.0232029 0.2503623
2012 0.1508987 0.0264385 0.1752070 0.1097043 0.0280685 0.2558563
2013 0.1587052 0.0265238 0.1671262 0.1346078 0.0447954 0.3327843
2014 0.1635587 0.0317405 0.1940620 0.1570003 0.0617643 0.3934026
knitr::kable(summary_by_month, caption = "Media, Deviazione Standard e CV per Mese")
Media, Deviazione Standard e CV per Mese
month avg_price_mean avg_price_sd avg_price_cv effectiveness_mean effectiveness_sd effectiveness_cv
1 0.1456404 0.0298191 0.2047447 0.0830550 0.0230133 0.2770850
2 0.1488405 0.0251204 0.1687741 0.0878334 0.0219340 0.2497228
3 0.1511365 0.0232379 0.1537545 0.1159661 0.0345763 0.2981587
4 0.1514613 0.0261743 0.1728118 0.1253031 0.0379708 0.3030319
5 0.1582350 0.0257872 0.1629677 0.1414639 0.0502672 0.3553360
6 0.1615458 0.0234705 0.1452867 0.1423839 0.0575854 0.4044376
7 0.1568810 0.0272201 0.1735081 0.1434996 0.0740419 0.5159724
8 0.1564556 0.0282532 0.1805830 0.1419251 0.0526388 0.3708913
9 0.1565223 0.0296694 0.1895539 0.1117406 0.0348163 0.3115815
10 0.1558974 0.0325273 0.2086456 0.1119427 0.0359808 0.3214212
11 0.1542330 0.0296849 0.1924677 0.1024983 0.0293150 0.2860044
12 0.1549955 0.0270089 0.1742558 0.1173273 0.0378814 0.3228693

10. Visualizzazioni

ggplot(summary_by_city, aes(x = reorder(city, avg_price_mean), y = avg_price_mean)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  coord_flip() +
  labs(title = "Prezzo Medio per Città", x = "Città", y = "Prezzo Medio") +
  theme_minimal()

ggplot(summary_by_year, aes(x = year, y = effectiveness_mean)) +
  geom_line(group = 1, color = "darkred", size = 1.2) +
  geom_point(color = "darkred") +
  labs(title = "Efficacia media degli annunci per anno", x = "Anno", y = "Efficacia media") +
  theme_minimal()

ggplot(summary_by_month, aes(x = factor(month), y = avg_price_mean)) +
  geom_bar(stat = "identity", fill = "darkgreen") +
  labs(title = "Prezzo medio per Mese", x = "Mese", y = "Prezzo Medio") +
  theme_minimal()

ggplot(df, aes(x = reorder(city, median_price, FUN = median), y = median_price)) +
  geom_boxplot(fill = "skyblue") +
  coord_flip() +
  labs(title = "Distribuzione del Prezzo Mediano per Città", x = "Città", y = "Prezzo Mediano (USD)") +
  theme_minimal()

sales_by_month_city <- df %>%
  group_by(city, month) %>%
  summarise(total_sales = sum(sales, na.rm = TRUE), .groups = "drop")

ggplot(sales_by_month_city, aes(x = factor(month), y = total_sales, fill = city)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Totale delle Vendite per Mese e Città", x = "Mese", y = "Totale Vendite") +
  theme_minimal()

df$date <- as.Date(paste(df$year, df$month, "01", sep = "-"))

sales_trend <- df %>%
  group_by(date, city) %>%
  summarise(total_sales = sum(sales, na.rm = TRUE), .groups = "drop")

ggplot(sales_trend, aes(x = date, y = total_sales, color = city)) +
  geom_line(size = 1) +
  labs(title = "Andamento Storico delle Vendite Immobiliari", x = "Data", y = "Totale Vendite") +
  theme_minimal()

Conclusioni

L’analisi descrittiva del mercato immobiliare del Texas evidenzia dinamiche interessanti sia dal punto di vista dei prezzi che dell’efficacia delle vendite:

In sintesi, l’analisi mostra un mercato immobiliare strutturato ma variegato, con stabilità nei prezzi e ampia eterogeneità nell’efficacia delle vendite, aprendo spunti interessanti per azioni di marketing mirate, valutazioni di investimento o strategie di pubblicazione ottimizzate per area e periodo.