Il dataset contiene variabili sia qualitative che quantitative. Riporto sotto una descrizione per ciascuna:
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
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
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)
)
}
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)
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.
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)
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")
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
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")
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.
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’.
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.
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.
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))
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")
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.
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")
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.
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.
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.