Introduzione

Texas Realty Insights ha raccolto lo storico mensile delle compravendite residenziali in quattro città del Texas. L’obiettivo di questo report è descrivere il mercato con gli strumenti della statistica descrittiva: capire come si distribuiscono vendite, prezzi e annunci, come cambiano tra città, anni e mesi, e ricavarne delle indicazioni operative per le agenzie clienti.

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

dati <- read.csv("realestate_texas.csv")

Esplorazione del dataset

Prima di calcolare qualsiasi indice guardiamo com’è fatto il dataset.

dim(dati)
## [1] 240   8
str(dati)
## '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 ...
head(dati)
##       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
#valori assunti dalle variabili che identificano città e periodo
unique(dati$city)
## [1] "Beaumont"              "Bryan-College Station" "Tyler"                
## [4] "Wichita Falls"
unique(dati$year)
## [1] 2010 2011 2012 2013 2014
unique(dati$month)
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12

Il dataset ha 240 righe e 8 colonne, senza valori mancanti. Ogni riga corrisponde a una città in un certo mese di un certo anno: ci sono 4 città (Beaumont, Bryan-College Station, Tyler e Wichita Falls), 5 anni (dal 2010 al 2014) e 12 mesi, quindi 4 x 5 x 12 = 240 osservazioni. Possiamo notare che R legge year e month come numeri interi, ma in realtà identificano un periodo: di questo teniamo conto nella classificazione.

Classificazione delle variabili

Variabile Tipo Analisi sensata
city qualitativa nominale distribuzione di frequenze, confronti tra città
year temporale (qualitativa ordinale) distribuzione di frequenze, raggruppamenti, serie storiche
month temporale (qualitativa ordinale, ciclica) distribuzione di frequenze, stagionalità
sales quantitativa discreta indici di posizione, variabilità e forma
volume quantitativa continua (milioni di dollari) indici di posizione, variabilità e forma
median_price quantitativa continua (dollari) indici di posizione, variabilità e forma
listings quantitativa discreta indici di posizione, variabilità e forma
months_inventory quantitativa continua (mesi) indici di posizione, variabilità e forma

Le variabili year e month sono scritte come numeri, ma calcolarne la media non avrebbe senso (il “mese medio” 6,5 non dice nulla sul mercato). Le trattiamo quindi come variabili temporali: servono per raggruppare i dati (analisi per anno e per mese) e, combinate tra loro, per costruire una data con cui disegnare le serie storiche. Il mese ha anche una natura ciclica, utile per cercare la stagionalità delle vendite.

#creiamo una variabile data (primo giorno del mese) per le serie storiche
dati$data <- as.Date(paste(dati$year, dati$month, "01", sep="-"))

Distribuzioni di frequenza delle variabili qualitative e temporali

N=dim(dati)[1]

#distribuzione di frequenze delle città
ni <- table(dati$city)
fi <- ni/N
cbind(ni, fi)
##                       ni   fi
## Beaumont              60 0.25
## Bryan-College Station 60 0.25
## Tyler                 60 0.25
## Wichita Falls         60 0.25
#distribuzione di frequenze degli anni
ni <- table(dati$year)
fi <- ni/N
cbind(ni, fi)
##      ni  fi
## 2010 48 0.2
## 2011 48 0.2
## 2012 48 0.2
## 2013 48 0.2
## 2014 48 0.2
#distribuzione di frequenze dei mesi
ni <- table(dati$month)
fi <- ni/N
cbind(ni, fi)
##    ni         fi
## 1  20 0.08333333
## 2  20 0.08333333
## 3  20 0.08333333
## 4  20 0.08333333
## 5  20 0.08333333
## 6  20 0.08333333
## 7  20 0.08333333
## 8  20 0.08333333
## 9  20 0.08333333
## 10 20 0.08333333
## 11 20 0.08333333
## 12 20 0.08333333

Le tre distribuzioni sono perfettamente uniformi: ogni città compare 60 volte (25%), ogni anno 48 volte (20%) e ogni mese 20 volte (8,3%). Il dataset è quindi bilanciato, e questo è importante perché nei confronti tra città o tra periodi nessun gruppo pesa più degli altri.

Indici di posizione, variabilità e forma

Per le cinque variabili quantitative calcoliamo gli indici di posizione (minimo, quartili, mediana, media, massimo), di variabilità (range, differenza interquartile, deviazione standard, coefficiente di variazione) e di forma (asimmetria e curtosi).

#coefficiente di variazione in percentuale
CV <- function(x){
  return( sd(x)/mean(x) * 100 )
}

#funzione che calcola tutti gli indici per una variabile
indici <- function(x){
  return( c(minimo = min(x),
            Q1 = unname(quantile(x, 0.25)),
            mediana = median(x),
            media = mean(x),
            Q3 = unname(quantile(x, 0.75)),
            massimo = max(x),
            range = max(x) - min(x),
            IQR = IQR(x),
            dev_std = sd(x),
            CV = CV(x),
            asimmetria = skewness(x),
            curtosi = kurtosis(x) - 3) )
}

tabella_indici <- cbind(sales = indici(dati$sales),
                        volume = indici(dati$volume),
                        median_price = indici(dati$median_price),
                        listings = indici(dati$listings),
                        months_inventory = indici(dati$months_inventory))

round(tabella_indici, 2)
##             sales volume median_price listings months_inventory
## minimo      79.00   8.17     73800.00   743.00             3.40
## Q1         127.00  17.66    117300.00  1026.50             7.80
## mediana    175.50  27.06    134500.00  1618.50             8.95
## media      192.29  31.01    132665.42  1738.02             9.19
## Q3         247.00  40.89    150050.00  2056.00            10.95
## massimo    423.00  83.55    180000.00  3296.00            14.90
## range      344.00  75.38    106200.00  2553.00            11.50
## IQR        120.00  23.23     32750.00  1029.50             3.15
## dev_std     79.65  16.65     22662.15   752.71             2.30
## CV          41.42  53.71        17.08    43.31            25.06
## asimmetria   0.72   0.88        -0.36     0.65             0.04
## curtosi     -0.31   0.18        -0.62    -0.79            -0.17
#istogrammi delle variabili quantitative
par(mfrow = c(2, 3))
hist(dati$sales, main = "sales", xlab = "Numero di vendite", ylab = "Frequenze assolute", col = "lightblue")
hist(dati$volume, main = "volume", xlab = "Milioni di dollari", ylab = "Frequenze assolute", col = "lightblue")
hist(dati$median_price, main = "median_price", xlab = "Dollari", ylab = "Frequenze assolute", col = "lightblue")
hist(dati$listings, main = "listings", xlab = "Annunci attivi", ylab = "Frequenze assolute", col = "lightblue")
hist(dati$months_inventory, main = "months_inventory", xlab = "Mesi", ylab = "Frequenze assolute", col = "lightblue")

Commento

  • sales: in un mese una città registra in media 192 vendite, ma la mediana è più bassa (175,5) e la metà centrale dei dati va da 127 a 247 vendite. Il fatto che la media sia più alta della mediana, insieme all’asimmetria positiva (0,72), indica una coda verso destra: ci sono mesi con molte più vendite del solito (fino a 423).
  • volume: il valore delle vendite mensili va da 8 a 84 milioni di dollari, con media 31 e mediana 27 milioni. È la variabile con la coda destra più marcata (asimmetria 0,88): pochi mesi molto ricchi, concentrati nelle città più grandi, alzano la media.
  • median_price: il prezzo mediano va da 73.800 a 180.000 dollari, con media e mediana molto vicine (132.665 e 134.500). L’asimmetria è leggermente negativa (-0,36): ci sono alcuni valori bassi (le città più economiche) che allungano la coda sinistra.
  • listings: gli annunci attivi vanno da 743 a 3.296, con media 1.738. Anche qui la coda è verso destra (asimmetria 0,65) e la curtosi negativa (-0,79) indica una distribuzione piatta: l’istogramma mostra più gruppi di valori, che corrispondono alle diverse dimensioni delle città.
  • months_inventory: servono in media circa 9 mesi per smaltire gli annunci attivi, con valori da 3,4 a 14,9. È la variabile più simmetrica (asimmetria 0,04) e ha una curtosi vicina a zero, quindi una forma simile a quella di una normale.

Tutte le curtosi sono vicine a zero o negative: nessuna variabile ha code particolarmente pesanti, cioè non ci sono valori estremi isolati ma piuttosto distribuzioni “larghe”, che mescolano città con dimensioni di mercato molto diverse.

Variabilità e asimmetria a confronto

Per capire quale variabile è più variabile non possiamo confrontare le deviazioni standard, perché dipendono dall’unità di misura: la deviazione standard del prezzo (22.662 dollari) è molto più grande di quella delle vendite (79,7) solo perché i prezzi sono espressi in dollari. Usiamo quindi il coefficiente di variazione, che rapporta la deviazione standard alla media ed è un numero puro, confrontabile tra variabili diverse. Per l’asimmetria usiamo l’indice di asimmetria di Fisher, che è già adimensionale.

round(tabella_indici[c("CV", "asimmetria"), ], 3)
##             sales volume median_price listings months_inventory
## CV         41.422 53.705       17.082   43.308           25.060
## asimmetria  0.718  0.885       -0.365    0.649            0.041

La variabile con la maggiore variabilità è volume, con un coefficiente di variazione del 53,7%: il valore totale delle vendite cambia moltissimo tra una città e l’altra e tra un periodo e l’altro, perché combina due fattori che variano entrambi (numero di vendite e prezzo). Seguono listings (43,3%) e sales (41,4%), mentre median_price è la più stabile (17,1%).

La variabile con la distribuzione più asimmetrica è ancora volume (asimmetria 0,885, in valore assoluto la più alta), con una coda verso destra: la maggior parte dei mesi ha un volume moderato, mentre pochi mesi di città grandi raggiungono valori molto alti. months_inventory è invece praticamente simmetrica (0,041).

Distribuzione in classi del prezzo mediano

Suddividiamo median_price in classi di ampiezza costante pari a 20.000 dollari, da 70.000 a 190.000 dollari: in questo modo si ottengono 6 classi che coprono tutti i valori osservati (minimo 73.800, massimo 180.000) e corrispondono a fasce di prezzo facili da leggere per chi lavora in agenzia.

#suddivisione in classi
prezzo_cl <- cut(dati$median_price,
                 breaks = seq(70000, 190000, 20000),
                 dig.lab = 6)

ni <- table(prezzo_cl)
fi <- ni/N
Ni <- cumsum(ni)
Fi <- Ni/N

distr_freq_prezzo <- as.data.frame(cbind(ni, fi, Ni, Fi))
distr_freq_prezzo
##                 ni         fi  Ni         Fi
## (70000,90000]   11 0.04583333  11 0.04583333
## (90000,110000]  38 0.15833333  49 0.20416667
## (110000,130000] 46 0.19166667  95 0.39583333
## (130000,150000] 85 0.35416667 180 0.75000000
## (150000,170000] 54 0.22500000 234 0.97500000
## (170000,190000]  6 0.02500000 240 1.00000000
distr_freq_prezzo$classe <- factor(rownames(distr_freq_prezzo), levels = rownames(distr_freq_prezzo))

ggplot(data = distr_freq_prezzo)+
  geom_col(aes(x = classe, y = ni), fill = "steelblue", col = "black")+
  labs(x = "Classi di prezzo mediano ($)",
       y = "Frequenze assolute",
       title = "Distribuzione del prezzo mediano in classi")+
  theme_bw()

Usiamo geom_col() perché la tabella contiene già le frequenze calcolate: geom_bar() conterebbe di nuovo le righe e darebbe un grafico sbagliato.

#indice di eterogeneità di Gini normalizzato
gini.index <- function(x){
  ni = table(x)
  fi = ni/length(x)
  fi2 = fi^2
  J = length(table(x))

  gini = 1-sum(fi2)
  gini.norm = gini/((J-1)/J)

  return(gini.norm)
}

gini.index(prezzo_cl)
## [1] 0.9112917

La classe più frequente è quella tra 130.000 e 150.000 dollari, che raccoglie il 35% dei mesi osservati; il 75% delle osservazioni ha un prezzo mediano fino a 150.000 dollari e solo il 2,5% supera i 170.000.

L’indice di Gini normalizzato vale 0,91, un valore vicino a 1: i prezzi mediani non sono concentrati in un’unica fascia ma sono distribuiti su quasi tutte le classi. Questo è coerente con la presenza di quattro mercati molto diversi tra loro: come vedremo, Wichita Falls si colloca nelle fasce più basse e Bryan-College Station in quelle più alte.

Calcolo delle probabilità

Le probabilità richieste sono frequentiste: si contano le righe che soddisfano la condizione e si dividono per il numero totale di righe (240).

#probabilità che una riga riporti la città Beaumont
p_beaumont <- sum(dati$city == "Beaumont") / N

#probabilità che una riga riporti il mese di luglio
p_luglio <- sum(dati$month == 7) / N

#probabilità che una riga riporti dicembre 2012 (condizione congiunta su anno e mese)
p_dicembre_2012 <- sum(dati$year == 2012 & dati$month == 12) / N

c(Beaumont = p_beaumont, Luglio = p_luglio, Dicembre_2012 = p_dicembre_2012)
##      Beaumont        Luglio Dicembre_2012 
##    0.25000000    0.08333333    0.01666667
  • Beaumont: 60 righe su 240, quindi la probabilità è 0,25 (25%), come per ogni città, dato che il dataset è bilanciato.
  • Luglio: ogni mese compare una volta per città e per anno, quindi 4 x 5 = 20 righe su 240: la probabilità è 1/12, circa 0,083 (8,3%).
  • Dicembre 2012: la condizione riguarda due colonne insieme. Le righe che la soddisfano sono 4, una per città, quindi la probabilità è 4/240 = 1/60, circa 0,017 (1,7%). È pari al prodotto delle probabilità dell’anno 2012 (1/5) e del mese di dicembre (1/12), perché nel dataset anno e mese sono combinati in modo completo e regolare.

Nuove variabili

Prezzo medio degli immobili. Il volume è il valore totale delle vendite in milioni di dollari, quindi dividendolo per il numero di vendite si ottiene il prezzo medio di un immobile venduto in quel mese:

prezzo medio = volume x 1.000.000 / sales

Efficacia degli annunci. Per misurare quanto funzionano gli annunci rapportiamo le vendite del mese agli annunci attivi: è la percentuale di annunci che nel mese si sono trasformati in una vendita.

efficacia annunci (%) = sales / listings x 100

Un valore alto significa che una parte consistente degli immobili in vendita trova un acquirente in poco tempo; un valore basso indica tanti annunci fermi rispetto alle vendite. È un indicatore facile da leggere in agenzia ed è legato a months_inventory, che misura la stessa cosa al contrario (quanti mesi servirebbero per vendere tutto).

dati$prezzo_medio <- dati$volume * 1000000 / dati$sales
dati$efficacia_annunci <- dati$sales / dati$listings * 100

summary(dati$prezzo_medio)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   97010  132939  156588  154320  173915  213234
summary(dati$efficacia_annunci)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   5.014   8.980  10.963  11.874  13.492  38.713
#confronto tra prezzo medio e prezzo mediano per città
dati %>%
  group_by(city) %>%
  summarise(prezzo_medio = mean(prezzo_medio),
            prezzo_mediano = mean(median_price))
## # A tibble: 4 × 3
##   city                  prezzo_medio prezzo_mediano
##   <chr>                        <dbl>          <dbl>
## 1 Beaumont                   146640.        129988.
## 2 Bryan-College Station      183534.        157488.
## 3 Tyler                      167677.        141442.
## 4 Wichita Falls              119430.        101743.
#mesi con l'efficacia più alta e più bassa
head(dati[order(-dati$efficacia_annunci), c("city", "year", "month", "sales", "listings", "efficacia_annunci")], 3)
##                      city year month sales listings efficacia_annunci
## 115 Bryan-College Station 2014     7   403     1041          38.71278
## 114 Bryan-College Station 2014     6   377     1152          32.72569
## 116 Bryan-College Station 2014     8   298     1016          29.33071
head(dati[order(dati$efficacia_annunci), c("city", "year", "month", "sales", "listings", "efficacia_annunci")], 3)
##         city year month sales listings efficacia_annunci
## 133    Tyler 2011     1   143     2852          5.014025
## 131    Tyler 2010    11   155     3042          5.095332
## 1   Beaumont 2010     1    83     1533          5.414220

Il prezzo medio va da circa 97.000 a 213.000 dollari, con una media di 154.320. Possiamo notare che in tutte le città il prezzo medio è più alto del prezzo mediano (per esempio 183.534 contro 157.488 a Bryan-College Station): significa che, all’interno di ogni mese, la distribuzione dei prezzi di vendita ha una coda verso destra, cioè alcuni immobili molto costosi alzano la media. Per le agenzie il prezzo mediano è quindi il riferimento più affidabile del “prezzo tipico”.

L’efficacia degli annunci è in media dell’11,9%: in un mese tipico circa un annuncio su otto si trasforma in una vendita. I valori vanno dal 5% (Tyler a gennaio 2011) al 38,7% (Bryan-College Station a luglio 2014): i mesi più efficaci sono tutti estivi e tutti a Bryan-College Station negli ultimi anni.

Analisi condizionate

Per città

per_citta <- dati %>%
  group_by(city) %>%
  summarise(media_vendite = round(mean(sales), 1),
            devst_vendite = round(sd(sales), 1),
            media_prezzo = round(mean(median_price)),
            devst_prezzo = round(sd(median_price)),
            media_volume = round(mean(volume), 1),
            devst_volume = round(sd(volume), 1),
            media_efficacia = round(mean(efficacia_annunci), 1),
            devst_efficacia = round(sd(efficacia_annunci), 1))

as.data.frame(per_citta)
##                    city media_vendite devst_vendite media_prezzo devst_prezzo
## 1              Beaumont         177.4          41.5       129988        10105
## 2 Bryan-College Station         206.0          85.0       157488         8852
## 3                 Tyler         269.8          62.0       141442         9337
## 4         Wichita Falls         116.1          22.2       101743        11320
##   media_volume devst_volume media_efficacia devst_efficacia
## 1         26.1          7.0            10.6             2.7
## 2         38.2         17.2            14.7             7.3
## 3         45.8         13.1             9.3             2.3
## 4         13.9          3.2            12.8             2.5
ggplot(per_citta)+theme_bw()+
  geom_col(aes(x = city, y = media_vendite), fill = "steelblue")+
  geom_errorbar(aes(x = city,
                    ymin = media_vendite - devst_vendite,
                    ymax = media_vendite + devst_vendite),
                width = 0.3, col = 2)+
  labs(x = "Città",
       y = "Vendite mensili (media ± dev. std)",
       title = "Vendite medie mensili per città")

ggplot(per_citta)+theme_bw()+
  geom_col(aes(x = city, y = media_efficacia), fill = "darkgreen")+
  geom_errorbar(aes(x = city,
                    ymin = media_efficacia - devst_efficacia,
                    ymax = media_efficacia + devst_efficacia),
                width = 0.3, col = 2)+
  labs(x = "Città",
       y = "Efficacia degli annunci, % (media ± dev. std)",
       title = "Efficacia media degli annunci per città")

Le quattro città sono mercati molto diversi:

  • Tyler è il mercato più grande: 270 vendite al mese e 45,8 milioni di dollari di volume in media, ma ha anche moltissimi annunci attivi e quindi l’efficacia più bassa (9,3%).
  • Bryan-College Station ha i prezzi più alti (prezzo mediano medio di circa 157.500 dollari) e l’efficacia degli annunci migliore (14,7%), ma con una deviazione standard alta: l’efficacia è cambiata molto nel tempo, come vedremo nelle serie storiche.
  • Beaumont è una città intermedia per vendite (177 al mese) e prezzi (circa 130.000 dollari), con un’efficacia del 10,6%.
  • Wichita Falls è il mercato più piccolo e più economico (116 vendite al mese, prezzo mediano di circa 101.700 dollari), ma con un’efficacia degli annunci buona (12,8%), perché ha pochi annunci rispetto alle vendite.

Per anno

per_anno <- dati %>%
  group_by(year) %>%
  summarise(media_vendite = round(mean(sales), 1),
            devst_vendite = round(sd(sales), 1),
            media_prezzo = round(mean(median_price)),
            devst_prezzo = round(sd(median_price)),
            media_annunci = round(mean(listings), 1),
            media_efficacia = round(mean(efficacia_annunci), 1),
            devst_efficacia = round(sd(efficacia_annunci), 1))

as.data.frame(per_anno)
##   year media_vendite devst_vendite media_prezzo devst_prezzo media_annunci
## 1 2010         168.7          60.5       130192        21822        1826.0
## 2 2011         164.1          63.9       127854        21318        1849.6
## 3 2012         186.1          70.9       130077        21432        1776.8
## 4 2013         211.9          84.0       135723        21708        1677.6
## 5 2014         230.6          95.5       139481        25625        1560.0
##   media_efficacia devst_efficacia
## 1            10.0             3.4
## 2             9.3             2.3
## 3            11.0             2.8
## 4            13.5             4.5
## 5            15.7             6.2
ggplot(per_anno)+theme_bw()+
  geom_line(aes(x = year, y = media_vendite), col = "steelblue", lwd = 1)+
  geom_point(aes(x = year, y = media_vendite), col = "steelblue", size = 3)+
  geom_errorbar(aes(x = year,
                    ymin = media_vendite - devst_vendite,
                    ymax = media_vendite + devst_vendite),
                width = 0.2, col = 2)+
  labs(x = "Anno",
       y = "Vendite mensili (media ± dev. std)",
       title = "Vendite medie mensili per anno")

Dal 2011 il mercato è in crescita costante: le vendite medie mensili passano da 164 nel 2011 a 231 nel 2014 (circa +40%), il prezzo mediano sale da circa 127.900 a 139.500 dollari e gli annunci attivi diminuiscono (da circa 1.850 a 1.560). Di conseguenza l’efficacia degli annunci migliora ogni anno, dal 9,3% del 2011 al 15,7% del 2014. Le barre di errore sono ampie perché all’interno di ogni anno ci sono città molto diverse tra loro.

Per mese

per_mese <- dati %>%
  group_by(month) %>%
  summarise(media_vendite = round(mean(sales), 1),
            devst_vendite = round(sd(sales), 1),
            media_prezzo = round(mean(median_price)),
            devst_prezzo = round(sd(median_price)),
            media_efficacia = round(mean(efficacia_annunci), 1),
            devst_efficacia = round(sd(efficacia_annunci), 1))

as.data.frame(per_mese)
##    month media_vendite devst_vendite media_prezzo devst_prezzo media_efficacia
## 1      1         127.4          43.4       124250        25151             8.3
## 2      2         140.8          51.1       130075        22823             8.8
## 3      3         189.4          59.2       127415        23442            11.6
## 4      4         211.7          65.4       131490        21458            12.5
## 5      5         238.8          83.1       134485        18796            14.1
## 6      6         243.6          95.0       137620        19231            14.2
## 7      7         235.8          96.3       134750        21945            14.3
## 8      8         231.4          79.2       136675        22488            14.2
## 9      9         182.3          72.5       134040        24344            11.2
## 10    10         179.9          75.0       133480        26358            11.2
## 11    11         156.8          55.5       134305        24691            10.2
## 12    12         169.4          60.7       133400        22810            11.7
##    devst_efficacia
## 1              2.3
## 2              2.2
## 3              3.5
## 4              3.8
## 5              5.0
## 6              5.8
## 7              7.4
## 8              5.3
## 9              3.5
## 10             3.6
## 11             2.9
## 12             3.8
ggplot(per_mese)+theme_bw()+
  geom_col(aes(x = factor(month), y = media_vendite), fill = "steelblue")+
  geom_errorbar(aes(x = factor(month),
                    ymin = media_vendite - devst_vendite,
                    ymax = media_vendite + devst_vendite),
                width = 0.3, col = 2)+
  labs(x = "Mese",
       y = "Vendite mensili (media ± dev. std)",
       title = "Vendite medie per mese")

Le vendite hanno una stagionalità molto chiara: sono basse a gennaio e febbraio (127 e 141 vendite in media), crescono in primavera e raggiungono il massimo tra maggio e agosto (oltre 230 vendite, con il picco di giugno a 244), per poi scendere in autunno. Anche l’efficacia degli annunci segue lo stesso andamento: supera il 14% da maggio ad agosto, contro l’8-9% di gennaio e febbraio. Il prezzo mediano invece varia poco durante l’anno.

Visualizzazioni

Prezzo mediano per città

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

Il boxplot conferma che le città si differenziano soprattutto per il livello dei prezzi: Bryan-College Station ha la distribuzione più alta (mediana intorno a 155.000 dollari), Wichita Falls la più bassa (intorno a 102.000), con Tyler e Beaumont in mezzo. Le distribuzioni di Bryan-College Station e Wichita Falls non si sovrappongono per niente: si tratta di due mercati con fasce di prezzo completamente diverse. Wichita Falls ha anche la scatola più ampia, quindi i prezzi più variabili da un mese all’altro, mentre Beaumont ha un valore anomalo in alto (163.800 dollari a gennaio 2010).

Volume delle vendite tra città e anni

ggplot(data = dati)+
  geom_boxplot(aes(x = city, y = volume, fill = factor(year)))+
  labs(x = "Città",
       y = "Volume delle vendite (milioni di $)",
       fill = "Anno",
       title = "Distribuzione del volume delle vendite per città e anno")+
  theme_bw()

Il volume cresce negli anni in tre città su quattro: a Tyler e a Bryan-College Station i box del 2014 sono nettamente più alti di quelli del 2010-2011, e lo stesso vale, in misura minore, per Beaumont. Wichita Falls invece rimane stabile intorno ai 14 milioni al mese. Bryan-College Station ha anche box molto allungati, segno di una forte differenza tra i mesi estivi e quelli invernali.

Vendite mensili per città: barre sovrapposte

vendite_mese_citta <- dati %>%
  group_by(month, city) %>%
  summarise(vendite = sum(sales))

ggplot(data = vendite_mese_citta)+
  geom_col(aes(x = factor(month), y = vendite, fill = city), position = "stack", col = "black")+
  labs(x = "Mese",
       y = "Totale vendite (2010-2014)",
       fill = "Città",
       title = "Totale vendite per mese e città")+
  theme_bw()

ggplot(data = vendite_mese_citta)+
  geom_col(aes(x = factor(month), y = vendite, fill = city), position = "fill", col = "black")+
  labs(x = "Mese",
       y = "Quota delle vendite (da 0 a 1)",
       fill = "Città",
       title = "Composizione delle vendite mensili per città (normalizzato)")+
  theme_bw()

Il primo grafico mostra il totale delle vendite di ogni mese nei cinque anni: si vede bene il picco estivo, che riguarda tutte le città. Il grafico normalizzato mostra invece la quota di ogni città sul totale del mese: Tyler pesa sempre circa un terzo delle vendite, Wichita Falls circa il 15%. Le quote cambiano poco durante l’anno, con una sola eccezione: Bryan-College Station passa dal 22-23% delle vendite nei mesi invernali a quasi un terzo tra maggio e luglio, quindi è la città con la stagionalità più forte.

Per inserire l’informazione sull’anno nello stesso blocco grafico usiamo un pannello per ogni anno (facet_wrap): ogni riga di pannelli mostra le vendite mensili di un anno, divise per città.

ggplot(data = dati)+
  geom_col(aes(x = factor(month), y = sales, fill = city), position = "stack")+
  facet_wrap(~year, ncol = 1)+
  labs(x = "Mese",
       y = "Vendite",
       fill = "Città",
       title = "Vendite mensili per città, anno per anno")+
  theme_bw()+
  theme(legend.position = "bottom")

Con un pannello per anno si vede che la stagionalità si ripete ogni anno con la stessa forma, ma che le barre diventano più alte dal 2012 in poi: il picco estivo del 2014 supera di molto quello del 2010 e del 2011.

Confronto storico tra città

ggplot(data = dati)+
  geom_line(aes(x = data, y = median_price, col = city), lwd = 0.8)+
  labs(x = "Data",
       y = "Prezzo mediano ($)",
       col = "Città",
       title = "Andamento del prezzo mediano nel tempo")+
  theme_bw()

Per costruire il line chart usiamo la variabile data, creata unendo anno e mese: se mettessimo sull’asse x solo il mese, R collegherebbe i punti dei diversi anni in un’unica linea a zig-zag, illeggibile. Il grafico mostra che Bryan-College Station è quasi sempre la città più cara e Wichita Falls la più economica, con prezzi che oscillano molto da un mese all’altro. Dal 2013 i prezzi salgono sopratutto a Bryan-College Station e a Tyler.

efficacia_anno_citta <- dati %>%
  group_by(city, year) %>%
  summarise(efficacia = mean(efficacia_annunci))

ggplot(data = efficacia_anno_citta)+
  geom_line(aes(x = year, y = efficacia, col = city), lwd = 1)+
  geom_point(aes(x = year, y = efficacia, col = city), size = 2)+
  labs(x = "Anno",
       y = "Efficacia degli annunci (%)",
       col = "Città",
       title = "Efficacia media degli annunci per città e anno")+
  theme_bw()

L’efficacia degli annunci migliora in tutte le città dal 2011 in poi, ma con velocità molto diverse. A Bryan-College Station passa dal 10,6% del 2010 al 23,6% del 2014: quasi un annuncio su quattro viene venduto ogni mese. Tyler e Beaumont migliorano in modo costante (fino al 12,4% e al 13,5%), mentre Wichita Falls oscilla tra l’11% e il 14% senza una vera tendenza.

Conclusioni

L’analisi descrive un mercato immobiliare in crescita tra il 2010 e il 2014, con quattro città molto diverse per dimensione e livello dei prezzi e una forte stagionalità comune.

Tendenze principali

  • Le vendite crescono dal 2011 in poi (+41% di vendite medie mensili tra il 2011 e il 2014), i prezzi aumentano e gli annunci attivi diminuiscono: gli immobili si vendono più in fretta e l’efficacia degli annunci migliora ogni anno.
  • Le vendite si concentrano tra maggio e agosto, mentre gennaio e febbraio sono i mesi più deboli.
  • volume è la variabile più variabile e più asimmetrica, perché somma le differenze di dimensione e di prezzo tra le città; il prezzo mediano è invece la grandezza più stabile.

Sulla base dell’analisi effettuata, proponiamo le seguenti raccomandazioni per le agenzie clienti:

  • Bryan-College Station è la città con i maggiori margini di crescita: vendite totali passate da circa 2.000 a oltre 3.100 all’anno, prezzi più alti e in aumento, efficacia degli annunci salita fino al 23,6% e magazzino ridotto a poco più di 4 mesi nel 2014. Conviene aumentare il numero di immobili in portafoglio, perché la domanda assorbe rapidamente l’offerta.
  • Tyler è il mercato più grande ma con molti annunci fermi: l’efficacia è la più bassa delle quattro città. Qui la priorità non è aumentare gli annunci ma migliorarne la qualità e i prezzi di listino, per ridurre i tempi di vendita.
  • Wichita Falls è un mercato stabile e piccolo, con prezzi bassi ma annunci efficaci: è adatto a una presenza di mantenimento più che a investimenti di espansione.
  • Concentrare gli sforzi commerciali tra marzo e agosto: in questi mesi le vendite e l’efficacia degli annunci sono più alte, quindi è il momento migliore per pubblicare nuovi annunci e investire in promozione. I mesi invernali possono essere usati per acquisire nuovi immobili e preparare il portafoglio per la primavera.
  • Usare il prezzo mediano come riferimento per i listini: il prezzo medio è sempre più alto del mediano, perché pochi immobili costosi alzano la media, quindi rappresenta peggio il prezzo tipico di una zona.
  • Monitorare l’efficacia degli annunci mese per mese: è un indicatore semplice (vendite / annunci attivi) che permette di accorgersi subito di un mercato che rallenta o accelera.