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.
All’interno del dataset troviamo sia colonne riferite a variabili qualitative nominali, variabili quantitative continue e temporali.
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.
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.index <- function(x) {
freq <- table(x)
freq_sort <- sort(freq, decreasing = TRUE)
moda <- names(freq_sort[1])
return(moda)
}
CV <- function(x) {
return((sd(x)/mean(x)) * 100)
}
Asim.index <- function(x) {
m3 <- (sum((x - mean(x))^3)) / length(x)
return(m3 / (sd(x)^3))
}
kurtosis.index <- function(x) {
m4 <- (sum((x - mean(x))^4)) / length(x)
return((m4 / (sd(x)^4)) - 3)
}
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:
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:
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:
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:
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.
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à.
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%.
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))
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).
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).
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 |
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.
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.
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.