Analisi mercato immobiliare del Texas

Caricamento dataset e ricerca di eventuali errori

Per prima cosa abbiamo preparato l’ambiente di lavoro (inizializzazione workspace e copia file CSV nella directory di lavoro) e caricato il dataset con il comando:

 data <- read.csv("realestate_texas.csv", sep=",", header=TRUE, fileEncoding = "Latin1")

Con il comando attach(data) puntiamo i riferimenti alle colonne del dataset, evitando di specificare la tabella.

Visualizziamo le prime righe dei dati con:

 head(data)

Possiamo facilmente intuire che tali dati potrebbero rappresentare già una sintesi di uno studio sulle singole vendite, effettuato su altri dati grezzi (anche se per gli scopi del progetto non è importante). In questo caso abbiamo 240 osservazioni, 6 variabili quantitative, 2 qualitative, 0 errori o valori nulli, quindi non dobbiamo fare operazioni di pulizia o di sostituzione valori non validi.


Analisi delle variabili contenute nel dataset

Identificazione e descrizione delle variabili statistiche

All’interno del dataset troviamo sia colonne riferite a variabili qualitative nominali, variabili quantitative continue e temporali.

Variabili temporali

  • year: è una variabile quantitativa discreta che esprime un dato temporale (anno di vendita), tale informazione va letta insieme a month per indicare un determinato periodo di vendita.

Variabili qualitative nominali

  • city: è una variabile qualitativa su scala nominale, in quanto le diverse modalità possono essere confrontate in termini di uguaglianza. Può essere utilizzata per identificare le città in cui avviene un numero di vendite.
  • month: è una variabile numerica ma qualitativa categoriale che esprime un dato temporale (il mese di vendita), va letta insieme a year (anzi può essere interpretata come un suo “offset”).

Variabili quantitative

  • sales: è una variabile quantitativa discreta, in quanto rappresenta un conteggio (il numero di vendite) ed assume valori interi.
  • volume: è una variabile quantitativa continua, rappresenta l’importo totale delle vendite.
  • median_price: è una variabile quantitativa continua, rappresenta il valore mediano sul prezzo.
  • listings: anch’essa è una variabile quantitativa discreta (conteggio di annunci attivi).
  • months_inventory: è una variabile quantitativa continua, in quanto può essere suddivisa in intervalli sempre più piccoli.

Calcolo indici di posizione, variabilità e forma

Calcoliamo indici di posizione, variabilità e forma per tutte le variabili per le quali ha senso farlo. Per le altre creiamo una distribuzione di frequenza.

Sia gli indici di posizione che quelli di variabilità possiamo calcolarli per le variabili quantitative: volume, sales, listings, median_price (che è già un valore mediano) e months_inventory. Per tutti gli altri si calcolano le distribuzioni di frequenza o l’Indice di Gini.

Descrizione e definizione di funzioni in R

Per velocizzare il calcolo degli indici di posizione abbiamo utilizziamo la funzione summary sulle singole variabili (anche se avremmo potuto utilizzare mean, min, max, etc..).

Per alcuni indici di variabilità, abbiamo utilizzato le funzioni built-in di R:

  • range() per l’intervallo di variazione,

  • IQR() per il range interquartile,

  • var() per la varianza,

  • sd() per la deviazione standard

Seguono delle funzioni custom di R per il calcolo di

  • moda
moda.index <- function(x) {
  freq <- table(x)
  freq_sort <- sort(freq, decreasing = TRUE)
  moda <- names(freq_sort[1])
  return(moda)
}
  • coefficiente di variazione
CV <- function(x) {
  return((sd(x)/mean(x)) * 100)
}
  • indice di asimmetria di Fisher (momento terzo della distribuzione)
Asim.index <- function(x) {
  m3 <- (sum((x - mean(x))^3)) / length(x)
  return(m3 / (sd(x)^3))
}
  • indice di Curtosi (momento quarto della distribuzione)
kurtosis.index <- function(x) {
  m4 <- (sum((x - mean(x))^4)) / length(x)
  return((m4 / (sd(x)^4)) - 3)
}

Calcolo dei valori

Volume

Permette di capire l’andamento generale delle vendite nel tempo, identificando periodi con volumi di vendita più alti e quelli più bassi.

Indici di posizione ottenuti con summary(volume):

Minimo Primo Quartile Mediana Media Terzo Quartile Massimo Moda
8.166 17.660 27.062 31.005 40.893 83.547 14.003

e la moda ottenuta con moda.index(volume).

Nota: i valori del range sono tutti positivi e non nulli (perché lo sono sia il valore massimo che il valore minimo).

Gli Indici di variabilità permettono di capire quanto variano le vendite mensili variano rispetto alla media annuale. Li abbiamo calcolati con

volume_range ← max(volume) – min(volume)

volume_irq ← IQR(volume)

volume_cv ← CV(volume)

volume_var ← var(volume)

volume_sd ← sd(volume)

i cui risultati sono

Range Range interquartile Varianza Deviazione standard Coefficente di variazione Indice di Gini
75.381 23.2335 277.2707 16.65145 53.70536 -

Considerazioni: non essendoci né valori nulli né valori negativi, ci siamo potuti calcolare il coefficiente di variazione. Poichè il suo valore è di circa 54, possiamo dedurre che volumes ha una deviazione standard che è quasi il 54% della media (la quale corrisponde a 31.005).

Gli indici di forma li abbiamo ottenuti con

Asim.index(volume)

kurtosis.index(volume)

i cui risultati sono

Asimmetria Curtosi
0.8792182 0.1505673

Quindi possiamo dedurre che la forma della distribuzione è asimmetrica positiva, in quanto l’indice di asimmetria è positivo, di conseguenza vale media > mediana > moda. Inoltre è una distribuzione leptocurtica (in quando ha l’indice di curtosi positivo), quindi più allungata rispetto alla distribuzione normale.

Disegnando la funzione di densità con plot(density(volume)), otteniamo il seguente grafico:

Sales

Permette di capire l’andamento generale delle vendite nel tempo, identificando periodi con volumi di vendita più alti e quelli più bassi.

Indici di posizione ottenuti con summary(sales):

Minimo Primo Quartile Mediana Media Terzo Quartile Massimo Moda
79.0 127.0 175.5 192.3 247.0 423.0 124

e la moda ottenuta con moda.index(sales).

Indici di variabilità calcolati con

sales_range ← max(sales) – min(sales)

sales_irq ← IQR(sales)

sales_cv ← CV(sales)

sales_var ← var(sales)

sales_sd ← sd(sales)

i cui risultati sono

Range Range interquartile Varianza Deviazione standard Coefficente di variazione Indice di Gini
344 120 6344.2995 79.6511 41.4220 -

Considerazioni: il coefficiente di variazione è calcolabile grazie al fatto che non ci sono valori positivi e negativi contemporaneamente né zeri assoluti. Il coefficiente di variazione di circa 41.4 indica che sales ha una deviazione standard che è quasi meno del 42% della media (la quale corrisponde a 31.005).

Gli indici di forma li abbiamo ottenuti con

Asim.index(sales)

kurtosis.index(sales)

i cui risultati sono

Asimmetria Curtosi
0.7136206 -0.33552

Quindi possiamo dedurre che la forma della distribuzione è asimmetrica positiva, in quanto l’indice di asimmetria è positivo, di conseguenza vale media > mediana > moda.

Poiché l’indice di Curtosi è negativo, possiamo concludere che la distribuzione è platicurtica, quindi è più appiattita della distribuzione normale.

Disegnando la funzione di densità con plot(density(sales)), otteniamo il seguente grafico:

Median price

Utile per capire le tendenze del mercato immobiliare e per individuare i prezzi più richiesti. Rappresenta una media calcolata sui dati grezzi in una precedente analisi statistica.

Indici di posizione ottenuti con summary(median_price):

Minimo Primo Quartile Mediana Media Terzo Quartile Massimo Moda
73800 117300 134500 132665 150050 180000 130000

e la moda ottenuta con moda.index(median_price).

Indici di variabilità calcolati con

median_price_range ← max(median_price) – min(median_price)

median_price_irq ← IQR(median_price)

median_price_cv ← CV(median_price)

median_price_var ← var(median_price)

median_price_sd ← sd(median_price)

i cui risultati sono

Range Range interquartile Varianza Deviazione standard Coefficente di variazione Indice di Gini
106200 32750 513572983 22662.15 17.08218 -

Considerazioni: il coefficiente di variazione è calcolabile grazie al fatto che non ci sono valori positivi e negativi contemporaneamente né zeri assoluti. Il coefficiente di variazione di 17 indica che medium_price ha una deviazione standard che è quasi meno del 17% della media (la quale corrisponde a 132665).

Gli indici di forma li abbiamo ottenuti con

Asim.index(sales)

kurtosis.index(sales)

i cui risultati sono

Asimmetria Curtosi
-0.3622768 -0.6427292

Disegnando la funzione di densità con plot(density(median_price)), otteniamo il seguente grafico:

Listings

Utile per capire l’efficienza del processo di vendita in base al numero totale di annunci attivi nel tempo.

Indici di posizione ottenuti con summary(listings):

Minimo Primo Quartile Mediana Media Terzo Quartile Massimo Moda
743 1026 1618 1738 2056 3296 1581

e la moda ottenuta con moda.index(listings).

Indici di variabilità calcolati con

listings_range ← max(listings) – min(listings)

listings_irq ← IQR(listings)

listings_cv ← CV(listings)

listings_var ← var(listings)

listings_sd ← sd(listings)

i cui risultati sono

Range Range interquartile Varianza Deviazione standard Coefficente di variazione Indice di Gini
2553 1029.5 566569 752.7078 43.30833 -

Considerazioni: il coefficiente di variazione è calcolabile grazie al fatto che non ci sono valori positivi e negativi contemporaneamente né zeri assoluti. Il coefficiente di variazione di 43.3 indica che listings ha una deviazione standard che è circa il 43,3% della media (la quale corrisponde a 1738).

Gli indici di forma li abbiamo ottenuti con

Asim.index(listings)

kurtosis.index(listings)

i cui risultati sono

Asimmetria Curtosi
0.6454431 -0.8101534

Disegnando la funzione di densità con plot(density(listings), otteniamo il seguente grafico:

Months_inventory

Utile per valutare la liquidità del mercato e per identificare eventuali sovraffollamenti o carenze di offerta.

Indici di posizione ottenuti con summary(months_inventory):

Minimo Primo Quartile Mediana Media Terzo Quartile Massimo Moda
3.400 7.800 8.950 9.193 10.950 14.900 8.1

e la moda ottenuta con moda.index(months_inventory).

Indici di variabilità calcolati con

months_inventory_range ← max(months_inventory) – min(months_inventory)

months_inventory_irq ← IQR(months_inventory)

months_inventory_cv ← CV(months_inventory)

months_inventory_var ← var(months_inventory)

listings_sd ← sd(months_inventory)

i cui risultati sono

Range Range interquartile Varianza Deviazione standard Coefficente di variazione Indice di Gini
11.5 3.15 5.3069 2.3037 25.06031 -

Considerazioni: il coefficiente di variazione è calcolabile grazie al fatto che non ci sono valori positivi e negativi contemporaneamente né zeri assoluti. Il coefficiente di variazione di X indica che listings ha una deviazione standard che è circa il 25% della media (la quale corrisponde a 9.193).

Gli indici di forma li abbiamo ottenuti con

Asim.index(months_inventory)

kurtosis.index(months_inventory)

i cui risultati sono

Asimmetria Curtosi
0.04071944 -0.1979448

Disegnando la funzione di densità con plot(density(months_inventory), otteniamo il seguente grafico:

Per tutte le variabili notiamo che non ci sono valori troppo alti o troppo bassi (outliers), motivo per cui la media non è molto distante dalla mediana.


Identificazione variabili con maggiore variabilità e asimmetria

Determina:

  • Qual è la variabile con la più alta variabilità

  • Qual è la variabile con la distribuzione più asimmetrica.

Spiega come sei giunto a queste conclusioni e fornisci considerazioni statistiche.

Il risultato ottenuto è il seguente:

  • La variabile con maggiore variabilità è volume con coefficiente di variazione pari a 53.7%.

  • La variabile con maggiore asimmetria è volume con indice di Fisher pari a 0.879.

Ragionamento

Per stabilire quale variabile sia la più asimmetrica

  • variabili quantitative: consideriamo, in valore assoluto, il valore massimo dell’asimmetria di Fisher, nel nostro caso è quello di volume con un valore di 0.8792182;

  • variabili qualitative: nulla si può stabilire, in quanto non vi è un indice di forma per le variabili qualitative.

Per stabilire la variabile con più variabilità elevata

  • variabili quantitative: potremmo utilizzare la deviazione standard (che rappresenta la varianza nella stessa scala dei dati) e considerare il valore più alto; tuttavia, se i valori delle medie sono troppo diverse, meglio considerare il coefficiente di variazione (a patto che non ci siano valori negativi o nulli) ossia 53.70536 per la variabile volume;

  • variabili qualitative: in questo caso occorre considerare il valore più alto dell’Indice di Gini, che rappresenta la massima eterogeneità.


Creazione di classi per una variabile quantitativa

Seleziona una variabile quantitativa (es. sales o median_price) e suddividila in classi. Crea una distribuzione di frequenze e rappresenta i dati con un grafico a barre. Calcola l’indice di eterogeneità Gini e discuti i risultati.

Abbiamo suddiviso la variabile sales in classi di ampiezza 100 e calcolato la distribuzione di frequenze. In questo modo otteniamo i totali delle vendite in periodi differenti

N<-lenght(sales)
sales_cl<-cut(sales, breaks=c(0,100,200,300,400,500))
ni<-table(sales_cl)
fi<-ni/N
Ni<-cumsum(ni)
Fi<-Ni/N
distr_sales_cl<-as.data.frame(cbind(ni, fi, Ni, Fi))

abbiamo così ottenuto la seguente distribuzione di frequenze per la variabile sales:

Intervallo ni fi Ni Fi
(0,100] 21 0.08750000 21 0.0875000
(100,200] 128 0.53333333 149 0.6208333
(200,300] 66 0.27500000 215 0.8958333
(300,400] 22 0.09166667 237 0.9875000
(400,500] 3 0.01250000 240 1.0000000

per rappresentare tali valori su un grafico a barre, abbiamo utilizzato barplot (non abbiamo scomodato ggplot perché si tratta di grafico semplice).

barplot(distr_sales_cl$fi,
main="Distribuzione delle classi del numero totale di vendite",
xlab="Classi del numero totale di vendite",
ylab="Frequenze relative",
col="blue",
names.arg=rownames(distr_sales_cl))

l’indice di eterogeneità di Gini è ottenuto tramite la funzione custom da noi creata:

gini_coefficient <- 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)
}

Applicando tale funzione alla variabile variabile sales_cl otteniamo un valore di 0.7796441, ovvero un’eterogeneità al 78%.

Indice di gini per la variabile city

L’indice di Gini per la variabile city è pari a 1, in quanto si ha una eterogeneità massima. Lo possiamo vedere sia applicando alla variabile city la funzione definita nel punto precedente, che tramite la distribuzione costruita per tale variabile:

Località 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

costruita nel modo che conosciamo, ovvero

ni<-table(city)
fi<-ni/N
Ni<-cumsum(ni)
Fi<-Ni/N
distr_city<-as.data.frame(cbind(ni, fi, Ni, Fi))

Calcolo delle probabilità

Qual è la probabilità che presa una riga a caso di questo dataset essa riporti la città “Beaumont”? E la probabilità che riporti il mese di Luglio? E la probabilità che riporti il mese di dicembre 2012?

La probabilità che presa una riga a caso di questo dataset essa riporti la città “Beaumont” è pari a 0.25, in quanto abbiamo 60 osservazioni con tale città, e le singole osservazioni sono tutte equiprobabili (come possiamo vedere anche dalla tabella). Infatti, calcolando il numero di casi favorevoli / il numero di casi possibili, abbiamo:

distr_city["Beaumont", 1]/N

ovvero 60/240 che equivale a 0.25.

La probabilità che presa una riga a caso di questo dataset essa riporti il mese di Luglio è pari a 0.08333333, in quanto anche qui abbiamo un caso di equiprobabilità. Infatti costruendoci la distribuzione per mese:

ni<-table(month)
fi<-ni/N
Ni<-cumsum(ni)
Fi<-Ni/N
distr_month<-as.data.frame(cbind(ni, fi, Ni, Fi))

otteniamo

# ni fi Ni Fi
1 20 0.08333333 20 0.08333333
2 20 0.08333333 40 0.16666667
3 20 0.08333333 60 0.25000000
4 20 0.08333333 80 0.33333333
5 20 0.08333333 100 0.41666667
6 20 0.08333333 120 0.50000000
7 20 0.08333333 140 0.58333333
8 20 0.08333333 160 0.66666667
9 20 0.08333333 180 0.75000000
10 20 0.08333333 200 0.83333333
11 20 0.08333333 220 0.91666667
12 20 0.08333333 240 1.00000000

che è analogo al caso precedente della città (infatti 20/240=0.08333333).

E la probabilità che riporti il mese di dicembre 2012?

Si procede come prima, ma calcoliamo la distribuzione di frequenze doppie che tenga conto del mese e dell’anno:

month_year = table(month, year)/N
Month 2010 2011 2012 2013 2014
1 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
2 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
3 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
4 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
5 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
6 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
7 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
8 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
9 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
10 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
11 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667
12 0.01666667 0.01666667 0.01666667 0.01666667 0.01666667

Quindi il valore è 0.01666667 (equiprobabile, in quanto lo è anche nelle distribuzioni semplici, sia se si considera il solo mese che se si considera il solo anno).


Creazione di nuove variabili

Crea una nuova colonna che calcoli il prezzo medio degli immobili utilizzando le variabili disponibili. Prova a creare una colonna che misuri l’efficacia degli annunci di vendita. Commenta e discuti i risultati.

Consideriamo il rapporto tra la variabile volumes (espressa in milioni di dollari) ed il numero di vendite (ovvero la variabile sales) per ogni osservazione con

raw_data$mean_price <- (volume * 10^6) / sales

Per misurare l’efficacia degli annunci di vendita, dobbiamo creare la variabile ad_effectiveness calcolata come il rapporto tra il numero di vendite (sales) e la quantità di annunci attivi (listings). Poichè il rapporto è in percentuale, possiamo moltiplicare il valore per 100:

raw_data$ad_effectiveness <- (sales / listings) * 100

eseguendo il comando head(raw_data) otteniamo la tabella con le due nuove colonne

City Year Month Sales Volume Median Price Listings Months Inventory Mean Price Ad Effectiveness
Beaumont 2010 1 83 14.162 163800 1533 9.5 170626.5 5.414220
Beaumont 2010 2 108 17.690 138200 1586 10.0 163796.3 6.809584
Beaumont 2010 3 182 28.701 122400 1689 10.6 157697.8 10.775607
Beaumont 2010 4 200 26.819 123200 1708 10.6 134095.0 11.709602
Beaumont 2010 5 202 28.833 123100 1771 10.9 142737.6 11.405985
Beaumont 2010 6 189 27.219 122800 1803 11.1 144015.9 10.482529

Analisi condizionata

Usa il pacchetto dplyr o il linguaggio base di R per effettuare analisi statistiche condizionate per città, anno e mese. Genera dei summary (media, deviazione standard) e rappresenta graficamente i risultati.

Analizziamo le vendite annuali per città con dplyr:

summary_stats <- raw_data %>%
group_by(city, month, year) %>%
summarise(
mean_sales = mean(sales, na.rm = TRUE),
sd_sales = sd(sales, na.rm = TRUE)
)

otteniamo i seguenti valori con head(summary_stats):

City Month Year Mean Sales SD Sales
Beaumont 1 2010 83 NA
Beaumont 1 2011 108 NA
Beaumont 1 2012 110 NA
Beaumont 1 2013 159 NA
Beaumont 1 2014 148 NA
Beaumont 2 2010 108 NA

come vediamo la deviazione standard non è calcolabile in questo caso.

Visualizziamo i risultati con ggplot:

library(ggplot2)
ggplot(summary_stats, aes(x = interaction(year), y = mean_sales, fill = city)) +
  geom_col(width = 0.9, position = "dodge") +
  labs(title = "Andamento della media delle vendite annuali per città", x = "Anno", y = "media di appartamenti venduti") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Possiamo notare che nella città di Tyler sono state vendute più case nel 2014, più precisamente nel periodo di Giugno, come possiamo vedere nel grafico seguente, ottenuto aggiungendo il mese alla funzione x = interaction(year, month) ed eventualmente alla clausola group_by().

Usando la stessa funzione, possiamo ottenere la stessa analisi su altre variabili, come l’andamento del prezzo mediano (median_price).

Come possiamo vedere il prezzo mediano più alto si è verificato nel 2014 a Bryan-College Station, mentre quello più basso nel 2011 a Witchita Falls. Con maggiore precisione, tali valori si sono avuti, rispettivamente, nel mese di Settembre 2014 e Gennaio 2010).

Per quanto riguarda il prezzo degli immobili a Beamount, inizialmente è sceso nel 2011, e poi aumentare nuovamente nel biennio 2013-2014.


Visualizzazioni con ggplot2

Boxplot per confrontare la distribuzione del prezzo mediano tra le città.

Facciamo un’analisi della media di vendite annuali in ogni città.

Per fare ciò possiamo usare la funzione geom_boxplot() di ggplot2 ed evidenziare il valore di outlier in rosso. Possiamo notare che la zona più costosa è Bryan-College Station, come era emerso dalle indagini precedenti.

ggplot(raw_data, aes(x = city, y = median_price, fill = city)) +
  geom_boxplot(outlier.color = "red", outlier.shape = 8) +
   labs(title = "Confronto del Prezzo Mediano tra le Città",
   x = "Città",
   y = "Prezzo Mediano") +
  theme_minimal() +
  theme(axis.text.x = element_tele = 45, hjust = 1))

il cui boxplot ottenuto:

Grafico a barre per confrontare il totale delle vendite per mese e città.

Dal grafico possiamo notare che nel mese di Giugno vengono vendute più case, in particolare nella città di Tyler

Tale grafico è stato ottenuto tramite una summarise della libreria dplyr, seguito da ggplot2 con un vettore contenente le etichette dei mesi

summary_stats <- raw_data %>%
  group_by(city, month) %>%
  summarise(
    mean_sales = mean(sales, na.rm = TRUE),
    sd_sales = sd(sales, na.rm = TRUE)
  )
  
month_names <- c("Gen", "Feb", "Mar", "Apr", "Mag", "Giu",
"Lug", "Ago", "Set", "Ott", "Nov", "Dic")

ggplot(summary_stats, aes(x = interaction(month), y = mean_sales, fill = city)) + 
  geom_col(width = 0.9, position = "dodge") +
  scale_x_discrete(labels = function(x) month_names[as.numeric(x)]) +
  labs(title = "Andamento delle media vendite Mensili per Città",
  x = "Mese", y = "Media di Appartamenti Venduti") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Line charts per confrontare l’andamento delle vendite in periodi storici differenti

Come prima, abbiamo usato il summarise() di dplyr per preparare i dati delle vendite, aggiungendo anche una colonna per le date

summary_stats <- raw_data %>%
  group_by(city, year, month) %>%
  summarise(mean_sales = mean(sales, na.rm = TRUE),
    sd_sales = sd(sales, na.rm = TRUE),
    .groups = 'drop') %>%
mutate(date = as.Date(paste(year, month, "01", sep = "-")))

poi con ggplot generiamo il grafico che mostra l’andamento delle vendite nel tempo, ad intervalli di 3 mesi. Abbiamo usato geom_line() e geom_point() per evidenziare meglio le linee e i punti:

ggplot(summary_stats, aes(x = date, y = mean_sales, color = city, group = city)) +
  geom_line(size = 1) + 
  geom_point(size = 2) +
  labs(title = "Andamento delle Vendite per Città nel Tempo",
  x = "Periodo Storico", y = "Media di Appartamenti Venduti") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  scale_x_date(date_labels = "%b %Y", date_breaks = "3 months")

Il seguente risultato parla chiaro:

le vendita nella città di Tyler raggiungano il picco massimo nei periodo estivo del 2014 (come visto in una precedente analisi), preceduta da un abbassamento iniziato nel periodo invernale del 2014 fino alla primavera successiva. L’altra città dove si sono registrate più vendite è Bryan-College Station, dove addirittura arriva a superare quelle di Tyler nella primavera del 2013, per poi tornare in seconda posizione.


Conclusioni

Per concludere, possiamo sintetizzare le conclusioni in due punti:

  • Le vendite sono influenzate dalla stagionalità (picco in giugno) e dalla città.

  • Dal 2010 al 2015 le vendite sono quasi raddoppiate.

L’analisi suggerisce che le vendite immobiliari sono influenzate sia dalla stagionalità che dalle dinamiche di mercato locali.