setwd("C:/Users/barba/Downloads/RFile")
# Caricamento pacchetti
library(dplyr)
##
## Caricamento pacchetto: 'dplyr'
## I seguenti oggetti sono mascherati da 'package:stats':
##
## filter, lag
## I seguenti oggetti sono mascherati da 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2)
library(moments) # per skewness e kurtosis
# Funzione per etichette percentuali
percent_label <- function(x) paste0(round(x * 100, 1), "%")
# Import del dataset
df <- read.csv("realestate_texas.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 ...
L’obiettivo di questo lavoro è analizzare in modo descrittivo il
mercato immobiliare residenziale in alcune città del Texas (Beaumont,
Bryan‑College Station, Tyler, Wichita Falls) nel periodo 2010–2014,
utilizzando il dataset “Real Estate Texas”.
L’analisi mira a identificare trend storici nelle vendite, differenze
tra città, pattern stagionali e indicatori di efficacia delle
inserzioni, affiancando ai risultati numerici una serie di
visualizzazioni grafiche (boxplot, grafici a barre, line chart) utili
per supportare decisioni strategiche di business.
# Distribuzioni di frequenza per le variabili qualitative
table(df$city)
##
## Beaumont Bryan-College Station Tyler
## 60 60 60
## Wichita Falls
## 60
table(df$year)
##
## 2010 2011 2012 2013 2014
## 48 48 48 48 48
table(df$month)
##
## 1 2 3 4 5 6 7 8 9 10 11 12
## 20 20 20 20 20 20 20 20 20 20 20 20
# Riassunti descrittivi iniziali per le variabili quantitative
summary(df[, c("sales","volume","median_price",
"listings","months_inventory")])
## sales volume median_price listings
## Min. : 79.0 Min. : 8.166 Min. : 73800 Min. : 743
## 1st Qu.:127.0 1st Qu.:17.660 1st Qu.:117300 1st Qu.:1026
## Median :175.5 Median :27.062 Median :134500 Median :1618
## Mean :192.3 Mean :31.005 Mean :132665 Mean :1738
## 3rd Qu.:247.0 3rd Qu.:40.893 3rd Qu.:150050 3rd Qu.:2056
## Max. :423.0 Max. :83.547 Max. :180000 Max. :3296
## months_inventory
## Min. : 3.400
## 1st Qu.: 7.800
## Median : 8.950
## Mean : 9.193
## 3rd Qu.:10.950
## Max. :14.900
Il dataset contiene, per ogni città, anno e mese, informazioni relative alle vendite immobiliari. Le variabili sono le seguenti:
city: città di riferimento (Beaumont,
Bryan‑College Station, Tyler, Wichita Falls).
È una variabile qualitativa nominale, priva di ordinamento intrinseco;
si presta ad analisi basate su distribuzioni di frequenza e confronti
tra gruppi.
year: anno di riferimento (dal 2010 al
2014).
Variabile temporale (ordinale/discreta), fondamentale per l’analisi di
trend storici nel medio periodo.
month: mese di riferimento (1–12).
Variabile temporale ordinale, utile per lo studio della
stagionalità.
sales: numero totale di vendite
(conteggio).
Variabile quantitativa discreta; descrive l’intensità dell’attività di
compravendita.
volume: valore totale delle vendite in milioni
di dollari.
Variabile quantitativa continua; misura la dimensione economica del
mercato.
median_price: prezzo mediano di vendita in
dollari.
Variabile quantitativa continua; indicatore robusto del livello dei
prezzi.
listings: numero totale di annunci attivi.
Variabile quantitativa discreta; rappresenta l’offerta in ciascun
periodo.
months_inventory: mesi necessari a vendere tutte
le inserzioni correnti.
Variabile quantitativa continua; indica la liquidità del
mercato.
Le variabili temporali year e month non vengono analizzate con indici di posizione tradizionali, ma come dimensioni lungo le quali osservare l’evoluzione delle variabili quantitative (serie temporali, trend e stagionalità).
# Indici descrittivi globali
desc_global <- df %>%
summarise(
mean_sales = mean(sales), sd_sales = sd(sales),
mean_vol = mean(volume), sd_vol = sd(volume),
mean_price = mean(median_price), sd_price = sd(median_price),
mean_list = mean(listings), sd_list = sd(listings),
mean_mi = mean(months_inventory), sd_mi = sd(months_inventory)
)
desc_global
## mean_sales sd_sales mean_vol sd_vol mean_price sd_price mean_list sd_list
## 1 192.2917 79.65111 31.00519 16.65145 132665.4 22662.15 1738.021 752.7078
## mean_mi sd_mi
## 1 9.1925 2.303669
# Coefficienti di variazione
cv <- df %>%
summarise(
cv_sales = sd(sales) / mean(sales),
cv_vol = sd(volume) / mean(volume),
cv_price = sd(median_price) / mean(median_price),
cv_list = sd(listings) / mean(listings),
cv_mi = sd(months_inventory) / mean(months_inventory)
)
cv
## cv_sales cv_vol cv_price cv_list cv_mi
## 1 0.4142203 0.5370536 0.1708218 0.4330833 0.2506031
# Indici di forma (asimmetria e curtosi)
shape <- data.frame(
var = c("sales","volume","median_price","listings","months_inventory"),
skew = c(skewness(df$sales),
skewness(df$volume),
skewness(df$median_price),
skewness(df$listings),
skewness(df$months_inventory)),
kurt = c(kurtosis(df$sales),
kurtosis(df$volume),
kurtosis(df$median_price),
kurtosis(df$listings),
kurtosis(df$months_inventory))
)
shape
## var skew kurt
## 1 sales 0.71810402 2.686824
## 2 volume 0.88474203 3.176987
## 3 median_price -0.36455288 2.377038
## 4 listings 0.64949823 2.208210
## 5 months_inventory 0.04097527 2.825552
A livello complessivo, le variabili sales e volume mostrano valori medi differenti tra città, con Tyler e Bryan‑College Station generalmente caratterizzate da livelli di attività più elevati rispetto a Wichita Falls. La variabilità delle due variabili è significativa, segnalando oscillazioni notevoli da un mese all’altro.
La variabile median_price presenta una dispersione
inferiore a quella del volume, ma evidenzia differenze di livello tra
città (mercati più o meno “ricchi”).
Le variabili listings e
months_inventory risultano più elevate all’inizio del
periodo e in progressivo calo verso il 2013–2014, suggerendo una
maggiore efficienza e liquidità del mercato nel tempo.
Per le variabili qualitative (city, year, month) le distribuzioni di frequenza confermano un buon bilanciamento delle osservazioni tra città, anni e mesi, consentendo confronti temporali e spaziali affidabili.
# Individuazione della variabile con CV più alto
cv_long <- tidyr::pivot_longer(cv, everything(),
names_to = "var", values_to = "cv")
cv_long
## # A tibble: 5 × 2
## var cv
## <chr> <dbl>
## 1 cv_sales 0.414
## 2 cv_vol 0.537
## 3 cv_price 0.171
## 4 cv_list 0.433
## 5 cv_mi 0.251
# Individuazione della variabile con skewness più alto in valore assoluto
shape$abs_skew <- abs(shape$skew)
shape[order(-shape$abs_skew), ]
## var skew kurt abs_skew
## 2 volume 0.88474203 3.176987 0.88474203
## 1 sales 0.71810402 2.686824 0.71810402
## 4 listings 0.64949823 2.208210 0.64949823
## 3 median_price -0.36455288 2.377038 0.36455288
## 5 months_inventory 0.04097527 2.825552 0.04097527
Per confrontare la variabilità relativa si è utilizzato il coefficiente di variazione. Dai calcoli emerge che il volume delle vendite è la variabile con il CV più elevato, quindi quella con maggiore dispersione relativa rispetto alla media.
Per l’asimmetria, la variabile volume mostra la
skewness in valore assoluto più alta, con asimmetria positiva marcata:
la distribuzione è concentrata su valori medi/bassi, ma presenta alcuni
mesi con volumi molto elevati che generano una coda a destra.
Si conclude dunque che:
# Scelta della variabile quantitativa: median_price
min_p <- min(df$median_price)
max_p <- max(df$median_price)
# Creazione di 6 classi di uguale ampiezza
breaks <- seq(min_p, max_p, length.out = 7)
df$price_class <- cut(df$median_price, breaks = breaks, include.lowest = TRUE)
# Distribuzione di frequenza per classi
freq_price <- table(df$price_class)
rel_freq_price <- prop.table(freq_price)
freq_price
##
## [7.38e+04,9.15e+04] (9.15e+04,1.09e+05] (1.09e+05,1.27e+05] (1.27e+05,1.45e+05]
## 13 33 37 73
## (1.45e+05,1.62e+05] (1.62e+05,1.8e+05]
## 68 16
rel_freq_price
##
## [7.38e+04,9.15e+04] (9.15e+04,1.09e+05] (1.09e+05,1.27e+05] (1.27e+05,1.45e+05]
## 0.05416667 0.13750000 0.15416667 0.30416667
## (1.45e+05,1.62e+05] (1.62e+05,1.8e+05]
## 0.28333333 0.06666667
# Grafico a barre delle classi di prezzo
ggplot(df, aes(x = price_class)) +
geom_bar() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(x = "Classi di prezzo mediano", y = "Frequenza")
# Indice di eterogeneità di Gini
p <- as.numeric(rel_freq_price)
gini_eterogeneita <- 1 - sum(p^2)
gini_eterogeneita
## [1] 0.7771528
La distribuzione per classi del median_price mostra una maggiore concentrazione nelle fasce centrali, con un numero più limitato di osservazioni nelle classi corrispondenti ai prezzi più elevati. Questo conferma la presenza di una certa asimmetria positiva.
L’indice di Gini di eterogeneità assume un valore intermedio‑alto, segnalando che le osservazioni sono distribuite su più classi, pur con una densità maggiore in un intervallo centrale. Esiste quindi una discreta varietà di segmenti di prezzo, utile per la segmentazione della clientela e delle strategie di listing.
n_tot <- nrow(df)
# Probabilità che la riga sia relativa a Beaumont
p_beaumont <- sum(df$city == "Beaumont") / n_tot
p_beaumont
## [1] 0.25
# Probabilità che la riga sia relativa al mese di luglio
p_july <- sum(df$month == 7) / n_tot
p_july
## [1] 0.08333333
# Probabilità che la riga sia relativa a Beaumont, dicembre 2012
p_dec2012_beaumont <- sum(df$city == "Beaumont" &
df$year == 2012 &
df$month == 12) / n_tot
p_dec2012_beaumont
## [1] 0.004166667
La probabilità empirica che una riga del dataset si riferisca a
Beaumont è data dal rapporto tra il numero di
osservazioni per questa città e il numero totale di osservazioni.
Analogamente, la probabilità che una riga si riferisca al mese
di luglio si ottiene come quota di righe con month = 7 sul
totale.
Per l’evento congiunto “dicembre 2012 a Beaumont”, la probabilità corrisponde alla proporzione di righe con city = Beaumont, year = 2012 e month = 12 sul totale: essendo presente una sola combinazione per ogni città‑anno‑mese, tale probabilità è pari a 1 diviso il numero totale di righe.
# Creazione della variabile avg_price
df <- df %>%
mutate(avg_price = (volume * 1e6) / sales)
summary(df$avg_price)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 97010 132939 156588 154320 173915 213234
# Confronto con median_price
cor(df$median_price, df$avg_price)
## [1] 0.9464941
ggplot(df, aes(x = median_price, y = avg_price, color = city)) +
geom_point() +
labs(x = "Prezzo mediano", y = "Prezzo medio per transazione")
La nuova variabile avg_price rappresenta il prezzo
medio di ogni transazione e, confrontata con
median_price, fornisce indicazioni sulla forma della
distribuzione dei prezzi.
Dove media e mediana sono simili, la distribuzione dei prezzi è
abbastanza simmetrica; dove la media risulta più elevata, si osserva una
coda a destra, dovuta a poche transazioni di valore particolarmente
alto.
# Indicatori di efficacia
df <- df %>%
mutate(
eff_ratio = sales / listings,
eff_sales_per_mi = sales / months_inventory
)
summary(df$eff_ratio)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.05014 0.08980 0.10963 0.11874 0.13492 0.38713
summary(df$eff_sales_per_mi)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.737 14.165 18.477 22.457 26.424 98.293
# Confronto per città
df %>%
group_by(city) %>%
summarise(
mean_eff_ratio = mean(eff_ratio),
mean_eff_sales_per_mi = mean(eff_sales_per_mi)
)
## # A tibble: 4 × 3
## city mean_eff_ratio mean_eff_sales_per_mi
## <chr> <dbl> <dbl>
## 1 Beaumont 0.106 18.7
## 2 Bryan-College Station 0.147 31.2
## 3 Tyler 0.0935 24.9
## 4 Wichita Falls 0.128 15.0
L’indicatore eff_ratio misura la quota di annunci
che si trasformano in vendite, mentre eff_sales_per_mi
interpreta le vendite in rapporto al tempo di assorbimento
dell’inventario.
In molte città tali indicatori mostrano una tendenza alla crescita negli
anni, coerente con il calo di months_inventory, e suggerendo un mercato
via via più efficiente.
# Summary per città
summary_city <- df %>%
group_by(city) %>%
summarise(
mean_sales = mean(sales), sd_sales = sd(sales),
mean_vol = mean(volume), sd_vol = sd(volume),
mean_price = mean(median_price), sd_price = sd(median_price),
mean_list = mean(listings), sd_list = sd(listings),
mean_mi = mean(months_inventory), sd_mi = sd(months_inventory),
mean_eff_ratio = mean(eff_ratio),
mean_eff_sales_per_mi = mean(eff_sales_per_mi)
)
summary_city
## # A tibble: 4 × 13
## city mean_sales sd_sales mean_vol sd_vol mean_price sd_price mean_list
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Beaumont 177. 41.5 26.1 6.97 129988. 10105. 1679.
## 2 Bryan-Colle… 206. 85.0 38.2 17.2 157488. 8852. 1458.
## 3 Tyler 270. 62.0 45.8 13.1 141442. 9337. 2905.
## 4 Wichita Fal… 116. 22.2 13.9 3.24 101743. 11320. 910.
## # ℹ 5 more variables: sd_list <dbl>, mean_mi <dbl>, sd_mi <dbl>,
## # mean_eff_ratio <dbl>, mean_eff_sales_per_mi <dbl>
# Summary per città e anno
summary_city_year <- df %>%
group_by(city, year) %>%
summarise(
mean_sales = mean(sales),
mean_vol = mean(volume),
mean_price = mean(median_price),
mean_eff_ratio = mean(eff_ratio),
.groups = "drop"
)
summary_city_year
## # A tibble: 20 × 6
## city year mean_sales mean_vol mean_price mean_eff_ratio
## <chr> <int> <dbl> <dbl> <dbl> <dbl>
## 1 Beaumont 2010 156. 22.7 133117. 0.0898
## 2 Beaumont 2011 144 21.1 125642. 0.0823
## 3 Beaumont 2012 172. 24.5 126533. 0.102
## 4 Beaumont 2013 201. 30.3 132400 0.123
## 5 Beaumont 2014 214. 32.1 132250 0.135
## 6 Bryan-College Station 2010 168. 28.7 153533. 0.106
## 7 Bryan-College Station 2011 167. 28.9 151417. 0.103
## 8 Bryan-College Station 2012 197. 35.4 153567. 0.122
## 9 Bryan-College Station 2013 238. 45.1 159392. 0.171
## 10 Bryan-College Station 2014 260. 52.8 169533. 0.236
## 11 Tyler 2010 228. 36.3 135175 0.0745
## 12 Tyler 2011 239. 38.6 136217. 0.0773
## 13 Tyler 2012 264. 44.0 139250 0.0902
## 14 Tyler 2013 287. 50.3 146100 0.101
## 15 Tyler 2014 332. 59.6 150467. 0.124
## 16 Wichita Falls 2010 123. 15.0 98942. 0.129
## 17 Wichita Falls 2011 106. 12.1 98142. 0.108
## 18 Wichita Falls 2012 112. 13.2 100958. 0.126
## 19 Wichita Falls 2013 121. 14.9 105000 0.144
## 20 Wichita Falls 2014 117 14.5 105675 0.133
# Summary per città e mese (pattern stagionali)
summary_city_month <- df %>%
group_by(city, month) %>%
summarise(
mean_sales = mean(sales),
mean_price = mean(median_price),
.groups = "drop"
)
summary_city_month
## # A tibble: 48 × 4
## city month mean_sales mean_price
## <chr> <int> <dbl> <dbl>
## 1 Beaumont 1 122. 127460
## 2 Beaumont 2 135. 126980
## 3 Beaumont 3 171 124460
## 4 Beaumont 4 190. 129820
## 5 Beaumont 5 207. 129320
## 6 Beaumont 6 205 130680
## 7 Beaumont 7 185. 130900
## 8 Beaumont 8 217. 138480
## 9 Beaumont 9 174 127760
## 10 Beaumont 10 189. 130820
## # ℹ 38 more rows
L’analisi condizionata per città evidenzia differenze di livello nei principali indicatori: Tyler e Bryan‑College Station presentano vendite e volumi medi più elevati, Wichita Falls valori inferiori e Beaumont posizioni intermedie.
L’analisi per anno mostra un aumento di vendite,
volume e prezzi medi nella maggior parte delle città, segno di un
mercato in consolidamento.
L’analisi per mese conferma un pattern stagionale, con
mesi primaverili‑estivi più attivi rispetto ai mesi invernali.
ggplot(df, aes(x = city, y = median_price)) +
geom_boxplot() +
labs(x = "Città", y = "Prezzo mediano ($)")
I boxplot di median_price per città mostrano chiaramente differenze nelle mediane e nella dispersione dei prezzi. Alcune città hanno livelli di prezzo tipicamente più elevati, altre risultano più economiche. Questo influisce direttamente sul posizionamento commerciale degli immobili nelle diverse aree.
# Boxplot per città
ggplot(df, aes(x = city, y = volume)) +
geom_boxplot() +
labs(x = "Città", y = "Volume vendite (milioni $)")
# Boxplot per anno
ggplot(df, aes(x = factor(year), y = volume)) +
geom_boxplot() +
labs(x = "Anno", y = "Volume vendite (milioni $)")
I boxplot del volume per città evidenziano mercati
strutturalmente più grandi (Tyler, Bryan‑College Station) rispetto a
quelli più piccoli (Wichita Falls).
A livello di anno, i boxplot mostrano un progressivo aumento dei volumi
nel periodo, con un incremento non solo dei valori centrali ma anche
della dispersione negli anni più recenti.
# Totali delle vendite per mese e città
df_month_city <- df %>%
group_by(city, month) %>%
summarise(total_sales = sum(sales), .groups = "drop")
# Barre sovrapposte (stacked)
ggplot(df_month_city, aes(x = factor(month), y = total_sales, fill = city)) +
geom_col(position = "stack") +
labs(x = "Mese", y = "Totale vendite", fill = "Città")
# Barre normalizzate (percentuali) SENZA scales
ggplot(df_month_city, aes(x = factor(month), y = total_sales, fill = city)) +
geom_col(position = "fill") +
scale_y_continuous(labels = percent_label) +
labs(x = "Mese", y = "Quota sul totale del mese", fill = "Città")
# PRO LEVEL: includere anche l'anno con facet
df_my <- df %>%
group_by(city, year, month) %>%
summarise(total_sales = sum(sales), .groups = "drop")
ggplot(df_my, aes(x = factor(month), y = total_sales, fill = city)) +
geom_col(position = "stack") +
facet_wrap(~ year, nrow = 2) +
labs(x = "Mese", y = "Totale vendite", fill = "Città")
I grafici a barre mettono in luce la stagionalità delle vendite e la ripartizione dei volumi tra le diverse città nei vari mesi e anni. I mesi centrali dell’anno risultano generalmente più dinamici, con variazioni interessanti nella quota relativa di ciascuna città.
# Costruzione di un indice temporale continuo
df <- df %>%
mutate(time = year + (month - 0.5) / 12)
# Line chart mensile del prezzo mediano
ggplot(df, aes(x = time, y = median_price, color = city)) +
geom_line() +
labs(x = "Anno", y = "Prezzo mediano ($)", color = "Città")
# Aggregazione annuale per linee più lisce
df_year <- df %>%
group_by(city, year) %>%
summarise(mean_price = mean(median_price), .groups = "drop")
ggplot(df_year, aes(x = year, y = mean_price, color = city)) +
geom_line() +
geom_point() +
labs(x = "Anno", y = "Prezzo mediano medio annuale ($)", color = "Città")
Le linee mostrano una tendenza generalmente crescente del prezzo mediano nel periodo 2010–2014, con velocità diverse tra città. Analoghi grafici per le vendite e i volumi confermano il rafforzamento del mercato nel tempo.
L’analisi descrittiva del dataset “Real Estate Texas” permette di concludere che:
Per Texas Realty Insights, questi risultati suggeriscono di: