Analisi del Mercato Immobiliare del Texas

df <- read.csv("realestate_texas.csv")
attach(df)

1. Analisi delle variabili

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 ...

Il dataset é costitutio da 8 variabili statistiche, e 240 osservazioni:

  • 1 variabile (city) qualitativa su scala nominale

  • 7 variabili quantitative:

    • year -> discreta su scala di intervalli

    • month -> discreta su scala di intervalli (in origine qualitativa ordinale)

    • sales -> discreta su scala di rapporti

    • volume -> continua su scala di rapporti

    • median_price -> continua su scala di rapporti

    • listings -> discreta su scala di rapporti

    • months_inventory -> continua su scala di rapporti

Sono presenti variabili con riferimento temporale. Queste possono essere incrociate con le altre variabili per poter studiare le serie storiche e valutare/confrontare i trend pregressi. Inoltre, può risultare opportuno creare una nuova variabile che concateni year e month per manipolare l’intervallo temporale con granularità mensile.

In primis, tutte le variabili (eccetto quelle qualitative “grezze”) posso essere sintetizzate e analizzate con l’ausilio degli indici di posizione, in modo da osservarne le caratteristiche quantitative principali del dataset, quindi del mercato in toto. Le analisi di variabilità e forma permetteranno di avere maggior dettaglio su come si distribuiscono i dati, quindi come si comportana il mercato nel corso del tempo.

Rispetto agli obiettivi iniziali, la dimensione tempo permette di analizzare con chiarezza la variazione nel tempo delle vendite (sales), del valore delle vendite (volume) e del prezzo mediano di vendita (median_price), confrondamibili tra le varie città (city) su base annuale. In prima battuta, dalle analisi di questo genere possono emergere dei delta Year-over-Year interessanti, che possono essere esplosi con granularità mensile per insights di dettaglio (e.g. picchi dei mesi specifici dell’anno con maggiore incidenza delle vendite mensili sulle vendite totali dell’anno).

Può essere utile analizzare la ripartizione annua del numero delle vendite e del valore totale delle vendite sulla base delle città, in modo da capirne la performance, quindi quanto incidono queste varibili della singola città sul totale annuo. Ragionamento analogo può essere fatto sul totale di queste varibaili, senza esplodere i dati anno per anno.

Le variabili listings e months_inventory, in relazione con altri dati, sono la base per poter valutare l’efficacia intrinseca degli annunci di vendita. La costruzione di KPIs opportuni potranno mettere in relazione le vendite e le inserzioni pubblicitarie, per individuare casistiche di successo o fallimento, propedeutiche anche alla valutazione delle strategie passate e future.

2. Indici di posizione, variabilità e forma

# summary(df[c("sales", "volume","median_price","listings","months_inventory")])
df_var <- c("sales", "volume","median_price","listings","months_inventory")


# Tabella indici di posizione
loc_index_table <- lapply(df[df_var], function(x) {
  c(
    Min = min(x),
    Q1 = round(as.numeric(quantile(x, 0.25),1)),
    Mediana = round(median(x),1),
    Media = round(mean(x),1),
    Q3 = round(as.numeric(quantile(x, 0.75)),1),
    Max = max(x)
  )
}
)

loc_index_table <- as.data.frame(loc_index_table)
kable(loc_index_table, caption = "Indici di posizione")
Indici di posizione
sales volume median_price listings months_inventory
Min 79.0 8.166 73800.0 743.0 3.4
Q1 127.0 18.000 117300.0 1026.0 8.0
Mediana 175.5 27.100 134500.0 1618.5 8.9
Media 192.3 31.000 132665.4 1738.0 9.2
Q3 247.0 40.900 150050.0 2056.0 11.0
Max 423.0 83.547 180000.0 3296.0 14.9

Nel periodo di riferimento, in media si registrano 192 vendite mensili, per un valore di 31 mln di dollari, con un prezzo mediano di 132.655 dollari.

Mediamente sono necessari circa 10 mesi per vendere tutte le inserzioni. Mediamente le inserzioni mensili attive sono attorno a 1.738 annunci.

Il record storico del valore derivante dalle vendite mensili ha portato 83 mln di dollari, massimo registrato nel periodo. In termini di quantità di vendite effettuate in un mese, il mese con la domanda più attiva ha portato 423 vendite.

Nel periodo in esame, per la maggior parte il prezzo mediano degli immobili non supera i 150.050 dollari.

# Tabella indici di variabilità
disp_index_table <- lapply(df[df_var], function(x) {
  c(
  Range = round(max(x)-min(x),2),
  IQR = round(as.numeric(quantile(x,0.75) - quantile(x, 0.25)),2),
  Varianza = round(var(x),2),
  Deviazione_std = round(sd(x),2),
  CV = round((sd(x)/mean(x))*100,2)
  )
}
)

disp_index_table <- as.data.frame(disp_index_table)

kable(disp_index_table, caption = "Indici di variabilità")
Indici di variabilità
sales volume median_price listings months_inventory
Range 344.00 75.38 106200.00 2553.00 11.50
IQR 120.00 23.23 32750.00 1029.50 3.15
Varianza 6344.30 277.27 513572983.09 566568.97 5.31
Deviazione_std 79.65 16.65 22662.15 752.71 2.30
CV 41.42 53.71 17.08 43.31 25.06

Le quantità vendute, il valore totale delle vendite e il numero totale di annunci attivi, sono caratterizzate da una variabilità sufficientemente elevata rispetto all media. Limitata, invece, la variabilità del prezzo mediano e tempo necessario di esaurimento delle inserzioni pubblicitarie.

Per la natura della variabile nel contesto del mercato immobiliare, é fisiologico che il valore totale delle vendite sia quello con la maggiore dispersione, con alti e bassi molto variabili a seconda della performance mensile registrata.

shape_index_table <- lapply(df[df_var], function(x) {
  c(
  Asimmetria = round(skewness(x),2),
  Curtosi = round(kurtosis(x)-3,2)
  )
}
)

shape_index_table <- as.data.frame(shape_index_table)

kable(shape_index_table, caption = "Indici di forma")
Indici di forma
sales volume median_price listings months_inventory
Asimmetria 0.72 0.88 -0.36 0.65 0.04
Curtosi -0.31 0.18 -0.62 -0.79 -0.17

Months inventory é l’unica variabile quasi perfettamente simmetrica, con media, mediana e moda in prossimità dello stesso valore. L’assimmetria é positiva per tutte le variabili, tranne median price, che é caratterizzata dalla mediana minore della moda.

Volume, invce, deiversamente dalle altre variabili, tende ad avere frequenze elevate di valori più bassi, tende ad avere la forma quasi “normale”. Inoltre, vi é la presenza di code più pesanti della distribuzione, quindi valori particolarmente alti (outlier) che influenzano la variabilità e la media.

freq_table_city <- data.frame(
  city = names(table(city)),
  ni   = as.vector(table(city)),
  fi   = as.vector(table(city))/length(city),
  Ni   = as.vector(cumsum(table(city))),
  Fi   = as.vector(cumsum(table(city))/length(city))
)

gini.index <- function(x){
  ni = table(x)
  fi = ni/length(x)
  fi2=fi^2
  J = length(table(x))
  
  gini = 1 - sum(fi2)
  gini.normalizzato = gini/((J-1)/J)
  return(gini.normalizzato)
}

gini.index(city)
## [1] 1
kable(freq_table_city, caption = "Distribuzione di frequeza")
Distribuzione di frequeza
city ni fi Ni Fi
Beaumont 60 0.25 60 0.25
Bryan-College Station 60 0.25 120 0.50
Tyler 60 0.25 180 0.75
Wichita Falls 60 0.25 240 1.00

La variabile qualitativa city é quadrimodale, ed é caratterizzata da eterogeneità massima, in quanto tutte le modalità si presentano con la stessa frequenza. Visto che non si sono verificati mesi con vendite pari a 0, per tutte e 4 le città non ci sono stati stop delle vendite del periodo 2010-2014.

3. Identificazione delle variabili con maggiore variabilità e asimmetria

Valutando i dati forniti, risulta che che la variabile volume é quellla caratterizzate dalla maggiore variabilità dei dati. A testimoniare tale caratteristica é il valore più alto del Coefficiente di Variazione, pari a 53,71. Il valore totale delle vendite, quindi, é il dato che si discosta maggiormente rispetto alla propria media, assumendo sia valori molto alti, che valori molto bassi. E’ segno che il valore totale delle vendite può variare molto, a seconda del contesto di mercato.

Nel caso in esame, volume é anche la più asimmterica in termini assoluti (indice di asimmetria 0,88). In particolare, si intuisce un’asimmetria positiva, quindi la performance del business sul mercato é caratterizzate da valori totali delle vendite mensili tendenzialmente più bassi, ma con pesenti anche periodi molto proficui.

4. Creazione di classi per una variabile quantitativa

Mantenendo il focus sulla varibaile volume, é oppurtuna una divisione in classi per una rappresentazione più sintetica dei dati.

df$cl_volume <- cut(volume,
                 breaks = c(5,25,45,65,75,95))

attach(df)
## The following objects are masked from df (pos = 3):
## 
##     city, listings, median_price, month, months_inventory, sales,
##     volume, year
freq_table_cl_volume <- data.frame(
  Classe_ValoreTotVendite= names(table(cl_volume)),
  ni   = as.vector(table(cl_volume)),
  fi   = as.vector(round(table(cl_volume)/length(cl_volume),2)),
  Ni   = as.vector(cumsum(table(cl_volume))),
  Fi   = as.vector(round((cumsum(table(cl_volume))/length(cl_volume)),2))
)

gini.index <- function(x){
  ni = table(x)
  fi = ni/length(x)
  fi2=fi^2
  J = length(table(x))
  
  gini = 1 - sum(fi2)
  gini.normalizzato = gini/((J-1)/J)
  return(gini.normalizzato)
}


kable(freq_table_cl_volume, caption = "Distribuzione di frequeze per classi di volume delle vendite (mln di $)")
Distribuzione di frequeze per classi di volume delle vendite (mln di $)
Classe_ValoreTotVendite ni fi Ni Fi
(5,25] 104 0.43 104 0.43
(25,45] 87 0.36 191 0.80
(45,65] 37 0.15 228 0.95
(65,75] 8 0.03 236 0.98
(75,95] 4 0.02 240 1.00
gini.index(cl_volume)
## [1] 0.8195747

Si confera l’intuizione sull’assimetria della variabile. L’80% di tutte le vendite mensili registrate, non supera i 45 milioni di dollari. La classe con una maggiore incidenza sul totale, quindi 43%, é quella delle vendite mensili con valori tra 5 e 25 milioni di dollari.

Calcolando l’indice di Gini sulle classi così definite, si ottiene il valore pari a 0,82. Tra le classi vi é buona eterogeneità in termini di valore delle vendite registrato.

ggplot(freq_table_cl_volume) +
  geom_col(aes(
    x = reorder(Classe_ValoreTotVendite,-fi), 
    y = fi, 
    fill = Classe_ValoreTotVendite)) +
  geom_text(aes(x = reorder(Classe_ValoreTotVendite, -fi), 
                y = fi, 
                label = fi),
            vjust = - 0.35) + 
  labs(title = "Frequenze relative per classe") +
  xlab("Valore Totale Vendite (mln $)")+
  theme_classic()+
  theme(legend.position = "none")

5. Calcolo della probabilità

Alcune casistiche di estrazioni casuali dal dataset e le rispettive probabilità:

  • città di Beaumont é pari al 25%

  • mese di Luglio é pari a 21%

  • mese di Dicembre 2012 é pari a 0,4%

6. Creazione di nuove variabili

Il valore totale delle vendite é generalmente espresso come:

\[ V = P* Q \]

dove P é il prezzo di vendita e Q é quantità venduta

E’ possibile definire il prezzo di vendita, e quindi il prezzo di vendita medio.

df$price <- round((volume*1000000)/sales,0)
summary(df$price)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   97010  132939  156588  154320  173915  213234

Nell’intero periodo, il prezzo di vendita medio é di circa 154.320 dollari.

E’ possibile anche valutare l’efficacia degli annunci di vendita in toto. In termini quantitativi, trascurando l’aspetto temporale, tale metrica é rappresentabile come:

\[ \frac {sales}{listings}*100 \]

dove sales é la quantità venduta, mentre listings numero totale annunci attivi.

df$sales_per_listing <- (sales/listings)*100
summary(df$sales_per_listing)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   5.014   8.980  10.963  11.874  13.492  38.713
listings_per_city <- df %>% 
  group_by(city) %>% 
  summarise(avg_sales_per_listing = round(mean(sales_per_listing),2))

listings_per_month <- df %>% 
  group_by(month) %>% 
  summarise(avg_sales_per_month = round(mean(sales_per_listing),2))


ggplot(listings_per_city) +
  geom_col(aes(x = city, 
               y = avg_sales_per_listing, 
               fill = city), 
           width = 0.7) +
  labs(title = "Vendite medie per inserzione pubblicitaria",
       y = "% vendite su  n. inserzioni", 
       x = "Città") +
  geom_text(aes(
    x = reorder(city,-avg_sales_per_listing),
    y = avg_sales_per_listing,
    label = avg_sales_per_listing),
    vjust = 0.01,
    fontface = "bold"
    )+
  theme_classic() +
  theme(legend.position = "none")

Medialmente al mese il numero delle vendite é circa il 12% del totale annunci attivi nel periodo. Nel mese di luglio del 2014, città Bryan - College Station, si registra la miglior performance storica, una buona dinamica delle vendite rispetto agli annunci, raggiungendo il 39%.

L’efficacia degli annunci, non é necessariamente accompagnata dal buon ritorno economico, ma ci dice che le strategie adotate, correlate al contesto del momento, hanno portato ad una efficace promozione delle vendite. La performance peggiore potrebbe essere uno spunto di riflessione e un’area di miglioramento.

7. Analisi condizionata

# Tabelle per città
table_by_city_sales_volume <- df %>%
  group_by(city) %>%
  summarise(Media_q_venduta = round(mean(sales)),
            Deviazione_std_q_venduta = round(sd(sales)),
            Media_valore_vendita = round((mean(volume))),
            Deviazione_std_valore_vendita = round((sd(volume))))

kable(table_by_city_sales_volume, caption = "Summary per città (sales & volume)")
Summary per città (sales & volume)
city Media_q_venduta Deviazione_std_q_venduta Media_valore_vendita Deviazione_std_valore_vendita
Beaumont 177 41 26 7
Bryan-College Station 206 85 38 17
Tyler 270 62 46 13
Wichita Falls 116 22 14 3
# Tabelle per anno
table_by_year <- df %>%
  group_by(year) %>%
  summarise(Media_q_venduta = round(mean(sales)),
            Deviazione_std_q_venduta = round(sd(sales)),
            Media_valore_vendita = round((mean(volume))),
            Deviazione_std_valore_vendita = round((sd(volume))))

kable(table_by_year, caption = "Summary per anno (sales & volume)")
Summary per anno (sales & volume)
year Media_q_venduta Deviazione_std_q_venduta Media_valore_vendita Deviazione_std_valore_vendita
2010 169 61 26 11
2011 164 64 25 12
2012 186 71 29 15
2013 212 84 35 18
2014 231 96 40 21
# Tabelle per mese
table_by_month <- df %>%
  group_by(month) %>%
  summarise(Media_q_venduta = round(mean(sales)),
            Deviazione_std_q_venduta = round(sd(sales)),
            Media_valore_vendita = round((mean(volume))),
            Deviazione_std_valore_vendita = round((sd(volume))))

kable(table_by_month, caption = "Summary per mese (sales & volume)")
Summary per mese (sales & volume)
month Media_q_venduta Deviazione_std_q_venduta Media_valore_vendita Deviazione_std_valore_vendita
1 127 43 19 8
2 141 51 22 10
3 189 59 29 12
4 212 65 33 15
5 239 83 40 19
6 244 95 41 21
7 236 96 39 21
8 231 79 38 18
9 182 73 30 15
10 180 75 29 15
11 157 55 25 11
12 169 61 27 13
# Chart del numero medio vendite per città nel periodo 
ggplot(table_by_city_sales_volume) +
  geom_col(aes(x = city, 
               y = Media_q_venduta, 
               fill = city), 
           width = 0.7) +
  geom_errorbar(aes(
    x = city,
    ymin = Media_q_venduta - Deviazione_std_q_venduta, 
    ymax = Media_q_venduta + Deviazione_std_q_venduta), 
    width = 0.2,
    linetype = "dashed",
    color = "grey80") +
  labs(title = "Distribuzione della quantità vendite per città (2010-2014)",
       y = "Numero medio vendite", 
       x = "Città") +
  geom_text(aes(
    x = reorder(city,-Media_q_venduta),
    y = Media_q_venduta,
    label = Media_q_venduta),
    vjust = 0.01,
    fontface = "bold"
    )+
  theme_classic() +
  theme(legend.position = "none")

# Chart valore tot vendite medio per città nel periodo 
ggplot(table_by_city_sales_volume) +
  geom_col(aes(x = city, 
               y = Media_valore_vendita, 
               fill = city), 
           width = 0.7) +
  geom_errorbar(aes(
    x = city,
    ymin = Media_valore_vendita - Deviazione_std_valore_vendita, 
    ymax = Media_valore_vendita + Deviazione_std_valore_vendita), 
    width = 0.2,
    linetype = "dashed",
    color = "grey80") +
  labs(title = "Distribuzione del valore totale delle vendite ($) per città (2010-2014)",
       y = "Valore medio totale vendite", 
       x = "Città") +
  geom_text(aes(
    x = reorder(city,-Media_valore_vendita),
    y = Media_valore_vendita,
    label = paste(Media_valore_vendita,"mln")),
    vjust = 0.01,
    fontface = "bold")+
  theme_classic() +
  theme(legend.position = "none")

# Chart del numero medio vendite per anno nel periodo 
ggplot(table_by_year)+
  geom_col(aes(x = year,
               y = Media_q_venduta),
           fill = "skyblue4")+
  geom_errorbar(aes(
    x = year,
    ymin = Media_q_venduta - Deviazione_std_q_venduta, 
    ymax = Media_q_venduta + Deviazione_std_q_venduta), 
    width = 0.2,
    linetype = "dashed",
    color = "grey70") +
  geom_text(aes(x = year, 
                y = Media_q_venduta, 
                label = Media_q_venduta,
                fontface = "bold",
                vjust = - 0.35)) + 
  labs(title = "Distribuzione della quantità vendite per anno",
       y = "Numero medio vendite", 
       x = "Anno") +
  theme_classic()

# Chart del valore medio totale vendite per anno
ggplot(table_by_year)+
  geom_col(aes(x = year,
               y = Media_valore_vendita),
           fill = "skyblue4")+
  geom_errorbar(aes(
    x = year,
    ymin = Media_valore_vendita - Deviazione_std_valore_vendita, 
    ymax = Media_valore_vendita + Deviazione_std_valore_vendita), 
    width = 0.2,
    linetype = "dashed",
    color = "grey70") +
  geom_text(aes(x = year, 
                y = Media_valore_vendita, 
                label = paste(Media_valore_vendita, "mln"),
                fontface = "bold",
                vjust = - 0.35)) + 
  labs(title = "Distribuzione del valore totale delle vendite ($) per anno",
       y = "Valore medio totale vendite", 
       x = "Anno")+
  theme_classic()

# Chart del numero medio vendite per mese
table_by_month$month <- factor(table_by_month$month, levels = 1:12)

ggplot(table_by_month)+
  geom_col(aes(x = month,
               y = Media_q_venduta),
           fill = "skyblue4")+
  geom_errorbar(aes(
    x = month,
    ymin = Media_q_venduta - Deviazione_std_q_venduta, 
    ymax = Media_q_venduta + Deviazione_std_q_venduta), 
    width = 0.2,
    linetype = "dashed",
    color = "grey70") +
  geom_text(aes(x = month, 
                y = Media_q_venduta, 
                label = Media_q_venduta,
                fontface = "bold",
                vjust = - 0.35)) + 
  labs(title = "Distribuzione della quantità vendite per mese",
       y = "Numero medio vendite", 
       x = "Mese") +
  theme_classic()

# Chart del valore totale medio delle vendite per mese
ggplot(table_by_month)+
  geom_col(aes(x = month,
               y = Media_valore_vendita),
           fill = "skyblue4")+
  geom_errorbar(aes(
    x = month,
    ymin = Media_valore_vendita - Deviazione_std_valore_vendita, 
    ymax = Media_valore_vendita + Deviazione_std_valore_vendita), 
    width = 0.2,
    linetype = "dashed",
    color = "grey70") +
  geom_text(aes(x = month, 
                y = Media_valore_vendita, 
                label = paste(Media_valore_vendita, "mln"),
                fontface = "bold",
                vjust = - 0.35)) + 
  labs(title = "Distribuzione del valore totale delle vendite ($) per mese",
       y = "Valore medio totale vendite", 
       x = "Mese")+
  theme_classic()

8. Creazione di visualizzazioni con ggplot2

ggplot(df) +
  geom_boxplot(aes(
    x = city,
    y = median_price,
    fill = city)) +
  labs(title = "Distribuzione del prezzo mediano per città ($)",
       x = "",
       y = "Prezzo mediano")+
  theme_gray() +
  theme(legend.position = "none")

Tutte le città in esame, eccetto Tyler, manifestano la preseza un periodo con il prezzo mediano estremamente alto (outlier) rispetto al resto della distribuizone, plausibilmente per condizioni di mercato.

La città complessivamente più cara in termini di prezzo mediano degli immobili é Bryan-College Station, mentre all’estremo opposto si colloca Wichita Falls. Quest’ultima é di un range interquartile sufficientemente ampio, rispetto alle altre.

La città di Tyler é la più simmetrica in termini di prezzo mediano, con una contenuta dispersione di questo nel periodo; assenti valori anomali estremi. Il prezzo mediano dell’area é solido, quindi non manifesta sbalzi eccessivi.

La struttura del box di Bryan-College Satation suggerisce una distribuzione asimmetrica positiva. Il prezzo mediano degli immobili si concentra prevalentemente attorno a valori più bassi, ma non mancano alcuni casi di prezzi più elevati. E’ opportuno approfondire altre caratteristiche dell’area per comprenderne il mercato specifico.

ggplot(df) +
  geom_boxplot(aes(
    x = city,
    y = volume,
    fill = as.factor(year))) +
  labs(title = "Distribuzione valore totale delle vendite per città (mln $)",
       x = "",
       y = "Valore totale vendite",
       fill = "Anno")+
  theme_gray()

Nel 2012 la città di Beaumont vive un momento di instabilità del valore derivante dalle vendite. Per la maggior parte i valori registrati nell’anno sono elevati, ma anche diluiti da performance che portano valori totali delle vendite estremamente ridotte (outlier).

Nel complesso, si intuisce che nel corso degli anni si verifica una buona crescita del mercato in termini di valore totale delle vendite. Eccezione la città di Wichita Falls, con il “golden year” nel 2010.

Si nota la crescita di Bryan-College Station. Tuttavia, il mercato per questa città, é accompagnato da una spinta varibilità del valore delle vendite, specie nel 2013.

# DF per label totali mese
df_sales_totals_month <- df %>%
  group_by(month) %>%
  summarise(totale = sum(sales), .groups = "drop")

# DF per label totali per città, per mese
df_sales_totals_city <- df %>%
  group_by(month,city) %>%
  summarise(totale_città = sum(sales), .groups = "drop")


ggplot(df) +
  geom_col(aes(
    x = as.factor(month),
    y = sales,
    fill = city),
    position = "stack" ) +
  # Label totale mese 
  geom_text(
    data = df_sales_totals_month,
    aes(
      x = as.factor(month),
      y = totale,
      label = totale),
      vjust = -0.2,     
      fontface = "bold",
      size = 3) +
  # Label totale città
    geom_text(
      data = df_sales_totals_city,
      aes(
        x = as.factor(month),
        y = totale_città,
        label = totale_città,
        group = city),
      position = position_stack(vjust = 0.5),
      color = "white",
      size = 3 ) +
  labs(title = "Distribuzione del totale delle vendite",
       x = "Mese",
       y = "Vendite",
       fill = "Città") +
  theme_classic()

#
ggplot(df) +
  geom_col(aes(
    x = as.factor(month),
    y = sales,
    fill = city),
    position = "stack" ) +
  labs(title = "Distribuzione del totale delle vendite",
       x = "Mese", 
       y = "Vendite",
       fill = "Città") +
  theme_classic() + 
  facet_grid(. ~ year)

Valutando il totale delle vendite, declinato per mesi, si intuisce la presenza di un effetto stagionalità generale. Infatti, maggio-agosto totalizzano un maggior numero di vendite, quindi una domanda plausibilmente più attiva e reattivà alle strategie delle inserzioni pubblicitarie.

L’acquisto degli immobili appare meno appealing nei mesi invernali, in particolar modo nei mesi di gennaio e febbraio.

La città che, ancora una volta, ha un mercato che si discosta dal comportamento delle altre é Wichita Falls.

Dalla prospettiva della mera quantita di vendite registrate cross-month, emerge che l’incidenza maggiore delle vendite sul totale, é indubbiamente in capo alla città di Tyler.

# DF per label sales normalizzate per città, per mese
df_sales_norm <- left_join(df_sales_totals_city,df_sales_totals_month)
## Joining with `by = join_by(month)`
df_sales_norm <- df_sales_norm %>%
  mutate(
    inc_city = round((totale_città/totale),2)
  )

ggplot(df) +
  geom_col(aes(
    x = as.factor(month),
    y = sales,
    fill = city),
    position = "fill" ) +
    geom_text(
      data = df_sales_norm,
      aes(
        x = as.factor(month),
        y = inc_city,
        label = inc_city,
        group = city),
      position = position_stack(vjust = 0.5),
      color = "white",
      size = 3 )  + 
  labs(title = "Distribuzione del totale delle vendite",
       x = "Mese",
       y = "Vendite",
       fill = "Città") +
  scale_y_continuous(breaks = seq(0,1,0.1)) +
  theme_classic()

df <- df %>%
  mutate(
    date = paste(month, year, sep = "/"),
    date = as.Date(paste0("01/", date), format = "%d/%m/%Y")
  )
# Trend vallre totale delle vendite per città
trend_volume_by_date <- df %>% 
  group_by(date) %>% 
  summarise(total_volume = sum(volume))

ggplot(trend_volume_by_date)+
  geom_line(aes(x = date, y = total_volume), 
            color = "skyblue",
            linewidth = 1) +
  labs(title = "Valore totale delle vendite ($) - Trend mensile",
       x = "",
       y = "Valore totale vendite") +
  scale_x_date(
    date_labels = "%m/%Y",
    date_breaks = "3 month") + 
  theme_classic() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        panel.grid.major = element_line(color = "grey96"),
        panel.grid.minor = element_line(color = "grey96"))

# Trend valore totale delle vendite per città
ggplot(df)+
  geom_line(aes(x = date, y = volume, colour = city),
            linewidth = 1) +
  labs(title = "Valore totale delle vendite per città ($) - Trend mensile",
       x = "",
       y = "Valore totale vendite",
       colour = "Città") +
  scale_x_date(
    date_labels = "%m/%Y",
    date_breaks = "3 month") + 
  theme_classic() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        panel.grid.major = element_line(color = "grey96"),
        panel.grid.minor = element_line(color = "grey96"),
        legend.position = "bottom",           
        legend.direction = "horizontal")

A totale, indubbiamente il mercato e il business sono in continua crescita dal 2010. Il rallentamento si osserva nel corso del 2011, successivamente in ripresa fino al 2015. In questa sede, si conferma l’intuizione che il mercato é guidato da fenomeni di stagionalità, con picchi durante il periodo estivo, e cali durante il periodo invernale.

Le città registrano dinamiche analoghe nel corso del tempo. Non mancano, tuttavia, divergenze dei trend in alcuni momenti storici specifici.

Si nota altresì che la città di Tyler ha il mercato in assoluto più proficuo fino al 2013. Successivamente, emerge la competitività dell’area di Bryan-College Station, che si dimostra in grado di generare un valore maggiore delle vendite durante l’alta stagionalità estiva.

9. Conclusioni

Il mercato immobiliare del Texas, superato il rallenatamento nel 2011, storicamente é in crescita fino al 2015. Nonostante la differenza tra aree urbane, é evidente l’effetto ciclico della stagionalità sulla domanda. Ottime opportunità offre il periodo estivo, nei mesi tra maggio e agosto, “golden period” che porta risultati d’impatto. Può essere utile rivalutare nel dettaglio le strategie da adottare durante i mesi di stagnazione.

La città di Tyler é il main player, ottimo mercato con ottimi risultati. Nel corso degli anni, su base mensile, rappresenta circa il 36% del totale delle vendite. Tuttavia, ci sono opportunità non sfruttate in termini di efficacia delle strategie di marketing. Confrontando con le altre città, mediamente l’incidenza del numero di vendite sul numero delle inserzioni pubblicitarie attive é del 9%, il valore più basso. Mediamente nel periodo, il KPI é circa al 12%, buono se non é noto il valore target e considerando l’effetto stagionalità in cui la domanda é meno attiva.

Gli investimenti per le inserzioni pubblicitarie hanno maggiore effetto nel periodo estivo. Tuttavia, andrebbero rivalutate le strategie per quelle città, come Tyler, che soffrono maggiormente il calo stagionale della domanda.

La città di Bryan-College Station, anch’essa un player proficuo, con l’andamento competitivo della stagione estiva del 2014 dimostra un potenziale che va supportato con le politiche di marketing. Inoltre, diversamente da Tyler e altre, risente meno della contrazione autunnale della domanda.

Pur contribuendo poco in termini di valore derivante dalle vendite, é carente il mercato di Wichita Falls. Dopo il miglior periodo nel 2010, il suo mercato é altalenante e non mostra segni di crescita continua. E’, quindi, un’area di miglioramento.