Descrizione del dataset

Il dataset contiene variabili sia qualitative che quantitative. Riporto sotto una descrizione per ciascuna:

Caricamento dati

data <- read.csv("C:\\Users\\anton\\Desktop\\realestate_texas.csv")
head(data)
##       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

Analisi delle frequenze

Parto dalle frequenze assolute e relative per le variabili qualitative (e anche per quelle discrete che in questo caso tratto come categoriche).

# frequenze per città
data.frame(F_ASS = table(data$city),
           F_REL = prop.table(table(data$city)))
##              F_ASS.Var1 F_ASS.Freq            F_REL.Var1 F_REL.Freq
## 1              Beaumont         60              Beaumont       0.25
## 2 Bryan-College Station         60 Bryan-College Station       0.25
## 3                 Tyler         60                 Tyler       0.25
## 4         Wichita Falls         60         Wichita Falls       0.25
# per anno
data.frame(F_ASS = table(data$year),
           F_REL = prop.table(table(data$year)))
##   F_ASS.Var1 F_ASS.Freq F_REL.Var1 F_REL.Freq
## 1       2010         48       2010        0.2
## 2       2011         48       2011        0.2
## 3       2012         48       2012        0.2
## 4       2013         48       2013        0.2
## 5       2014         48       2014        0.2
# per mese
data.frame(F_ASS = table(data$month), F_REL = prop.table(table(data$month)))
##    F_ASS.Var1 F_ASS.Freq F_REL.Var1 F_REL.Freq
## 1           1         20          1 0.08333333
## 2           2         20          2 0.08333333
## 3           3         20          3 0.08333333
## 4           4         20          4 0.08333333
## 5           5         20          5 0.08333333
## 6           6         20          6 0.08333333
## 7           7         20          7 0.08333333
## 8           8         20          8 0.08333333
## 9           9         20          9 0.08333333
## 10         10         20         10 0.08333333
## 11         11         20         11 0.08333333
## 12         12         20         12 0.08333333

Funzione per gli indici statistici

Ho definito una funzione per calcolare tutti gli indici in un colpo solo, così non devo riscrivere le stesse cose ogni volta.

indici_stat <- function(x){
  data.frame(
    Indice = c("Media", "Mediana", "Min", "Q1", "Q3", "Max", "Range",
               "Varianza", "Dev_std", "Coeff_var", "IQR", "Asimmetria", "Curtosi"),
    Valore = round(c(
      mean(x), median(x), min(x),
      quantile(x,0.25), quantile(x,0.75),
      max(x), max(x) - min(x),
      var(x), sd(x), sd(x)/mean(x),
      IQR(x), skewness(x), kurtosis(x)
    ),3)
  )
}

Analisi delle variabili quantitative

Applico la funzione a ciascuna variabile e aggiungo istogramma e boxplot per vedere graficamente la distribuzione.

indici_stat(data$sales)
##        Indice   Valore
## 1       Media  192.292
## 2     Mediana  175.500
## 3         Min   79.000
## 4          Q1  127.000
## 5          Q3  247.000
## 6         Max  423.000
## 7       Range  344.000
## 8    Varianza 6344.300
## 9     Dev_std   79.651
## 10  Coeff_var    0.414
## 11        IQR  120.000
## 12 Asimmetria    0.718
## 13    Curtosi    2.687
hist(data$sales, main = "Istogramma sales", col="lightblue")

boxplot(data$sales)

indici_stat(data$volume)
##        Indice  Valore
## 1       Media  31.005
## 2     Mediana  27.062
## 3         Min   8.166
## 4          Q1  17.660
## 5          Q3  40.893
## 6         Max  83.547
## 7       Range  75.381
## 8    Varianza 277.271
## 9     Dev_std  16.651
## 10  Coeff_var   0.537
## 11        IQR  23.233
## 12 Asimmetria   0.885
## 13    Curtosi   3.177
hist(data$volume, main="Istogramma volume", col="lightblue")

boxplot(data$volume)

Notare, oltre allo sbilanciamento, la forte presebza di outliers nella distribuzione del volume, che indica dei mesi/città con volumi di vendita particolarmente elevati.

indici_stat(data$median_price)
##        Indice        Valore
## 1       Media    132665.417
## 2     Mediana    134500.000
## 3         Min     73800.000
## 4          Q1    117300.000
## 5          Q3    150050.000
## 6         Max    180000.000
## 7       Range    106200.000
## 8    Varianza 513572983.089
## 9     Dev_std     22662.149
## 10  Coeff_var         0.171
## 11        IQR     32750.000
## 12 Asimmetria        -0.365
## 13    Curtosi         2.377
hist(data$median_price, main = "Istogramma median_price")

boxplot(data$median_price)

Notare l’asimmetria a sinistra del prezzo mediano, che indica la rarità delle case a basso prezzo.

indici_stat(data$listings)
##        Indice     Valore
## 1       Media   1738.021
## 2     Mediana   1618.500
## 3         Min    743.000
## 4          Q1   1026.500
## 5          Q3   2056.000
## 6         Max   3296.000
## 7       Range   2553.000
## 8    Varianza 566568.966
## 9     Dev_std    752.708
## 10  Coeff_var      0.433
## 11        IQR   1029.500
## 12 Asimmetria      0.649
## 13    Curtosi      2.208
hist(data$listings, main="Istogramma listings")

boxplot(data$listings)

indici_stat(data$months_inventory)
##        Indice Valore
## 1       Media  9.193
## 2     Mediana  8.950
## 3         Min  3.400
## 4          Q1  7.800
## 5          Q3 10.950
## 6         Max 14.900
## 7       Range 11.500
## 8    Varianza  5.307
## 9     Dev_std  2.304
## 10  Coeff_var  0.251
## 11        IQR  3.150
## 12 Asimmetria  0.041
## 13    Curtosi  2.826
hist(data$months_inventory, main = "Istogramma months_inventory")

boxplot(data$months_inventory)

Conclusione su variabilità e asimmetria

Tra tutte le variabili quella che spicca di più è volume. Ha il coefficiente di variazione più alto (0.537), quindi è la più dispersa in termini relativi. La skewness è 0.885, cioè c’è una asimmetria a destra abbastanza forte.Dall’istogramma si capisce bene perchè: la maggior parte dei valori sta in basso e poi ci sono pochi casi con valori molto alti che allungano la coda verso destra. In sostanza è la variabile meno “regolare” che abbiamo nel dataset.

Probabilità e variabili derivate

n <- nrow(data)

# probabilità dela città Beaumont
prob_beaumont <- mean(data$city == "Beaumont")
prob_beaumont
## [1] 0.25
# probabilità di luglio
prob_luglio <- mean(data$month == 7)
prob_luglio
## [1] 0.08333333
# probabilità di dicembre 2012
prob_dic12 <- sum(data$month == 12 & data$year == 2012) / n
prob_dic12
## [1] 0.01666667
# creo il prezzo medio effettivo
data$mean_price <- (data$volume * 1000000) / data$sales
hist(data$mean_price, main="Distribuzione prezzo medio", col="lightyellow")

Malgrado il mediano sia nativo per singola riga del dataset ed il medio sia calcolato artificialmente, esso risulta, come da manuale, più sbilanciato verso valori alti rispetto al mediano. ## Indice di efficacia

Qui l’idea è costruire un indice che sintetizzi quanto è “efficace” un mercato. Un mercato che funziona bene dovrebbe avere tante vendite, pochi annunci e tempi brevi.Ho quindi standardizzato le tre variabili e le ho combinate: sales con segno positivo, listings e months_inventory con segno negativo.

sales_std <- scale(data$sales)
listings_std <- scale(data$listings)
inv_std <- scale(data$months_inventory)

data$indice_efficacia <- as.numeric(sales_std - listings_std - inv_std)

# normalizzo tra 0 e 1
min_val <- min(data$indice_efficacia)
max_val <- max(data$indice_efficacia)
data$eff_norm <- (data$indice_efficacia - min_val)/(max_val - min_val)

Ordinamento e analisi dell’indice

data_ord <- data[order(data$eff_norm),]
# i 5 peggiori
head(data_ord[,c("city","sales","listings","months_inventory","eff_norm")], 5)
##      city sales listings months_inventory   eff_norm
## 131 Tyler   155     3042             13.4 0.00000000
## 129 Tyler   220     3296             13.8 0.03109123
## 130 Tyler   202     3156             13.5 0.04029059
## 133 Tyler   143     2852             12.6 0.04577798
## 137 Tyler   271     3266             14.9 0.05175071
# i 5 migliori
tail(data_ord[,c("city","sales","listings","months_inventory","eff_norm")], 5)
##                      city sales listings months_inventory  eff_norm
## 103 Bryan-College Station   402     1385              6.1 0.8636202
## 116 Bryan-College Station   298     1016              4.0 0.8734199
## 113 Bryan-College Station   353     1212              4.8 0.8818658
## 114 Bryan-College Station   377     1152              4.5 0.9339865
## 115 Bryan-College Station   403     1041              4.1 1.0000000
hist(data$eff_norm, main="Distribuzione indice di efficacia", col="lightgreen")

Cluster di efficacia

Divido l’indice in 5 classi per vedere come si distribuiscono le varie città e i mesi.

clusters <- cut(data$eff_norm, breaks = 5)
round(prop.table(table(data$city, clusters), 2)*100, 2)
##                        clusters
##                         (-0.001,0.2] (0.2,0.4] (0.4,0.6] (0.6,0.8] (0.8,1]
##   Beaumont                     11.11     44.30     19.64      0.00    0.00
##   Bryan-College Station         0.00     21.52     19.64     93.75  100.00
##   Tyler                        88.89     32.91      8.04      6.25    0.00
##   Wichita Falls                 0.00      1.27     52.68      0.00    0.00
round(prop.table(table(data$month, clusters), 2)*100, 2)
##     clusters
##      (-0.001,0.2] (0.2,0.4] (0.4,0.6] (0.6,0.8] (0.8,1]
##   1         11.11     10.13      7.14      6.25    0.00
##   2         11.11     11.39      6.25      6.25    0.00
##   3          3.70     11.39      8.04      6.25    0.00
##   4          3.70     11.39      8.04      0.00   16.67
##   5         11.11      6.33      8.93      6.25   16.67
##   6          7.41      7.59      8.93      6.25   16.67
##   7          7.41      6.33      9.82      0.00   33.33
##   8          7.41      5.06      9.82     12.50   16.67
##   9         14.81      6.33      8.04     12.50    0.00
##   10         7.41      8.86      8.04     12.50    0.00
##   11         7.41      8.86      8.04     12.50    0.00
##   12         7.41      6.33      8.93     18.75    0.00

Medie per città e per mese

round(tapply(data$eff_norm, data$city, mean), 3)
##              Beaumont Bryan-College Station                 Tyler 
##                 0.365                 0.534                 0.257 
##         Wichita Falls 
##                 0.486
round(tapply(data$eff_norm, data$month, mean), 3)
##     1     2     3     4     5     6     7     8     9    10    11    12 
## 0.355 0.357 0.395 0.400 0.437 0.441 0.436 0.445 0.397 0.410 0.400 0.453

In quanto ad efficacia è evidente che la vincitrice sia la città di Bryan-Collage Station, come verificheremo anche in seguito più dettagliatamente. I mesi più efficaci risultano quelli estivi. ## Distribuzione di sales in classi

classi <- cut(data$sales, breaks=5)
freq <- table(classi)
freq_rel <- prop.table(freq)
freq_cum <- cumsum(freq_rel)

data.frame(freq, freq_rel, freq_cum)
##                classi Freq   classi.1     Freq.1  freq_cum
## (78.7,148] (78.7,148]   84 (78.7,148] 0.35000000 0.3500000
## (148,217]   (148,217]   77  (148,217] 0.32083333 0.6708333
## (217,285]   (217,285]   41  (217,285] 0.17083333 0.8416667
## (285,354]   (285,354]   27  (285,354] 0.11250000 0.9541667
## (354,423]   (354,423]   11  (354,423] 0.04583333 1.0000000
barplot(freq, main = "Distribuzione sales in classi", col = "steelblue")

Indice di Gini

k <- length(freq_rel)
gini <- (1 - sum(freq_rel^2)) / (1-1/k)
gini
## [1] 0.9132812

L’indice di Gini viene 0.913. È un valore alto, che di solito indica buona dispersione tra le classi. Però attenzione: non vuol dire che la distribuzione sia uniforme. guardando le frequenze si vede che quasi tutte le osservazioni cadono nelle prime classi, quindi c’è asimmetria eccome. Il Gini alto dipende dal fatto che nessuna classe da sola concentra una fetta schiacciante dei dati, sono un pò distribuite ma comunque spostate verso il basso.

Analisi Raggruppata per città

summary_city <- data %>%
  group_by(city) %>%
  summarise(
    mean_sales = mean(sales),
    sd_sales = sd(sales),
    mean_volume = mean(volume),
    sd_volume = sd(volume),
    mean_price = mean(mean_price),
    mean_eff = mean(eff_norm)
  )
summary_city
## # A tibble: 4 × 7
##   city             mean_sales sd_sales mean_volume sd_volume mean_price mean_eff
##   <chr>                 <dbl>    <dbl>       <dbl>     <dbl>      <dbl>    <dbl>
## 1 Beaumont               177.     41.5        26.1      6.97    146640.    0.365
## 2 Bryan-College S…       206.     85.0        38.2     17.2     183534.    0.534
## 3 Tyler                  270.     62.0        45.8     13.1     167677.    0.257
## 4 Wichita Falls          116.     22.2        13.9      3.24    119430.    0.486

Le differenze tra città sono abbastanza nette. Tyler vende di più di tutte come media, Wichita Falls è quella più ferma. Sul volume la situazione è simile. Dove cambia un po’ è sui prezzi: Bryan-College Station ha i prezzi medi più alti, Wichita Falls i più bassi. Sono proprio mercati diversi come struttura, non solo come dimensione. La cosa che mi ha colpito di più è sull’indice di efficacia, come già precedentemente osservato. Bryan-College Station è in cima nonostante non sia quella che vende di più, mentre Tyler è più in basso anche se ha tantissime vendite.Probabilmente dipende dal fatto che a Tyler ci sono anche tanti annunci e ci vuole più tempo per vendere, quindi l’indice scende. I boxplot sotto mostrano bene questa differenza. Inoltre le vendite e il volume di Bryan mostrano una maggiore deviazione standard, quindi per quanto la media sia più bassa di Tyler, abbiamo una grande variabilita’.

Analisi per anno

summary_year <- data %>%
  group_by(year) %>%
  summarise(
    mean_sales = mean(sales),
    mean_volume = mean(volume),
    mean_price = mean(mean_price),
    mean_eff = mean(eff_norm)
  )
summary_year
## # A tibble: 5 × 5
##    year mean_sales mean_volume mean_price mean_eff
##   <int>      <dbl>       <dbl>      <dbl>    <dbl>
## 1  2010       169.        25.7    150189.    0.334
## 2  2011       164.        25.2    148251.    0.284
## 3  2012       186.        29.3    150899.    0.367
## 4  2013       212.        35.2    158705.    0.490
## 5  2014       231.        39.8    163559.    0.578

C’è una crescita nel tempo. Nel 2011 c’è un piccolo calo, ma poi dal 2012 le cose ripartono e nel 2014 si toccano i valori più alti di vendite e volume.Il prezzo medio sale anche lui negli ultimi anni. L’efficacia migliora anno dopo anno, segno che probabilmente il mercato stava diventando più reattivo. Anche nei boxplot sotto si vede questa tendenza.

Analisi per mese

summary_month <- data %>%
  group_by(month) %>%
  summarise(
    mean_sales = mean(sales),
    sd_sales = sd(sales),
    mean_volume = mean(volume),
    sd_volume = sd(volume),
    mean_median_price = mean(median_price),
    sd_median_price = sd(median_price),
    mean_price = mean(mean_price),
    sd_price = sd(mean_price),
    mean_eff = mean(eff_norm),
    sd_eff = sd(eff_norm)
  )
summary_month
## # A tibble: 12 × 11
##    month mean_sales sd_sales mean_volume sd_volume mean_median_price
##    <int>      <dbl>    <dbl>       <dbl>     <dbl>             <dbl>
##  1     1       127.     43.4        19.0      8.37            124250
##  2     2       141.     51.1        21.7     10.1             130075
##  3     3       189.     59.2        29.4     12.0             127415
##  4     4       212.     65.4        33.3     14.5             131490
##  5     5       239.     83.1        39.7     19.0             134485
##  6     6       244.     95.0        41.3     21.1             137620
##  7     7       236.     96.3        39.1     21.4             134750
##  8     8       231.     79.2        38.0     18.0             136675
##  9     9       182.     72.5        29.6     15.2             134040
## 10    10       180.     75.0        29.1     15.1             133480
## 11    11       157.     55.5        24.8     11.2             134305
## 12    12       169.     60.7        27.1     12.6             133400
## # ℹ 5 more variables: sd_median_price <dbl>, mean_price <dbl>, sd_price <dbl>,
## #   mean_eff <dbl>, sd_eff <dbl>

La stagionalità c’è ed è abbastanza chiara. Da gennaio le vendite salgono, il picco sta tra maggio e luglio più o meno, poi calano fino a dicembre. anche i prezzi sono un pò più alti nei mesi centrali, il che ha senso perchè quando c’è più domanda i prezzi tendono a salire. L’efficacia segue lo stesso pattern, come già precedentemente osservato: nei mesi caldi il mercato gira meglio, in inverno è più lento.

Boxplot del prezzo mediano per città

ggplot(data, aes(x = city, y = median_price)) +
  geom_boxplot(fill = "lightblue") +
  labs(title = "Distribuzione del prezzo mediano per città",
       x = "Città", y = "Prezzo mediano") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Boxplot del volume per anno

ggplot(data, aes(x = factor(year), y = volume)) +
  geom_boxplot(fill="lightyellow") +
  labs(title = "Distribuzione del volume delle vendite per anno",
       x = "Anno", y = "Volume")

Totale vendite per mese e città

sales_city_month <- data %>%
  group_by(month, city) %>%
  summarise(tot_sales = sum(sales), .groups="drop")

ggplot(sales_city_month, aes(x = factor(month), y = tot_sales, fill = city)) +
  geom_col() +
  labs(title = "Totale vendite per mese e città",
       x = "Mese", y = "Totale vendite")

Il grafico lo conferma: le vendite salgono verso l’estate e poi scendono. Tyler pesa di più quasi sempre, Wichita Falls è sempre in fondo. Le altre due stanno in mezzo con andamenti simili tra loro.Il mercato d’inverno è chiaramente più fermo.

Composizione percentuale

ggplot(sales_city_month, aes(x = factor(month), y = tot_sales, fill = city)) +
  geom_col(position = "fill") +
  labs(title = "Composizione % delle vendite per mese e città",
       x = "Mese", y = "Percentuale")

Vendite per mese e città, divise per anno

sales_city_month_year <- data %>%
  group_by(year, month, city) %>%
  summarise(tot_sales = sum(sales), .groups = "drop")

ggplot(sales_city_month_year, aes(x = factor(month), y = tot_sales, fill = city)) +
  geom_col() +
  facet_wrap(~year) +
  labs(title = "Totale vendite per mese e città, per anno",
       x = "Mese", y = "Totale vendite")

Separando per anno lo schema stagionale si vede uguale, ma si nota anche la crescita complessiva: le barre del 2014 sono decisamente più alte di quelle del 2010. il 2011 è un pò più basso degli altri anni, poi dal 2012 riprende. Le proporzioni tra le città non cambiano granché da un anno all’altro, Tyler è sempre quella con più vendite e Wichita Falls quella con meno. la struttura resta stabile ma il livello complessivo sale.

Andamento temporale delle vendite

data_time <- data %>%
  arrange(year, month) %>%
  mutate(periodo = as.Date(paste(year, month, "01", sep="-")))

ggplot(data_time, aes(x = periodo, y = sales, color = city, group = city)) +
  geom_line() +
  labs(title = "Andamento delle vendite nel tempo per città",
       x = "Periodo", y = "Vendite") +
  scale_x_date(date_breaks = "1 year", date_labels = "%Y") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Dal grafico a linee si vede bene la crescita dal 2012 in poi, con le oscillazioni stagionali che si ripetono ogni anno. Tyler sta sempre sopra, Wichita Falls sempre sotto, Beaumont e Bryan-College Station nel mezzo.

Conclusioni

Da questa analisi il quadro che esce è abbastanza chiaro: il mercato immobiliare nelle quattro città del Texas considerate sta crescendo, sopratutto dal 2012. Vendite, volume e prezzi sono tutti in aumento. La stagionalità è un dato di fatto, i mesi da maggio a luglio circa sono quelli dove si vende di più e dove il mercato è più efficente. nei mesi invernali c’è un calo netto.Il volume è la variabile più instabile e asimmetrica, ci sono dei picchi ma non è una cosa costante. Questo vuol dire che il mercato non è proprio uniforme, ha dei momenti in cui si concentrano molte transazioni e altri in cui è più fermo.

Sulle città il punto più interessante secondo me è che vendere tanto non vuol dire per forza essere efficenti. Tyler fa più vendite di tutte ma l’indice di efficacia è più basso di Bryan-College Station, che ha meno offerta e tempi più rapidi. Questo fa capire che per valutare un mercato bisogna guardare anche quante case ci sono in lista e quanto ci mettono a vendersi, non solo quante se ne vendono. Come spunti pratici direi che ha senso concentrare le risorse nei mesi centrali dell’anno visto che il mercato è più ricettivo, mentre nei periodi più lenti magari si potrebbe lavorare sui prezzi o sulla quantità di annunci per non avere troppa offerta ferma. Nelle città con trend positivo si potrebbe pensare di investire di più, in quelle più deboli forse conviene ottimizzare quello che c’è piuttosto che espandersi. sono ragionamenti generali ovviamente, ogni situazione va guardata nel dettaglio.