Descrizione e Obiettivi del progetto

Questo studio approfondisce l’evoluzione del mercato immobiliare in quattro città chiave dello Stato del Texas tra il 2010 e il 2014. L’obiettivo è fornire insight statistici e visivi che supportino le decisioni strategiche di vendita e ottimizzazione delle inserzioni immobiliari.

Librerie utilizzate

Si utilizzano le librerie: dplyr, ggplot2, tidyr, e moments.

Caricamento delle librerie necessarie

library(dplyr)
library(moments)
library(ggplot2)
library(tidyr)

Importazione dati

data <- read.csv("realestate_texas.csv", sep = ",")
str(data)
## '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 ...

#Analisi delle variabili

il dataset “realestate_texas” è composto di 240 unità statistiche e 8 variabili così strutturate:

  • city” rappresenta la città di vendita dell’immobile, di tipo stringa. E’ una variabile qualitativa su scala nominale. Le modalità assunte da “city”, si possono confrontare solo in termini di uguaglianza.

  • year” rappresenta l’anno di vendita dell’immobile, di tipo numero intero. E’ una variabile numerica continua, su scala di intervalli. Si può stabilire un ordine tra i valori di “year”, infatti 2011 è più recente di 2010 e non c’è uno zero assoluto. In questo progetto verrà utilizzata per descrivere o classificare le osservazioni, pertanto sarà trattata come variabilie qualitativa ordinale.

  • month” rappresenta il mese di vendita dell’immobile, di tipo numero intero. E’ una variabile qualitativa su scala nominale. Anche se rappresentata da numeri (codificata), i mesi non hanno un ordine universale (è una variabile ciclica) e viene trattata come etichetta o categoria dei dati. Nel prosieguo dell’analisi si effettua un approfondimento sulle variabili che esprimo una dimensione temporale (”year” e “month”).

  • sales” rappresenta il numero di immobili venduti, di tipo numero intero. E’ una variabile numerica discreta, su scala di rapporti. La variabile assume valori interi, non può essere suddivisa in sotto-intervalli sempre più piccoli, posso fare confronti tra le quantità vendute e posso avere uno zero assoluto che assume significato, ossia zero immobili venduti.

  • volume” rappresenta le vendite di immobili in milioni di dollari, di tipo decimale. E’ una variabile numerica continua, su scala di rapporti. La variabile assume valori decimali, posso fare confronti tra i valori di vendita e posso avere vendite di valore pari a zero.

  • median_price” rappresenta il prezzo mediano di vendita degli immobili, di tipo decimale. E’ una variabile numerica continua, su scala di rapporti. La variabile assume valori decimali, posso fare confronti tra i prezzi di vendita mediani e posso avere un prezzo di vendita mediano di zero (almeno teoricamente, qualora almeno metà degli immobili abbia un prezzo di vendita di zero).

  • listings” rappresenta il numero totale di annunci immobiliari attivi, di tipo intero. E’ una variabile numerica discreta, su scala di rapporti. La variabile assume valori interi e non può essere suddivisa in sottointervalli sempre più piccoli, posso fare confronti tra il numero di annunci attivi e posso avere uno zero assoluto che assume significato, ossia zero annunci attivi.

  • months_inventory” rappresenta il numero di mesi necessario per vendere gli immobili di tutti gli annunci attivi, di tipo decimale. E’ una variabile numerica continua, su scala di rapporti. months_inventory può assumere valori decimali, si può stabilire un ordine tra i valori della variabile e posso avere uno zero assoluto che assume senso, infatti posso metterci zero mesi per vendere un immobile (almeno teoricamente, per esempio se lo vendo il giorno stesso dell’annuncio).

Analisi da condurre sulle variabili

  1. Analisi di distribuzione dei ricavi complessivi, del prezzo mediano e dei volumi di vendita per città, nel tempo.

Verranno utilizzate a tal fine le variabili “sales”, “volume”, “median_price”, “city”, “year”, “month”.

  1. Si cercherà di identificare il periodo e il luogo in cui si sono generati maggiori ricavi dalle vendite immobiliari con un deep dive nell’analisi di possibili pattern su prezzi mediani e quantità venduta.

  2. Variabili “sales”, “volume”, “median_price”: sono variabili quantitative numeriche per le quali possiamo valutare i trend nel tempo attraverso l’analisi della serie storica di ogni variabile.

  3. Variabili “year” e “month”: spesso la dimensione temporale è rappresentata da variabili di tipo continuo su scala di intervalli, in tal caso infatti, si possono stabilire sotto-intervalli di tempo sempre più piccoli tra un anno e l’altro (trimestri, mesi, giorni, ore, minuti, ecc ecc) e non esiste uno zero assoluto.

    Nel nostro dataset non abbiamo una variabile di tipo data, ma possiamo crearla a partire dalle informazioni su anno e mese. Questo ci tornerà utile nell’analisi delle serie storiche delle vendite. Infatti, quando si misura una variabile in tempi diversi si parla di serie storica. Per farlo, avremmo bisogno di rappresentare graficamente il tempo sull’asse delle x, per avere un asse temporale ordinato e interpretabile e che ci permetta di osservare diversi orizzonti temporali in un unico grafico.

  4. Si calcoleranno inoltre indici di posizione, di variabilità e di forma che ci permettano di identificare dove si concentrano i dati, quanto si disperdono e che forma hanno le loro distribuzioni.

  1. “city” è una variabile categoriale per la quale andremo a creare una distribuzione di frequenza osservando in quali città si sono concentrate le vendite. Inoltre, in combinazione con la variabile “year” visualizzeremo graficamente come si sono distribuite le vendite geograficamente e nel tempo.

    Prima di performare questa analisi, valutiamo quanti valori diversi assumono le variabili “city” e “year”.

Modalità delle variabili city e year

table(data$city)
## 
##              Beaumont Bryan-College Station                 Tyler 
##                    60                    60                    60 
##         Wichita Falls 
##                    60
table(data$year)
## 
## 2010 2011 2012 2013 2014 
##   48   48   48   48   48

Dato che le variabili assumono pochi valori non verranno create delle classi per queste variabili.

  1. Analisi degli annunci immobiliari

    i. “listings” e “months_inventory” sono due variabili quantitative numeriche di cui: “listings” è discreta ma assume molti valori (è granulare) e “months_inventory” è continua. Possiamo valutare gli indici di posizione, variabilità e forma per comprendere alcune dinamiche di alto livello del mercato immobiliare.

    ii. Queste variabili verranno analizzate per valutare la dinamicità del mercato immobiliare per comprendere le dinamiche dal lato dell’offerta immobliare segmentando in funzione della geografia e del tempo.

Calcolo degli indici

  1. Si calcoleranno gli indici di posizione, variabilità e forma per le variabili quantitative.
  2. Si calcoleranno gli le distribuzioni di frequenze, la moda, l’indice di eterogeneità di Gini per le variaibli qualitative.

Analisi variabili quantitative

Funzione calculate_statitics e tabella delle statistiche

library("dplyr")
library("moments")

calculate_statistics <- function(x) {
  c(
    mean     = mean(x),
    median   = median(x),
    range    = range(x),
    std_dev  = sd(x),
    coeff_var = sd(x) / mean(x),
    skewness  = skewness(x),
    kurtosis  = kurtosis(x) - 3  # Normalizzazione indice di curtosi
  )
}

#richiamando la funzione calculate_statistics viene creato un dataframe per alcune delle variaibili del dataset
statistics_table <- 
  data %>%
  summarise(across(c(volume, sales, median_price, listings, months_inventory), calculate_statistics)) %>%
  t() %>%
  as.data.frame()

#rinominare le colonne della tabella
colnames(statistics_table) <- c("mean", "median", "min", "max", "std_dev", "coeff_var", "skewness", "kurtosis")
statistics_table <- round(statistics_table, 2)

#formattare i valori per rendere più leggibili senza alterare il formato originario
knitr::kable(
  statistics_table,
  caption = "Analisi dei principali indici",
  digits = 2,
  format.args = list(big.mark = ".", decimal.mark = ",")
)
Analisi dei principali indici
mean median min max std_dev coeff_var skewness kurtosis
volume 31,01 27,06 8,17 83,55 16,65 0,54 0,88 0,18
sales 192,29 175,50 79,00 423,00 79,65 0,41 0,72 -0,31
median_price 132.665,42 134.500,00 73.800,00 180.000,00 22.662,15 0,17 -0,36 -0,62
listings 1.738,02 1.618,50 743,00 3.296,00 752,71 0,43 0,65 -0,79
months_inventory 9,19 8,95 3,40 14,90 2,30 0,25 0,04 -0,17

volume: le vendite medie complessivi si attestano a 31 milioni di dollari, un valore leggermente più alto rispetto alla mediana di 27. L’indice di asimmetria di 0,88 indica infatti un’asimmetria positiva, riflettendo una maggior frequenza di valori bassi. La deviazione standard di quasi 17 milioni è pari a ca. il 54% del valore medio a indicazione di una variabilità dei dati leggermente alta. L’indice di curtosi di 0,18 indica una distribuzione leptocurtica con possibili valori di outlier molto distanti dalla media. il valore mimino e massimo sono circa 4 volte più basso/3 volte più alto della media.

sales: i volumi di vendita medi complessivi si attestano a 192 unità, un valore leggermente più alto rispetto alla mediana di 172. L’indice di asimmetria di 0,72 indica infatti un’asimmetria positiva, riflettendo una maggior frequenza di valori bassi. La deviazione standard di 79 unità è pari a ca. il 41 % del valore medio a indicazione di una variabilità dei dati abbastanza contenuta. L’indice di curtosi di -0,31 indica una distribuzione platicurtica ossia una distribuzione più larga e piatta rispetto alla normale e eventi estremi teoricamente meno presenti. Il valore mimino e massimo sono circa 2.5-2 volte più basso/alto rispetto a media.

median_price: il prezzo mediano medio di tuti gli immobili venduti si attesta a circa 133 mila dollari, un valore marginalmente più basso rispetto alla mediana di 134.500. L’indice di asimmetria negativa di -0,36, riflette una maggior frequenza di valori alti. La deviazione standard di circa 23 milioni di euro è pari a ca. il 17% del valore medio a indicazione di una stabilità relativa dei dati. L’indice di curtosi di -0,62 indica una distribuzione platicurtica ossia una distribuzione più larga e piatta rispetto alla normale e eventi estremi teoricamente meno presenti. il valore mimino quasi 2 volte più basso rispetto a media e il valore massimo è piuttosto vicino al valore medio.

Le osservazioni di questa distribuzione rappresentano i prezzi mediani calcolati per ogni mese di ogni anno in ogni città rispetto alle vendite immobiliari. L’asimmetria e la forma della campana ci potrebbero suggerire che i campioni su cui i prezzi mediani sono stati calcolati siano piccoli e che vi sia una certa assimmetria nelle distribuzioni originarie. La curtosi potrebbe indicare che le distribuzioni originarie sono piuttosto diverse tra loro.

Questo primo livello di analisi sulle variabili “sales”, “volume” e “median_price” ci può suggerire di indagare segmenti specifici del mercato per valutarne l’eterogeneità e altre caratteristiche.

listings: il numero di annunci medi attivi si attesta a 1738, un valore leggermente più alto rispetto alla mediana di 1618. L’indice di asimmetria di 0,65 indica infatti un’asimmetria positiva, riflettendo una maggior frequenza di valori bassi. La deviazione standard di quasi 753 è pari a ca. il 43% del valore medio a indicazione di una variabilità dei dati abbastanza contenuta. L’indice di curtosi di -0,79 indica una distribuzione platicurtica ossia una distribuzione più larga e piatta rispetto alla normale ed eventi estremi teoricamente meno presenti. il valore mimino e massimo sono circa poco più di 2 volte più basso/ poco meno di 2 volte più alto rispetto alla media.

months_inventory: il numero di mesi necessari a vendere tutti gli immobili degli annunci attivi è pari a 9,19, un valore praticamente in linea con la mediana di 8,95. L’indice di asimmetria di asimmetria infatti è quasi nullo. La deviazione standard di quasi 2,3 è pari a ca. il 25% del valore medio a indicazione di una certa stabilità relativa nei dati. L’indice di curtosi di -0,17 indica una distribuzione lievemente platicurtica ossia una distribuzione più larga e piatta rispetto alla normale ed eventi estremi teoricamente meno presenti. il valore mimino e massimo sono circa poco più di 2.5 volte più basso/ poco meno di 2 volte più alto rispetto alla media.

Analisi variabili qualitative

Funzione calculate_frequency_distribution e distribuzione di frequenze

calculate_frequency_distribution_nominal <- function(data, variable_column) {
  n <- nrow(data)
  ni <- table(variable_column)
  fi <- ni/ n

  
  return(as.data.frame(cbind(
    ni = ni, 
    fi = fi
  )))
}

calculate_frequency_distribution<- function(data, variable_column) {
  n <- nrow(data)
  ni <- table(variable_column)
  fi <- ni/ n
  Ni <- cumsum(ni)
  Fi <- cumsum(fi)
  
  return(as.data.frame(cbind(
    ni = ni, 
    fi = fi, 
    Ni = Ni, 
    Fi = Fi
  )))
}
#distribuzione di frequenza per city e year
freq_dist_city <- calculate_frequency_distribution_nominal(data, data$city)
freq_dist_year <- calculate_frequency_distribution(data, data$year)

freq_dist_city
##                       ni   fi
## Beaumont              60 0.25
## Bryan-College Station 60 0.25
## Tyler                 60 0.25
## Wichita Falls         60 0.25
freq_dist_year
##      ni  fi  Ni  Fi
## 2010 48 0.2  48 0.2
## 2011 48 0.2  96 0.4
## 2012 48 0.2 144 0.6
## 2013 48 0.2 192 0.8
## 2014 48 0.2 240 1.0
#calcolo indice di gini
gini_index <- function(x){
  freq_abs = table(x)
  freq_rel = freq_abs/length(x)
  freq_rel_squared = freq_rel^2
  J = length(table(x))
  
  gini = 1-sum(freq_rel_squared)
  gini_norm = gini/((J-1)/J)
  
  return(gini_norm)
}

gini_index(data$city)
## [1] 1
gini_index(data$year)
## [1] 1
  • freq_dist_city: notiamo che ogni città ha lo stesso numero di osservazioni.

  • freq_dist_year: notiamo che anche ogni anno ha lo stesso numero di osservazioni.

Possiamo concludere che vi sono 4 mode per la variabile city e year.

Il calcolo dell’indice di Gini (normalizzato) considerato che la distribuzione sia di city che di year è perfettamente equa si presuppone restituisca valore 1 (massima eterogeneità). L’output della funzione gini_index lo conferma

Variabile con maggior variabilità

Osservando il coefficiente di variazione è possibile confrontare la variabilità tra diverse variabili. Il coefficiente di variazione è dato dal rapporto tra la deviazione standard e la media dei dati e permette di confrontare la variabilità di due campioni relativamente alla stessa variabile o confrontare la variabilità di uno stesso campione relativamente a due variabili. L’analisi di tale indice nella tabella statistics_tabel ci permette di rispondere alle seguenti domande:

Creazioni classi per variabile quantitativa

Creazione variabile sales_class

data$sales_class <- cut(data$sales,
                        breaks = c(0,50,100,200,300,400,500))
head(data$sales_class)
## [1] (50,100]  (100,200] (100,200] (100,200] (200,300] (100,200]
## Levels: (0,50] (50,100] (100,200] (200,300] (300,400] (400,500]

Osservando il valore minimo e massimo della variabile sales nella tabella statistics_tabel vediamo che questi sono 79 e 423. Vengono quindi create delle classi per la variabile sales coerenti rispetto a questi valori.

A questo punto si richiamano le funzioni calculate_frequency_distribution e gini_index per calcolare la distribuzione di frequenza e l’indice di Gini per la nuova variabile sales_class

Sales-class sarà rappresentata graficamente e commentata in seguito.

freq_dist_sales <- calculate_frequency_distribution(data, data$sales_class)
freq_dist_sales <- round(freq_dist_sales, 2)
knitr::kable(
  freq_dist_sales,
  caption = "distribuzione di frequenza per classi di vendite",
  digits = 2,
  format.args = list(big.mark = ".", decimal.mark = ",")
)
distribuzione di frequenza per classi di vendite
ni fi Ni Fi
(0,50] 0 0,00 0 0,00
(50,100] 21 0,09 21 0,09
(100,200] 128 0,53 149 0,62
(200,300] 66 0,28 215 0,90
(300,400] 22 0,09 237 0,99
(400,500] 3 0,01 240 1,00
gini_index(data$sales_class)
## [1] 0.7484583

Rapresentazione grafica di sales_class

library(ggplot2)

#palette di colori personalizzata
city_palette <- c(
  "Beaumont" = "#5DADE2", 
  "Bryan-College Station" = "#7EC8E3", 
  "Tyler" = "#66CDAA", 
  "Wichita Falls" = "#3CB371"
)

#grafici per sales
ggplot(data = data) +
  geom_bar(
    aes(x = sales_class, fill = city), 
    position = "stack", 
    col = "black"
  ) +
  geom_text(
    stat = "count",
    aes(x = sales_class, label = after_stat(count)), 
    position = position_stack(vjust = 0.9), 
    color = "white", size = 3
  ) +
  scale_fill_manual(values = city_palette) +
  labs(
    title = "Immobili venduti per classi",
    subtitle = "Distribuzione per città di vendita",
    x = "Classi di vendite",
    y = "Frequenze assolute",
    fill = "Città"
  ) +
  theme_bw() +
  scale_y_continuous(breaks = seq(0, 150, 30)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 12),
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.major.y = element_line(color = "gray80"),
    panel.grid.minor = element_blank()
  )

year_palette <- c(
  "2010" = "#5DADE2", 
  "2011" = "#7EC8E3", 
  "2012" = "#66CDAA", 
  "2013" = "#3CB371",
  "2014" = "#3CB990"
)

ggplot(data = data) +
  geom_bar(
    aes(x = sales_class, fill = factor(year)), 
    position = "stack", 
    col = "black"
  ) +
  geom_text(
    stat = "count",
    aes(x = sales_class, label = after_stat(count)), 
    position = position_stack(vjust = 0.9), 
    color = "white", size = 3
  ) +
  scale_fill_manual(values = year_palette) +
  labs(
    title = "Immobili venduti per classi",
    subtitle = "Distribuzione per anno di vendita",
    x = "Classi di vendite",
    y = "Frequenze assolute",
    fill = "Anno"
  ) +
  theme_bw() +
  scale_y_continuous(breaks = seq(0, 150, 30)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 12),
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.major.y = element_line(color = "gray80"),
    panel.grid.minor = element_blank()
  )

Osservando la tabella freq_dist_sales notiamo che l’80% dei dati si concentra nelle classi di volumi di vendita tra (100,200] e (200,300] (il valore medio osservato in statistics_table è 192, con una mediana di 175). Le altre classi raggruppano alcune osservazioni anche se in misura minore, infatti l’indice di Gini indica una disuguaglianza forte ma non totale (75%).

Le rappresentazioni grafiche mostrano la distribuzione degli immobili venduti per classi, a loro volta distribuiti per città e anni.

Nella classe più frequente (100,200] le vendite si sono manifestate per lo più a Beaumont e Wichita Falls, e si sono distribuite prevalentemente tra il 2010 e il 2012, mostrando una flessione nel 2013 e 2014.A Witchita Falls sembrano essere prevalenti periodi in cui la quantità di immobili venduti è contenuta.

La distribuzione nel complesso è assimmetrica verso destra, quindi è meno comune avere periodi con vendite molto elevate.

Vediamo anche come appare graficamente la distribuzione di frequenze assolute per median_price e volume (prezzo mediano e ricavato delle vendite in USD)

# grafici per median_price

data$median_price_class <- cut(data$median_price, 
                        breaks = c(0, 40000, 80000, 120000, 160000, 200000),
                        labels = c("0-40k", "40k-80k", "80k-120k", "120k-160k","160k-200k"),
                        include.lowest = TRUE)

ggplot(data = data) +
  geom_bar(
    aes(x = median_price_class, fill = city), 
    position = "stack", 
    col = "black"
  ) +
  geom_text(
    stat = "count",
    aes(x = median_price_class, label = after_stat(count)), 
    position = position_stack(vjust = 0.5), 
    color = "white", size = 3
  ) +
  scale_fill_manual(values = city_palette) +
  labs(
    title = "Prezzo mediano per classi",
    subtitle = "Distribuzione per città",
    x = "Prezzo mediano",
    y = "Frequenze assolute",
    fill = "Città"
  ) +
  theme_bw() +
  scale_y_continuous(breaks = seq(0, 150, 30)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 12),
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.major.y = element_line(color = "gray80"),
    panel.grid.minor = element_blank()
  )

ggplot(data = data) +
  geom_bar(
    aes(x = median_price_class, fill = factor(year)), 
    position = "stack", 
    col = "black"
  ) +
  geom_text(
    stat = "count",
    aes(x = median_price_class, label = after_stat(count)), 
    position = position_stack(vjust = 0.5), 
    color = "white", size = 3
  ) +
  scale_fill_manual(values = year_palette) +
  labs(
    title = "Prezzo mediano per classi",
    subtitle = "Distribuzione per anno",
    x = "Prezzo mediano",
    y = "Frequenze assolute",
    fill = "Anno"
  ) +
  theme_bw() +
  scale_y_continuous(breaks = seq(0, 150, 30)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 12),
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.major.y = element_line(color = "gray80"),
    panel.grid.minor = element_blank()
  )

# grafici per volume

data$volume_class <- cut(data$volume, 
                        breaks = c(0, 25, 50, 75, 100),
                        labels = c("0-25mn", "25mn-50mn", "50mn-75mn", "75mn-100mn"),
                        include.lowest = TRUE)

ggplot(data = data) +
  geom_bar(
    aes(x = volume_class, fill = city), 
    position = "stack", 
    col = "black"
  ) +
  geom_text(
    stat = "count",
    aes(x = volume_class, label = after_stat(count)), 
    position = position_stack(vjust = 0.5), 
    color = "white", size = 3
  ) +
  scale_fill_manual(values = city_palette) +
  labs(
    title = "Volume di vendita per classi",
    subtitle = "Distribuzione per città",
    x = "Volume di vendita",
    y = "Frequenze assolute",
    fill = "Città"
  ) +
  theme_bw() +
  scale_y_continuous(breaks = seq(0, 150, 30)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 12),
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.major.y = element_line(color = "gray80"),
    panel.grid.minor = element_blank()
  )

ggplot(data = data) +
  geom_bar(
    aes(x = volume_class, fill = factor(year)), 
    position = "stack", 
    col = "black"
  ) +
  geom_text(
    stat = "count",
    aes(x = volume_class, label = after_stat(count)), 
    position = position_stack(vjust = 0.5), 
    color = "white", size = 3
  ) +
  scale_fill_manual(values = year_palette) +
  labs(
    title = "Volume di vendita per classi",
    subtitle = "Distribuzione per anno",
    x = "Volume di vendita",
    y = "Frequenze assolute",
    fill = "Anno"
  ) +
  theme_bw() +
  scale_y_continuous(breaks = seq(0, 150, 30)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold", size = 14),
    plot.subtitle = element_text(size = 12),
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.major.y = element_line(color = "gray80"),
    panel.grid.minor = element_blank()
  )

La fascia di prezzo mediano con più osservazioni è quella tra i 120k e i 160k, dove si osserva una particolare concentrazione. Sembra evidente che a Wichita Falls i prezzi mediani siano prevalentemente più passi che a Beaumont e Bryan-College Station. Non c’è una sostanziale differenza anno per anno nelle diverse classi di prezzo mediano.

Abbiamo visto come a Witchita Falls si vendano prevalentemente meno immobili e con un prezzo mediano inferiore, infatti il volume di affari complessivo in questa città è concentrato nella fascia fino a 25 milioni di dollari.

Beaumont e Bryan-College sono più rappresentate dalle classi medio-basse di volumi, infatti sono quelle dove il prezzo mediano è spostato verso una fascia medio-alta ma le quantità di vendita sono più contenute. Bryan College sembra rappresentare più delle altre città la fascia di volumi transati più alta in assoluto (sopra i 75 mln).

A Tyler il volume delle transazioni del mercato immobiliare si colloca nella fascia medio alta (tra i 50 e i 75 milioni), infatti è la città più rappresentata nella fascia di prezzo tra i 120k e i 160k e mostra una quantità di vendite nella fascia alta più frequente.

In generale nel mercato immobiliare nel Texas le fasce di fatturato complessivo più basse sono predominanti. Potremmo in questa fase ipotizzare che siano più frequenti molte transazioni a prezzi mediani contenuti, e poche transazioni nella fascia più alta e di prezzo concentrate per lo più in una sola città.

Complessivamente possiamo osservare una certa eterogeneità nei diversi segmenti di mercato a livello regionale. Vi sono della aree urbane (soprattutto a Tyler) dove si vendono in misura maggiore immobili di fascia più elevata, e che tali transazioni siano proporzionalmente aumentate negli ultimi anni rispetto al passato, indice di una possibile variazione nella domanda di mercato in tempi recenti.

Calcolo delle probabilità

  1. Qual è la probabilità che, presa una riga a caso di questo dataset, essa riporti la città “Beaumont”?
  2. Qual’è la probabilità che, presa una riga a caso di questo dataset, riporti il mese di Luglio?
  3. Qual’è la probabilità che, presa una riga a caso di questo dataset, e la probabilità che riporti il mese di dicembre 2012?

Funzione calculate_probability e calcolo delle probabilità

calculate_probability <- function(x, value) {
  n_var <- sum(x == value)
  n <- nrow(data)
  prob <- n_var/n
}

prob_city <- calculate_probability(data$city, "Beaumont")
prob_city
## [1] 0.25
prob_month <- calculate_probability(data$month, 7)
prob_month
## [1] 0.08333333
prob_date <- sum(data$month == 12 & data$year == 2012)/nrow(data)
prob_date
## [1] 0.01666667

Risposte:

1. 25%

2. 8,3%

3. 1,7%

Creazione di nuove variabili

Creazione della colonna che calcola il prezzo medio degli immobili.

data$average_price <- round(data$volume/data$sales * 1000000, 2)

statistics_table <- 
  data %>%
  summarise(across(c(average_price), calculate_statistics)) %>%
  t() %>%
  as.data.frame()


colnames(statistics_table) <- c("mean", "median", "min", "max", "std_dev", "coeff_var", "skewness", "kurtosis")


statistics_table <- round(statistics_table, 2)


knitr::kable(
  statistics_table,
  caption = "Principali indici della variabile prezzo medio",
  digits = 2,
  format.args = list(big.mark = ".", decimal.mark = ",")
)
Principali indici della variabile prezzo medio
mean median min max std_dev coeff_var skewness kurtosis
average_price 154.320,4 156.588,5 97.010,2 213.233,9 27.147,46 0,18 -0,07 -0,78

La media dei prezzi medi calcolati su ogni singola operazione è circa 154.000 dollari, molto vicino al prezzo mediano. La dispersione è molto bassa (la deviazione standard è un valore conenuto rispetto alla media) e la distribuzione è quasi simmetrica e più schiacciata di una distribuzione normale (platicurtica).

Creazione della colonna che misura l’efficacia degli annunci di vendita.

data$earnings_per_listing <- round((data$volume * 1000000)/(data$listings/data$months_inventory), 2)

statistics_table <- 
  data %>%
  summarise(across(c(average_price, earnings_per_listing), calculate_statistics)) %>%
  t() %>%
  as.data.frame()

colnames(statistics_table) <- c("mean", "median", "min", "max", "std_dev", "coeff_var", "skewness", "kurtosis")

statistics_table <- round(statistics_table, 2)

knitr::kable(
  statistics_table,
  caption = "Principali indici delle variabili prezzo medio e reddittività degli annunci",
  digits = 2,
  format.args = list(big.mark = ".", decimal.mark = ",")
)
Principali indici delle variabili prezzo medio e reddittività degli annunci
mean median min max std_dev coeff_var skewness kurtosis
average_price 154.320,4 156.588,5 97.010,20 213.233,9 27.147,46 0,18 -0,07 -0,78
earnings_per_listing 158.311,1 148.023,2 66.696,13 335.240,1 52.539,43 0,33 1,06 1,18

la colonna che misura l’efficienza dell’inventario di annunci attivi è calcolata come il rapporto tra:

  • Ricavato di vendita degli immobili, fratto
  • numero medio di listini attivi evasi ogni mese.

Il denominatore è calcolato come:

  • numero di listini attivi, fratto
  • numero di mesi necessario per evadere tutte le inserzioni attive.

earnings_per_listings” è un indicatore della redditività mensile delle inserzioni attive.

La media è pari a ca. 158.311 dollari, con una mediana di circa 148.000 dollari. La variabilità sembra contenuta, l’asimmetria è positiva e la distribuzione è leptocurtica. Potrebbero esserci annunci di vendita con una redditività particolarmente elevata.

Dal confronto della media tra average_price e earnings_per_listings potremmo dedurre che nel complesso il mercato è in equilibrio senza evidenti segnali di disallineamento tra domanda e offerta.

Questo perchè il volume d’affari complessivo rapportato alla quantità venduta (domanda) e il volume d’affari complessivo rapportato agli annunci attivi (offerta) restituiscono valori coerenti tra loro.

Tuttavia, abbiamo visto dai grafici precedenti che il mercato immobiliare del Texas sembra non essere omogeneo a livello territoriale. Questo equilibrio a livello generale potrebbe non essere presente analizzando il mercato delle singole città. Per indagare meglio questo aspetto, procediamo con l’analisi condizionata.

Analisi statistica condizionata

Funzione “conditional_analysis” e analisi condizionata su alcune variabili (city e year)

conditional_analysis <- function(data, group_vars, summary_vars, summary_function = mean) {
  data %>%
    group_by(across(all_of(group_vars))) %>%
    summarise(across(all_of(summary_vars), summary_function), .groups = "drop") %>%
    as.data.frame()
}

summary_vars <- c("volume", "sales", "median_price", "earnings_per_listing", "months_inventory", "listings")

#analisi condizionata dei valori medi su città, anno, anno e mese, città e mese
conditional_stats_city <- conditional_analysis(data, "city", summary_vars)
conditional_stats_year <- conditional_analysis(data, "year", summary_vars)
conditional_stats_date <- conditional_analysis(data, c("year", "month"), summary_vars)
conditional_stats_citymonth <- conditional_analysis(data, c("city", "month"), summary_vars)

conditional_stats_city[,-1] <- round(conditional_stats_city[,-1], 2)
conditional_stats_year[,-1] <- round(conditional_stats_year[,-1], 2)
conditional_stats_year$year <- as.numeric(gsub("\\.", "", conditional_stats_year$year))
conditional_stats_date[,-c(1,2)] <- round(conditional_stats_date[,-c(1,2)], 2)
conditional_stats_citymonth[,-c(1,2)] <- round(conditional_stats_citymonth[,-c(1,2)], 2)

#analisi condizionata della sd  su città, anno, anno e mese, città e mese
conditional_sd_city <- conditional_analysis(data, "city", summary_vars, sd)
conditional_sd_year <- conditional_analysis(data, "year", summary_vars, sd)
conditional_sd_date <- conditional_analysis(data, c("year", "month"), summary_vars, sd)
conditional_sd_citymonth <- conditional_analysis(data, c("city", "month"), summary_vars, sd)


conditional_sd_city[,-1] <- round(conditional_sd_city[,-1], 2)
conditional_sd_year[,-1] <- round(conditional_sd_year[,-1], 2)
conditional_sd_year$year <- as.numeric(gsub("\\.", "", conditional_sd_year$year))
conditional_sd_date[,-c(1,2)] <- round(conditional_sd_date[,-c(1,2)], 2)
conditional_sd_citymonth[,-c(1,2)] <- round(conditional_sd_citymonth[,-c(1,2)], 2)

knitr::kable(
  conditional_stats_city,
  caption = "Statistiche medie per città",
  digits = 2,
  format.args = list(big.mark = ".", decimal.mark = ",")
)
Statistiche medie per città
city volume sales median_price earnings_per_listing months_inventory listings
Beaumont 26,13 177,38 129.988,3 151.105,9 9,97 1.679,32
Bryan-College Station 38,19 205,97 157.488,3 188.953,4 7,66 1.458,13
Tyler 45,77 269,75 141.441,7 173.912,1 11,32 2.905,05
Wichita Falls 13,93 116,07 101.743,3 119.273,2 7,82 909,58
knitr::kable(
  cbind(year = conditional_stats_year$year,
        format(conditional_stats_year[,-1],
               big.mark = ".", decimal.mark = ",",
               nsmall = 2, scientific = FALSE, justify = "right")),
  caption = "Statistiche medie per anno",
  align = "r"
)
Statistiche medie per anno
year volume sales median_price earnings_per_listing months_inventory listings
2010 25,68 168,67 130.191,67 142.430,82 9,97 1.826,00
2011 25,16 164,12 127.854,17 148.822,22 10,90 1.849,65
2012 29,27 186,15 130.077,08 161.685,08 9,88 1.776,81
2013 35,15 211,92 135.722,92 168.462,55 8,15 1.677,60
2014 39,77 230,60 139.481,25 170.155,04 7,06 1.560,04
knitr::kable(
  conditional_sd_city,
  caption = "Statistiche sd per città",
  digits = 2,
  format.args = list(big.mark = ".", decimal.mark = ",")
)
Statistiche sd per città
city volume sales median_price earnings_per_listing months_inventory listings
Beaumont 6,97 41,48 10.104,99 30.981,93 1,65 91,13
Bryan-College Station 17,25 84,98 8.852,24 71.727,68 2,25 252,53
Tyler 13,11 61,96 9.336,54 39.808,14 1,89 226,75
Wichita Falls 3,24 22,15 11.320,03 26.220,88 0,78 73,76
knitr::kable(
  cbind(year = conditional_sd_year$year,
        format(conditional_sd_year[,-1],
               big.mark = ".", decimal.mark = ",",
               nsmall = 2, scientific = FALSE, justify = "right")),
  caption = "Statistiche sd per anno",
  align = "r"
)
Statistiche sd per anno
year volume sales median_price earnings_per_listing months_inventory listings
2010 10,80 60,54 21.821,76 39.315,18 2,08 785,02
2011 12,20 63,87 21.317,80 51.058,48 2,07 780,38
2012 14,52 70,91 21.431,52 53.356,50 1,61 738,45
2013 17,93 84,00 21.708,08 57.970,72 1,69 743,52
2014 21,19 95,51 25.625,41 55.381,20 1,75 706,71

Analisi condizionata dei valori medi di “volume”, “sales”, “median price” e “earnings_per_listing” e “listings” per città e anno

  1. Analisi per città:

    Come intuito in precedenza dai grafici di sales, volume e median_price suddivisi per classi, le statistiche condizionate sulle città fanno emergere alcune differenze:

  • Bryan-College Station mostra la reddittività per inserzione più alta (188.953,40 dollari) e il prezzo mediano più alto (157.488,33 dollari), nonostante le vendite misurate in immobili venduti si posizionino al secondo posto.
  • Wichita Falls ha il valore più basso in tutte le categorie. Rappresenta il mercato meno sviluppato sia in termini di volumi che di prezzi
  • Tyler ha il maggior volume di vendita (45,77 milioni USD) e il maggior numero di vendite (269,75). earnings_per_listing indica che la reddittività è alta (seconda a Bryan-College). I volumi transati elevati sono spiegati prevalentemente dalla quantità venduta e ci vuole mediamente più tempo per vendere gli immobili rispetto a Bryan-College.
  • Beaumont si posiziona come un mercato intermedio tra Wichita Falls e Bryan-College Station.

A Beaumont e Bryan-College considerato un numero medio di mesi di evasione dell’inventario in linea (o più basso) della media complessiva del Texas (9,19) e un prezzo mediano sulla fascia medio alta (la fascia con maggiori osservazioni in assoluto infatti è quella 120k-160k) potremmo dedurre che i volumi complessivi di transato potrebbero aumentare a fronte di uno stimolo della domanda (aumentare l’offerta di immobili potrebbe essere una strada se il mercato è dinamico ed in espansione, a tal proposito si dovrebbero condurre altri studi per esempio su aumento della popolazione, opportunità di lavoro, qualità della vita,ecc).  

Vediamo per esempio che il valore medio di inserzioni attive a Tyler è il più elevato e questo spinge la quantità venduta, incrementando i volumi di fatturato complessivo.

Bryan-College mostra la maggior variabilità rispetto alle altre città su diverse metriche, salvo i prezzi mediani dove Witchita-Falls mostra la deviazione standard maggiore (il mercato sembra piccolo e con maggior dispersione di prezzi).

  1. Dall’analisi per anno emerge chiaramente un progressivo trend in crescita dei volumi complessivi transati guidati dalla quantità venduta piuttosto che dai prezzi (tendenzialmente stabili). La reddittività per inserzione è andata migliorando nel tempo, i tempi di rotazione si sono ridotti (infatti le vendite sono aumentate) indicando un mercato sempre più dinamico. La deviazione standard negli anni è aumentata per volumi, immobili venduti e prezzi. Con la crescita complessiva del mercato si è probabilmente accentuata la segmentazione come potrebbero suggerire le differenze tra le diverse città.

Visualizzazioni relative ad analisi condizionata

Grafico per la media condizionata di “sales” su anno e mese

ggplot(conditional_stats_date, aes(x = factor(month), y = sales, fill = factor(year))) +
  geom_col(position = "stack", color = "black") +
  scale_fill_viridis_d(option = "plasma", direction = -1) +
  theme_bw() +
  labs(
    title = "Vendite medie mensili per anno",
    x = "Mese",
    y = "Vendite medie cumulate",
    fill = "Anno"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

A prima vista si conferma il trend in aumento delle vendite con il passare degli anni e la distribuzione delle vendite sembra mosrtare dei cali durante il period invernale rispetto al primaverile-estivo.

In questa fase possiamo intuire che la domanda di immobili è soggetta ad una certa stagionalità.

Grafico per la media condizionata di “sales” su città ed anno

conditional_stats_city_year <- conditional_analysis(data, c("city", "year"), "sales")
conditional_stats_city_year$sales <- round(conditional_stats_city_year$sales, 2)

ggplot(conditional_stats_city_year, aes(x = city, y = sales, fill = factor(year))) +
  geom_col(position = "stack", color = "black") +
  theme_bw() +
  scale_fill_viridis_d(option = "plasma", direction = -1) +
  labs(
    title = "Vendite medie per città e anno",
    x = "Città",
    y = "Vendite medie cumulate",
    fill = "Anno"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    axis.text.x = element_text(angle = 45, hjust = 1),
    strip.text = element_text(face = "bold")
  )

La tendenza all’aumento delle vendite negli anni si è manifestato in tutte le città (in misura minore per Witchita Falls) a indicare un aumento della domanda generalizzato in tutto il Texas.

Grafico per la media condizionata di “volume” su anno e mese

ggplot(conditional_stats_date, aes(x = factor(month), y = volume, fill = factor(year))) +
  geom_col(position = "stack", color = "black") +
  scale_fill_viridis_d(option = "plasma", direction = -1) +
  theme_bw() +
  labs(
    title = "Volume transato medio mensile per anno",
    x = "Mese",
    y = " Vendite medie cumulate",
    fill = "Anno"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Grafico per la media condizionata di “volume” su city e year

conditional_stats_city_year_volume <- conditional_analysis(data, c("city", "year"), "volume")
conditional_stats_city_year_volume$volume <- round(conditional_stats_city_year_volume$volume, 2)

ggplot(conditional_stats_city_year_volume, aes(x = city, y = volume, fill = factor(year))) +
  geom_col(position = "stack", color = "black") +
  theme_bw() +
  scale_fill_viridis_d(option = "plasma", direction = -1) +
  labs(
    title = "Volume transato medio mensile per città",
    x = "Città",
    y = "Vendite medie cumulate",
    fill = "Anno"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    axis.text.x = element_text(angle = 45, hjust = 1),
    strip.text = element_text(face = "bold")
  )

Altre visualizzazioni

Creazione variabile “date” e “quarter”

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


data <- data %>%
  mutate(quarter = case_when(
    month %in% 1:3  ~ "Q1",
    month %in% 4:6  ~ "Q2",
    month %in% 7:9  ~ "Q3",
    month %in% 10:12 ~ "Q4"
  ))

Grafico delle vendite (“sales”) per city, year, quarter

quarter_palette <- c(
  "Q1" = "#5DADE2", 
  "Q2" = "#7EC8E3", 
  "Q3" = "#66CDAA", 
  "Q4" = "#3CB371"
)

total_sales_city_year_quarter <- data %>%
  group_by(city, year, quarter) %>%
  summarise(sales = sum(sales), .groups = "drop")

ggplot(total_sales_city_year_quarter, aes(x = city, y = sales, fill = factor(quarter))) +
  geom_col(position = "fill", color = "black") +
  facet_wrap(~ year, nrow = 1) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = quarter_palette, name = "Trimestre") +
  labs(
    title = "Distribuzione % degli immobili venduti mensilmente per città",
    x = "Città"
  ) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    plot.title = element_text(face = "bold", hjust = 0.5)
    )

total_volume_city_year_quarter <- data %>%
  group_by(city, year, quarter) %>%
  summarise(volume = sum(volume), .groups = "drop")

ggplot(total_volume_city_year_quarter, aes(x = city, y = volume, fill = factor(quarter))) +
  geom_col(position = "fill", color = "black") +
  facet_wrap(~ year, nrow = 1) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = quarter_palette, name = "Trimestre") +
  labs(
    title = "Distribuzione % delle vendite mensili in USD per città e trimestre",
    x = "Città"
  ) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    plot.title = element_text(face = "bold", hjust = 0.5)
  )

Le vendite si concentrano prevalentemente nei due trimestri centrali dell’anno senza particolare distinzioni tra gli anni.

La città in cui si nota una maggiore stagionalità è Bryan-College dove le vendite si realizzano per lo più nel secondo trimestre di ogni anno.

Boxplot

# Boxplots prezzo mediano
boxplot(median_price ~ city, data = data,
        col = "lightblue",
        main = "Prezzo mediano per città",
        xlab = "Città", ylab = "Prezzo Mediano")

boxplot(median_price ~ year, data = data,
        col = "lightblue",
        main = "Prezzo mediano per anno",
        xlab = "Anno", ylab = "Prezzo Mediano")

# Boxplots prezzo mediano citta e anno
ggplot(data, aes(x = city, y = median_price, fill = factor(year))) +
  geom_boxplot(position = position_dodge()) +
  labs(
    title = "Prezzo mediano per città e anno",
    x = "Città",
    y = "Prezzo Mediano",
    fill = "Anno"
  ) +
  theme_bw() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    plot.title = element_text(face = "bold", size = 14)
  )

# Boxplots prezzo mediano città e quarter
ggplot(data, aes(x = city, y = median_price, fill = quarter)) +
  geom_boxplot() +
  labs(
    title = "Prezzo mediano per città e trimestre",
    x = "Città", y = "Prezzo Mediano",
    fill = "Trimestre"
  ) +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Le distribuzioni del prezzo mediano come precedentemente analizzato presentano una variabilità contenuta. I prezzi mediani sono più alti a Bryan College e Tyler. Per Beaumont e Witchita Falls si osservano degli outliers. Il prezzo mediano per anno è piuttosto stabile, con una leggera tendenza a rialzo dopo il 2012. Le distribuzioni rispetto all’anno sono piuttosto asimmetriche a sinistra, mostrando quindi prezzi mediani nella fascia alta più frequenti.

Serie storiche

# volumi nel tempo
ggplot(data, aes(x = date, y = volume, color = city)) +
  geom_line(size = 1) +
  theme_minimal() +
  scale_x_date(date_breaks = "3 months", date_labels = "%b %Y") +
  labs(
    title = "Andamento dei volumi di vendita nel tempo",
    x = "Data",
    y = "Volume di vendita",
    color = "Città"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

# media mobile 6 mesi per i volumi di vendita
data <- data %>%
  arrange(city, date) %>%
  group_by(city) %>%
  mutate(volume_rolling = stats::filter(volume, rep(1/6, 6), sides = 1)) %>%
  ungroup()

ggplot(data, aes(x = date, y = volume_rolling, color = city)) +
  geom_line(size = 1) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b %Y") +
  labs(title = "Andamento dei volumi di vendita nel tempo - media mobile 6M",
       x = "Data",
       y = "Volume di vendita",
       color = "Città"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

# media mobile 6M per le quantità vendute
data <- data %>%
  arrange(city, date) %>%
  group_by(city) %>%
  mutate(sales_rolling = stats::filter(sales, rep(1/6, 6), sides = 1)) %>%
  ungroup()

# quantità vendute nel tempo
ggplot(data, aes(x = date, y = sales_rolling, color = city)) +
  geom_line(size = 1) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b %Y") +
  labs(title = "Andamento degli immobili venduti nel tempo - media mobile 6m",
       x = "Data",
       y = "Immobili venduti",
       color = "Città"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

# media mobile 3M per i prezzi mediani
data <- data %>%
  arrange(city, date) %>%
  group_by(city) %>%
  mutate(median_price_rolling = stats::filter(median_price, rep(1/3, 3), sides = 1)) %>%
  ungroup()

# prezzo mediano nel tempo
ggplot(data, aes(x = date, y = median_price_rolling, color = city)) +
  geom_line(size = 1) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b %Y") +
  labs(title = "Andamento prezzi mediani nel tempo - media mobile 3m",
       x = "Data",
       y = "Prezzi mediani",
       color = "Città"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

# annunci immobiliari nel tempo
ggplot(data, aes(x = date, y = listings, color = city)) +
  geom_line(size = 1) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b %Y") +
  labs(title = "Andamento degli annunci attivi nel tempo",
       x = "Data",
       y = "Annunci attivi",
       color = "Città"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

# tempo medio di evasione annunci
ggplot(data, aes(x = date, y = months_inventory, color = city)) +
  geom_line(size = 1) +
  scale_x_date(date_breaks = "3 months", date_labels = "%b %Y") +
  labs(title = "Andamento dei mesi di inventario nel tempo",
       x = "Data",
       y = "Mesi di inventario",
       color = "Città"
  ) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

Osservando le serie storiche, sembra evidente quanto segue:

  • elevata stagionalità nelle vendite: i volumi di vendita mostrano picchi nei mesi primaverili-estivi più marcati soprattutto a Bryan-College e Tyler, ma presenti anche a Beaumont e Witchita. Salvo Witchita-Falls, dove il mercato sembra tendenzialmente stagnante, dal 2012 in poi si osserva un trend incrementale dei volumi in tutte le altre principali città del Texas. Questi pattern sono più facilmente leggibili dal grafico a media mobile (su 6 mesi, data l’elevata stagionalità).

  • Osservando la serie storica delle quantità vendute e dei prezzi mediani si nota che:

    • rispetto alle quantità si osservano esattamente gli stessi pattern osservati sui volumi (analizzando il grafico con media mobile a sei mesi, dati i forti picchi stagionali)

    • rispetto al prezzo mediano si osserva un pattern parzialmente diverso. Considerato che i picchi stagionali sono più contenuti, analizziamo il grafico della media mobile a 3 mesi invece di 6 per i prezzi mediani. Si nota:

      • un forte trend in rialzo per Bryan-College; un trend a rialzo meno pronunciato per Tyler e una sostanziale stabilità nel tempo per Beuamont e Witchita.

      • picchi stagionali meno pronunciati per Bryan–College e Tyler e più pronunciati per Beaumont e soprattutto Witchita.

      • Bryan-College sembra essere la città che sopporta meglio i cali del mercato immobiliare Texano (probabilmente associati a congiunture sfavorevoli del ciclo economico).

  • L’andamento degli annunci attivi e del tempo di inventario sembrano dire che:

    • c’è stato un tendenziale decremento degli annunci attivi a Tyler (la città con il maggior numero di annunci) e soprattutto a Bryan-College a partire dal 2013, il cui numero si è allineanto a quello di Witchita;
    • Witchita e Beaumont sono relativamente stabili nel livello di annunci attivi nel tempo, Witchita con il numero più basso e Beaumont ad un livello nella maggior parte dei casi superiore a Bryan-College (eccetto picchi stagionali per Bryan-College).
    • é interessante osservare come il trend dei tempi di inventario si sia costantemente ridotto a partire dal 2011 in tutte le città (eccetto Witchita che è più stabile sull’orizzonte osservato). Questo indica che il mercato si è ravvivato a partire da quella data e gli annunci vengono evasi più velocemente.
    • Rispetto all’offerta di mercato possiamo quindi osservare che, mentre in città come Tyler il numero di listini attivi sia andato riducendosi nel tempo questo sia avvenuto in maniera meno drastica rispetto a Brayn-College. A Beaumont, nonostante il tempo dell’inventario si sia andato a ridurre, il numero di annunci attivi si è mantenuto costante. In queste tre città abbiamo inoltre assistito ad un aumento degli immobili venduti negli ultimi anni costante e comparabile.

Commenti finali

Andamento generale del mercato immobiliare Texano:

Andamento per area urbana: