Introduzione

Descrizione del progetto

L’azienda Texas Realty Insights desidera analizzare le tendenze del mercato immobiliare nello stato del Texas, sfruttando i dati storici relativi alle vendite di immobili. L’obiettivo è fornire insight statistici e visivi che supportino le decisioni strategiche di vendita e ottimizzazione delle inserzioni immobiliari.

Obiettivi del progetto

Identificare e interpretare i trend storici delle vendite immobiliari in Texas. Valutare l’efficacia delle strategie di marketing delle inserzioni immobiliari. Offrire una rappresentazione grafica dei dati che evidenzi la distribuzione dei prezzi e delle vendite tra città, mesi e anni.

Valore Aggiunto

L’analisi statistica proposta permetterà a Texas Realty Insights di ottimizzare le loro strategie di mercato, identificando città con opportunità di crescita e valutando l’efficacia delle inserzioni immobiliari nel tempo. Grazie a una visione chiara e strutturata dei dati, l’azienda potrà prendere decisioni basate su informazioni concrete, migliorando la gestione delle vendite immobiliari in Texas.

1. Analisi delle variabili

data <- read.csv("C:/Users/fede_/Documents/professionai/statistica_descrittiva/realestate_texas.csv")
attach(data)
cat("Rows:", nrow(data), "Columns:", ncol(data), "\n")
## Rows: 240 Columns: 8
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
print(unique(city))
## [1] "Beaumont"              "Bryan-College Station" "Tyler"                
## [4] "Wichita Falls"
print(unique(year))
## [1] 2010 2011 2012 2013 2014
print(unique(month))
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12

Il dataset è composto da 240 osservazioni e 8 variabili. Ciascuna osservazione rappresenta la registrazione di diverse informazioni per una determinata città, in un determinato anno e mese. Sono presenti 4 città, registrate ogni mese tra il 2010 e il 2014 (4 città x 5 anni x 12 mesi = 240). Per ciascuna città, in ciascun anno e mese, il dataset riporta: il numero e il valore totale delle vendite, il prezzo mediano di vendita, il numero di annunci attivi, e il tempo richiesto per vendere tutte le inserzioni.
Certamente, potrebbe essere interessante indagare come queste variabili varino nel tempo, analizzando le differenze tra le diverse città. Sarebbe interessante, però, indagare anche la relazione tra le diverse variabli. Per esempio, si potrebbe osservare come varino il tempo richiesto per vendere tutte le inserzioni, il numereo e il valore totale delle vendite, al variare del prezzo mediano o del numero di annunci attivi.

2. Indici di Posizione, Variabilità e Forma

library(moments)

measures <- c("Minimo", "Q1", "Q3", "Massimo", "Mediana", "Media")
vars <- c("sales", "volume", "median_price", "listings", "months_inventory")
results <- matrix(nrow = length(measures), ncol = length(vars))
rownames(results) <- measures
colnames(results) <- vars

for (i in seq_along(vars)) {
  x <- data[[vars[i]]]
  results[ , i] <- c(
    min(x),
    quantile(x, 0.25),
    quantile(x, 0.75),
    max(x),
    median(x),
    mean(x)
  )
}

results <- as.data.frame(results)
results <- round(results, 3)
print(results)
##           sales volume median_price listings months_inventory
## Minimo   79.000  8.166      73800.0  743.000            3.400
## Q1      127.000 17.660     117300.0 1026.500            7.800
## Q3      247.000 40.893     150050.0 2056.000           10.950
## Massimo 423.000 83.547     180000.0 3296.000           14.900
## Mediana 175.500 27.062     134500.0 1618.500            8.950
## Media   192.292 31.005     132665.4 1738.021            9.193

Nel complesso, osservando questi indici è possibile fare diverse considerazioni. Il valore totale medio delle vendite in un mese è di circa 31 milioni, con un range che va da un minimo di 8 milioni ad un massimo di 83 milioni a mese. Mediamente, ogni mese sono stati venduti circa 192 mila immobili. Inoltre, nei 5 anni considerati (2010-2014), nel 75% dei mesi gli immobili venduti sono stati almeno 127 mila. In media, il prezzo mediano di vendita è stato di circa 132 mila dollari, con un massimo di 180 mila dollari. Il numero minimo di annunci attivi in un mese è stato di 743, con un massimo di 3296. Nel 25% dei casi sono sempre stati più di 1000, mentre solo nel 25% dei casi sono stati più di 2000. Infine, in media sono serviti circa 9 mesi per vendere tutte le inserzioni del mese, con un massimo di più di un anno (15 mesi) e uun minimo di poco più di un trimestre.

3. Identificazione delle variabili con maggiore variabilità e asimmetria

measures <- c("Variance", "DevStd","CV", "Asimmetria", "Curtosi")
vars <- c("sales", "volume", "median_price", "listings", "months_inventory")
results <- matrix(nrow = length(measures), ncol = length(vars))
rownames(results) <- measures
colnames(results) <- vars

for (i in seq_along(vars)) {
  x <- data[[vars[i]]]
  results[ , i] <- c(
    var(x),
    sd(x),
    sd(x)/mean(x),
    skewness(x),
    kurtosis(x)
  )
}

results <- as.data.frame(results)
results <- round(results, 3)
print(results)
##               sales  volume  median_price   listings months_inventory
## Variance   6344.300 277.271 513572983.089 566568.966            5.307
## DevStd       79.651  16.651     22662.149    752.708            2.304
## CV            0.414   0.537         0.171      0.433            0.251
## Asimmetria    0.718   0.885        -0.365      0.649            0.041
## Curtosi       2.687   3.177         2.377      2.208            2.826

La variabile con varianza e deviazione standard più ampie è il prezzo mediano di vendita. Tuttavia, questi indici risentono della scala della misura, rendendo impossibile un confronto tra diverse varabili. Per questo, la variabile con maggiore variabilità è il valore totale delle vendite in un mese, con un coefficiente di variazione (CV) di 0.537. Inoltre, la stessa variable è anche la più asimmetrica, con un indice di asimmetria di 0.885. Questo ci fa intuire che la distribuzione sia schiacciata a destra, con una lunga coda a sinistra

4. Creazione di classi per una variabile quantitativa

categories <- cut(
  median_price,
  breaks = c(70000, 100000, 120000, 140000, 160000, 190000),
  labels = c("<100 mila", "100-120 mila", "120-140 mila", "140-160 mila", ">160 mila")
)
ni <- table(categories)
fi <- ni / dim(data)[1]
Ni <- cumsum(ni)
Fi <- Ni / dim(data)[1]
freq_tab <- cbind(ni, fi, Ni, Fi)
print(freq_tab)
##              ni        fi  Ni        Fi
## <100 mila    26 0.1083333  26 0.1083333
## 100-120 mila 40 0.1666667  66 0.2750000
## 120-140 mila 75 0.3125000 141 0.5875000
## 140-160 mila 78 0.3250000 219 0.9125000
## >160 mila    21 0.0875000 240 1.0000000
barplot(fi,
        main="Distribuzione delle Classi del Prezzo Mediano",
        xlab="Classe di Prezzo Mediano",
        ylab="Frequenze Relative",
        col="blue",
        names.arg=rownames(freq_tab))

calculate_gini <- function(fi){
  fi2 = fi^2
  J = length(fi)
  
  gini = 1 - sum(fi2)
  gini_norm = gini / ((J-1)/J)
  
  return(gini_norm)
}

gini <- calculate_gini(fi)
cat("Gini index = ", gini)
## Gini index =  0.9369358

Il prezzo mediano è stato suddiviso in classi ad intervalli approssimativamente regolari (20 mila dollari). Ciò che emerge subito dalla tavola di frequenze è che in più del 60% dei casi il prezzo mediano è stato tra 120 e 160 mila dollari. Inoltre sia la tavola di frequenze che il grafico a barre confermano un’asimmetria della distribuzione verso valori maggiori di 120 mila dollari. Infine l’indice di gini ha rivelato un’alta eterogeinà tra le classi estratte.

5. Calcolo della probabilità

La probabilità che, presa una riga a caso del dataset, essa riporti la città “Beaumont”, o che riporti il mese di luglio, o che riporti dicembre 2012 può essere calcolata secondo l’accezione classica della probabilità. Nello specifico, la probabilità di specifici eventi di cui conosciamo le frequenze può essere calcolata come numero di casi favorevoli su numero di casi possibili. In questo caso dunque, la probabilità che un’osservazione sia stata registrata a Beaumont corrisponde a 1/4 = 0.250, poichè Beaumont è una città di 4 possibili città equamente distribuite. Analogamente, la probabilità che una registrazione sia avvenuta a luglio è data dalla ripetizione di luglio per 5 anni per 4 città (=20) sul totale delle possibili osservazioni: 20/240 = 0.833. Infine, la probabilità che la registrazione sia avvenuta nel dicembre 2012 è di 4/240 = 0.017, poichè dicembre 2012 compare una volta per ogni città (N=4).

6. Creazione di nuove variabili

data$prezzo_medio <- (volume * 1e6) / sales
efficacia_annunci <- listings / sales
data$efficacia_annunci <- (efficacia_annunci - min(efficacia_annunci)) / (max(efficacia_annunci) - min(efficacia_annunci))

Sono state create due nuove variabili. Il prezzo medio dell’immobile per ogni mese considerato. La variabile è stata calcolata come il valore totale delle vendite diviso per il numero delle vendite. Il valore totale delle vendite, è stato riportato sulla scala dei milioni, per avere il prezzo medio sulla scala delle centinaia di migliaia.
L’efficiacia degli annunci invece è stata calcolata come il rapporto tra il numero di annunci attiv i n un determinato mese e il numero di vendite. La misura è stata poi riscalata tra 0 e 1 per avere un indice con dei limiti prestabiliti.

7. Analisi condizionata

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
vars <- names(data)[4:8]

summary_table <- data %>%
  group_by(city) %>%
  summarise(across(
    all_of(vars),
    list(
      media = ~mean(.x, na.rm = TRUE)
    ),
    .names = "{.col}"
  ), .groups = "drop")
print("Mean for each variable grouped by city")
## [1] "Mean for each variable grouped by city"
print(summary_table)
## # A tibble: 4 × 6
##   city                  sales volume median_price listings months_inventory
##   <chr>                 <dbl>  <dbl>        <dbl>    <dbl>            <dbl>
## 1 Beaumont               177.   26.1      129988.    1679.             9.97
## 2 Bryan-College Station  206.   38.2      157488.    1458.             7.66
## 3 Tyler                  270.   45.8      141442.    2905.            11.3 
## 4 Wichita Falls          116.   13.9      101743.     910.             7.82
vars <- names(data)[4:8]

summary_table <- data %>%
  group_by(city) %>%
  summarise(across(
    all_of(vars),
    list(
      sd = ~sd(.x, na.rm = TRUE)
    ),
    .names = "{.col}"
  ), .groups = "drop")
print("Standard deviation for each variable grouped by city")
## [1] "Standard deviation for each variable grouped by city"
print(summary_table)
## # A tibble: 4 × 6
##   city                  sales volume median_price listings months_inventory
##   <chr>                 <dbl>  <dbl>        <dbl>    <dbl>            <dbl>
## 1 Beaumont               41.5   6.97       10105.     91.1            1.65 
## 2 Bryan-College Station  85.0  17.2         8852.    253.             2.25 
## 3 Tyler                  62.0  13.1         9337.    227.             1.89 
## 4 Wichita Falls          22.2   3.24       11320.     73.8            0.781
vars <- names(data)[4:8]

summary_table <- data %>%
  group_by(year) %>%
  summarise(across(
    all_of(vars),
    list(
      media = ~mean(.x, na.rm = TRUE)
    ),
    .names = "{.col}"
  ), .groups = "drop")
print("Mean for each variable grouped by year")
## [1] "Mean for each variable grouped by year"
print(summary_table)
## # A tibble: 5 × 6
##    year sales volume median_price listings months_inventory
##   <int> <dbl>  <dbl>        <dbl>    <dbl>            <dbl>
## 1  2010  169.   25.7      130192.    1826              9.97
## 2  2011  164.   25.2      127854.    1850.            10.9 
## 3  2012  186.   29.3      130077.    1777.             9.88
## 4  2013  212.   35.2      135723.    1678.             8.15
## 5  2014  231.   39.8      139481.    1560.             7.06
vars <- names(data)[4:8]

summary_table <- data %>%
  group_by(year) %>%
  summarise(across(
    all_of(vars),
    list(
      sd = ~sd(.x, na.rm = TRUE)
    ),
    .names = "{.col}"
  ), .groups = "drop")
print("Standard deviation for each variable grouped by year")
## [1] "Standard deviation for each variable grouped by year"
print(summary_table)
## # A tibble: 5 × 6
##    year sales volume median_price listings months_inventory
##   <int> <dbl>  <dbl>        <dbl>    <dbl>            <dbl>
## 1  2010  60.5   10.8       21822.     785.             2.08
## 2  2011  63.9   12.2       21318.     780.             2.07
## 3  2012  70.9   14.5       21432.     738.             1.61
## 4  2013  84.0   17.9       21708.     744.             1.69
## 5  2014  95.5   21.2       25625.     707.             1.75
vars <- names(data)[4:8]

summary_table <- data %>%
  group_by(month) %>%
  summarise(across(
    all_of(vars),
    list(
      media = ~mean(.x, na.rm = TRUE)
    ),
    .names = "{.col}"
  ), .groups = "drop")
print("Mean for each variable grouped by month")
## [1] "Mean for each variable grouped by month"
print(summary_table)
## # A tibble: 12 × 6
##    month sales volume median_price listings months_inventory
##    <int> <dbl>  <dbl>        <dbl>    <dbl>            <dbl>
##  1     1  127.   19.0       124250    1647.             8.84
##  2     2  141.   21.7       130075    1692.             9.06
##  3     3  189.   29.4       127415    1757.             9.40
##  4     4  212.   33.3       131490    1826.             9.72
##  5     5  239.   39.7       134485    1824.             9.68
##  6     6  244.   41.3       137620    1833.             9.70
##  7     7  236.   39.1       134750    1821.             9.62
##  8     8  231.   38.0       136675    1786.             9.39
##  9     9  182.   29.6       134040    1749.             9.18
## 10    10  180.   29.1       133480    1710.             8.94
## 11    11  157.   24.8       134305    1653.             8.66
## 12    12  169.   27.1       133400    1558.             8.12
vars <- names(data)[4:8]

summary_table <- data %>%
  group_by(month) %>%
  summarise(across(
    all_of(vars),
    list(
      sd = ~sd(.x, na.rm = TRUE)
    ),
    .names = "{.col}"
  ), .groups = "drop")
print("Standard deviation for each variable grouped by month")
## [1] "Standard deviation for each variable grouped by month"
print(summary_table)
## # A tibble: 12 × 6
##    month sales volume median_price listings months_inventory
##    <int> <dbl>  <dbl>        <dbl>    <dbl>            <dbl>
##  1     1  43.4   8.37       25151.     705.             1.97
##  2     2  51.1  10.1        22823.     711.             1.98
##  3     3  59.2  12.0        23442.     727.             2.06
##  4     4  65.4  14.5        21458.     770.             2.24
##  5     5  83.1  19.0        18796.     790.             2.38
##  6     6  95.0  21.1        19231.     812.             2.41
##  7     7  96.3  21.4        21945.     827.             2.50
##  8     8  79.2  18.0        22488.     816.             2.45
##  9     9  72.5  15.2        24344.     803.             2.52
## 10    10  75.0  15.1        26358.     779.             2.44
## 11    11  55.5  11.2        24691.     741.             2.37
## 12    12  60.7  12.6        22810.     693.             2.27

Il maggior numero di vendite è avvenuto nella città di Tyler, che ha registrato anche il maggior valore totale delle vendite nei cinque anni. Tuttavia, Tyler non è la città con il prezzo mediano maggiore, primato che spetta invece a Bryan-College Station. Nonostante queste siano le prime due città sia per vendite, che per valore totale delle vendite, che anche per prezzo mediano, esse presentano tendenze opposte per quanto riguarda il numero di annunci e di mesi richiesti per evaderli tutti. Mentre Tyler presenta i valori massi tra le 4 città, Bryan-College Station presenta i valori minimi.
Questa tendenza invertita è presneta anche guardando l’informazione media per anno, collassando le città. Infatti, mentre le vendite, il valore totale di vendita, e il prezzo mediano sono aumentati negli anni, il numero di annunci attivi e i mesi richiesti per evaderli sono progressivamente diminuiti.
Infne, i mesi estivi sembrano essere quelli in cui il mercato immobiliare presenta un’attività più intensa. Nello specifico, il mese di Giugno è quello che registra il maggior numero di vendite e di valore totale. Un fattore molto interessante è anche che il prezzo mediano di vendita è influenzato dal mese, regitrando anche in questo caso il massimo valore nel mese di Giugno.

  1. Creazione di visualizzazioni con ggplot2
library(ggplot2)

ggplot(data, aes(x = city, y = median_price)) +
  geom_boxplot(fill = "lightblue", color = "darkblue") +
  labs(
    title = "Distribuzione del prezzo mediano per città",
    x = "Città",
    y = "Prezzo mediano"
  ) +
  theme_minimal()

ggplot(data, aes(x = city, y = median_price, fill = factor(year))) +
  geom_boxplot(position = position_dodge(width = 0.8)) +
  labs(
    title = "Prezzo mediano per città e anno",
    x = "Città",
    y = "Prezzo mediano",
    fill = "Anno"
  ) +
  theme_minimal()

Tutte le città hanno mostrato un aumento medio del prezzo mediano negli anni. Tuttavia, mentre la variazione di prezzo a Beaumont e Wichita Falls è stata lieve, le città di Tyler e Bryan-College Station hanno mostrato un aumento del prezzo mediano esponenziale, Bryan-College Station (dove gli immobili hanno un prezzo mediano sistematicamente più alto di tutte le altre città) che ha mostrato un picco nel 2014 con un prezzo mediano pari circa 170 mila dollari in media.

ggplot(data, aes(x = city, y = sales, fill = factor(month))) +
  geom_boxplot(position = position_dodge(width = 0.8)) +
  labs(
    title = "Vendite per città e mese",
    x = "Città",
    y = "Vendite",
    fill = "Mese"
  ) +
  theme_minimal()

Come notato in precedenza, il numero di vendita sembra crescere durante i mesi estivi. Tuttavia c’è da notare come questi picchi siano particolarmente marcati a Bryan-College Station e Tyler. Può essere interessante notare che le vendite a Bryan-College Station nei mesi di Gennaio, Febbraio, e Marzo, sono sovrapponibili a quelle a Beaumont.

data$date <- as.Date(paste(data$year, data$month, "01", sep = "-"), format = "%Y-%m-%d")

ggplot(data, aes(x = date, y = sales, color = city)) +
  geom_line(linewidth = 1) +
  labs(
    title = "Andamento delle vendite nel tempo",
    x = "Data",
    y = "Vendite",
    color = "Città"
  ) +
  theme_minimal()

Anche in questo caso si vedono i cicli annuali delle vendite con i picchi presenti durante i mesi estivi. Si vede anche come Wichita Falls non mostri alcuna tendenza all’aumento delle vendite, al contrario di Beaumon, seppur in misura minore rsipetto a Bryan-College Station e Tyler.

ggplot(data, aes(x = city, y = volume, fill = factor(year))) +
  geom_boxplot(position = position_dodge(width = 0.8)) +
  labs(
    title = "Valore totale delle vendite per città e anno",
    x = "Città",
    y = "Valore totale delle vendite",
    fill = "Anno"
  ) +
  theme_minimal()

Anche considerando il valore totale delle vendite si può notare una crescita esponenziale che caratterizza prevalentemente Bryan-College Station e Tyler. Tuttavia, in questo caso, anche Beaumont mostra un incremento che sembrerebbe esponenziale.

data$month_names <- factor(month, levels = 1:12, labels = month.name, ordered = TRUE)
monthly_totals <- data %>%
  group_by(month_names, city) %>%
  summarise(total_sales = sum(sales), .groups = "drop")

ggplot(monthly_totals, aes(x = month_names, y = total_sales, fill = city)) +
  geom_bar(stat = "identity") +
  labs(
    title = "Totale vendite mensili per città",
    x = "Mese",
    y = "Vendite totali",
    fill = "Città"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

monthly_percentages <- monthly_totals %>%
  group_by(month_names) %>%
  mutate(perc = total_sales / sum(total_sales)) %>%
  ungroup()

ggplot(monthly_percentages, aes(x = month_names, y = perc, fill = city)) +
  geom_bar(stat = "identity") +
  scale_y_continuous(labels = scales::percent) +
  labs(
    title = "Distribuzione percentuale delle vendite per mese e città",
    x = "Mese",
    y = "Percentuale",
    fill = "Città"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

city_year_month <- data %>%
  group_by(city, year, month_names) %>%
  summarise(total_sales = sum(sales), .groups = "drop")

city_year_month$city_year <- paste(city_year_month$city, city_year_month$year, sep = "_")

ggplot(city_year_month, aes(x = month_names, y = total_sales, fill = city)) +
  geom_bar(stat = "identity") +
  facet_grid(rows = vars(year)) +
  labs(
    title = "Distribuzione mensile delle vendite per città (divisa per anno)",
    x = "Mese",
    y = "Vendite totali",
    fill = "Città"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

ggplot(data, aes(x = date, y = months_inventory, color = city)) +
  geom_line(linewidth = 1) +
  labs(
    title = "Numero di annunci attivi nel tempo",
    x = "Data",
    y = "Annunci attivi",
    color = "Città"
  ) +
  theme_minimal()

Il tempo richiesto per vendere tutte le inserzioni mostra una solida tendenza a descrescere in utte le città, tranne a Wichita Falls dove il tempo richiesto era già sistematicamente più basse rispetto a quello delle altre città. Tuttavia, tra il 2013 e il 2014, a Bryan-College Station il tempo richiesto è arrivato ad essere addirittura il minore rispetto alle altre città. A Tyler e Beaumont i tempi erano i maggiori, fino alla fine del 2014 quando sono arrivati ad essere ai livelli di Wichita Falls. Anche in questo caso si possono osservare le oscillazioni all’interno dello stesso anno.

Conclusioni

In generale il mercato immobiliare in Texas sembra essere molto attivo e promettente. Questo aspetto viene evidenziato dalla presenza di tendenze positive per quanto riguarda vendite, ricavi totali, e valore mediano degli immobili. In questo, la città di Bryan-College Station sembra essere quella più promettente, seguita da Tyler e Beaumont. Al contrario, a Wichita Falls sembra che il mercato sia stagnante. Tutti gli indici non mostrano incrementi degni di nota e sono sistematicamente più bassi rispetto a quelli delle altre città.
Il mercato immobilirare si intensifica particolarmente nela tarda primavera e nei mesi estivi. In questi periodi, il numero delle vendite sale, ma anche il valore mediano degli immobili venduti.
Infine, nella maggior parte delle città, alla fine del 2014 sono richiesti mediamente circa 7 mesi per vendere dalla pubblicazione dell’annuncio. L’unica eccezione è Bryan-College Station, dove bastano poco più di 3 mesi per vendere l’immobile. Inoltre, in utti i casi (tra Wichita Falls) il tempo richiesto è in forte diminuzione.