knitr::opts_chunk$set(echo = TRUE)
# install.packages("dplyr") # manipolare facilmente i dati
# install.packages("e1071") # per skewness e kurtosis
# install.packages("purrr") #funzioni potenti ed evita for loop
# install.packages("kableExtra") #kableExtra per la gestione delle tabelle nel #documento markdown
# install.packages("ggplot2") # per i grafici
#se i pacchetti non sono installati li installa
if (!require("dplyr")) {
install.packages("dplyr")
}
if (!require("e1071")) {
install.packages("e1071")
}
if (!require("purrr")) {
install.packages("purrr")
}
if (!require("kableExtra")) {
install.packages("kableExtra")
}
if (!require("ggplot2")) {
install.packages("ggplot2")
}
#carica i pachetti
library(ggplot2)
library(kableExtra)
library(purrr)
library(dplyr)
library(e1071)
# toglie la notazione scientica
options(scipen = 999)
#Utility -> funzioni per il calcolo della Moda, Indici, Frequenza, GINI Index
# Funzione per il calcolo della moda
get_mode <- function(v) {
uniqv <- unique(v)
uniqv[which.max(tabulate(match(v, uniqv)))]
}
# Funzione per calcolare tutti gli indici su un singolo vettore
# per variabili Quantitative, la funzione ha due paramtri:
# x -> variabile su cui calcolare gli indici
# variabile_continua -> indica se la variabile è continua o discreta
# se la variabile è continua non viene calcolato l'indice Moda
calcola_indici <- function(x,variabile_continua = FALSE) {
if (variabile_continua)
{
data.frame(
media = mean(x, na.rm = TRUE), # Media aritmetica
mediana = median(x, na.rm = TRUE), # Mediana
minimo = min(x, na.rm = TRUE), # Minimo
massimo = max(x, na.rm = TRUE), # Massimo
Q1 = quantile(x, 0.25, na.rm = TRUE), # Primo quartile
Q3 = quantile(x, 0.75, na.rm = TRUE), # Terzo quartile
varianza = var(x, na.rm = TRUE), # Varianza
deviazione_std = sd(x, na.rm = TRUE), # Deviazione standard
coeff_var = sd(x, na.rm = TRUE) / mean(x, na.rm = TRUE), # Coefficiente di variazione
skewness = skewness(x, na.rm = TRUE), # Asimmetria (skewness)
kurtosis = kurtosis(x, na.rm = TRUE) # Curtosi
)
}
else
{
data.frame(
media = mean(x, na.rm = TRUE),
mediana = median(x, na.rm = TRUE),
moda = get_mode(x), # Moda da funziona
minimo = min(x, na.rm = TRUE),
massimo = max(x, na.rm = TRUE),
Q1 = quantile(x, 0.25, na.rm = TRUE),
Q3 = quantile(x, 0.75, na.rm = TRUE),
varianza = var(x, na.rm = TRUE),
deviazione_std = sd(x, na.rm = TRUE),
coeff_var = sd(x, na.rm = TRUE) / mean(x, na.rm = TRUE),
skewness = skewness(x, na.rm = TRUE),
kurtosis = kurtosis(x, na.rm = TRUE)
)
}
}
# funzione per calcolare la frequenza per variabili categoriche
get_frequenze <- function(var) {
df %>%
count({{var}}, name = "Frequenza") %>%
mutate(Frequenza_percentuale = round(Frequenza / sum(Frequenza) * 100, 2))
}
#indice di GINI
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)
}
#carica i dati del csv in un dataframe
df <- read.csv("Real Estate Texas.csv", sep = ",", header = TRUE)
| Variabile | Descrizione | Tipo di Variabile |
| city | città di riferimento | Qualitativa nominale |
| year | anno di riferimento | Quantitativa continua da trattare come qualitativa ordinale in questo caso |
| month | mese di riferimento (es. 1,2, …) | Qualitativa nominale |
| sales | numero totale di vendite | Quantitativa discreta |
| volume | valore totale delle vendite (in milioni di dollari) | Quantitativa continua |
| median_price | prezzo mediano di vendita (in dollari) | Quantitativa continua |
| listings | numero totale di annunci immobiliari attivi | Quantitativa discreta |
| months_inventory | quantità di tempo necessaria per vendere tutte le inserzioni correnti, espresso in mesi | Quantitativa continua |
| Variabile | Tipo di analisi |
|---|---|
| year |
|
| month |
|
# viene utilizzata la funzione calcola_indici per calcolare gli indici
riassunto_statistico_no_continue <- df %>%
select(where(is.numeric)) %>%
map_dfr(calcola_indici, .id = "variabile")
# dal riassunto statistico vengono tolte le varibili quantitative continue
# perchè alcuni indici non devono essere calcolati per tali variabili
riassunto_statistico_no_continue <- riassunto_statistico_no_continue %>%
filter(!variabile %in% c("year", "month","volume","median_price","months_inventory"))
# gli indici vengono arrotondati alla seconda cifra decimale
riassunto_statistico_no_continue <- riassunto_statistico_no_continue %>%
mutate(across(where(is.numeric), ~round(., 2)))
# viene creata la tabella degli indici tramite la funzione kbl del pacchetto # knitr e poi formatta tramite la funzione kable_styling del pacchetto kableExtra
riassunto_statistico_no_continue %>%
kbl(caption = "Riepilogo statistico delle variabili quantitative discrete",
align = "c",
booktabs = TRUE,
row.names = FALSE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
font_size = 14)
| variabile | media | mediana | moda | minimo | massimo | Q1 | Q3 | varianza | deviazione_std | coeff_var | skewness | kurtosis |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| sales | 192.29 | 175.5 | 124 | 79 | 423 | 127.0 | 247 | 6344.3 | 79.65 | 0.41 | 0.71 | -0.34 |
| listings | 1738.02 | 1618.5 | 1581 | 743 | 3296 | 1026.5 | 2056 | 566569.0 | 752.71 | 0.43 | 0.65 | -0.81 |
Variabile Sales -> media e mediana sono maggiori della moda e questo si riflette sull’asimmetria che sarà positiva infatti l’indice skewness ha un valore positivo
Variabile Listings -> media e mediana sono maggiori della moda e questo si riflette sull’asimmetria che sarà positiva infatti l’indice skewness ha un valore positivo; il range è molto elevato tra un massimo di 3296 ed un minimo di 743 questo significa che i dati sono molto dispersi.
# viene utilizzata la funzione calcola_indici per calcolare gli indici
riassunto_statistico_continue <- df %>%
select(where(is.numeric)) %>%
map_dfr(~calcola_indici(.x, variabile_continua = TRUE), .id = "variabile")
# dal riassunto statistico vengono tolte le varibili quantitative discrete
# perchè già calcolate
riassunto_statistico_continue <- riassunto_statistico_continue %>%
filter(!variabile %in% c("year", "month","sales","listings"))
# gli indici vengono arrotondati alla seconda cifra decimale
riassunto_statistico_continue <- riassunto_statistico_continue %>%
mutate(across(where(is.numeric), ~round(., 2)))
# viene creata la tabella degli indici tramite la funzione kbl del pacchetto knitr e poi formatta tramite la funzione kable_styling del pacchetto kableExtra
riassunto_statistico_continue %>%
kbl(caption = "Riepilogo statistico delle variabili quantitative continue",
align = "c",
booktabs = TRUE,
row.names = FALSE
) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
font_size = 14)
| variabile | media | mediana | minimo | massimo | Q1 | Q3 | varianza | deviazione_std | coeff_var | skewness | kurtosis |
|---|---|---|---|---|---|---|---|---|---|---|---|
| volume | 31.01 | 27.06 | 8.17 | 83.55 | 17.66 | 40.89 | 277.27 | 16.65 | 0.54 | 0.88 | 0.15 |
| median_price | 132665.42 | 134500.00 | 73800.00 | 180000.00 | 117300.00 | 150050.00 | 513572983.09 | 22662.15 | 0.17 | -0.36 | -0.64 |
| months_inventory | 9.19 | 8.95 | 3.40 | 14.90 | 7.80 | 10.95 | 5.31 | 2.30 | 0.25 | 0.04 | -0.20 |
Variabile Volume -> la media è superiore alla mediana questo denota una asimmetria positiva; il coefficiente di variazione ha un valore di 0.54 che denota una variabilità moderata
Variabile Median_price -> la media è leggermente inferiore alla mediana questo denota una asimmetria negativa; il coefficiente di variazione ha un valore di 0.17 che denota una bassa variabilità e cioè prezzi abbastanza stabili
Variabile Month_inventory -> media e mediana sono quasi simili questo denota una distribuzione simmetrica
# usando la funzione get_frequenze calcola la frequenza assoluta e percentuale delle varibili city, year e month
frequenze_city <- get_frequenze(city)
frequenze_year <- get_frequenze(year)
frequenze_month <- get_frequenze(month)
#tramite le funzioni kbl e kable_styling knitr e kableExtra visualizza i dati un una tabella
frequenze_city %>%
kbl(caption = "Distribuzione di frequenza per la variabile City",
align = "c",
booktabs = TRUE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
font_size = 14)
| city | Frequenza | Frequenza_percentuale |
|---|---|---|
| Beaumont | 60 | 25 |
| Bryan-College Station | 60 | 25 |
| Tyler | 60 | 25 |
| Wichita Falls | 60 | 25 |
Variabile City -> Ogni città compare 60 volte nel dataset ed ha una frequenza del 25%, la distribuzione è perfettamente bilanciata
#tramite le funzioni kbl e kable_styling knitr e kableExtra visualizza i dati un una tabella
frequenze_year %>%
kbl(caption = "Distribuzione di frequenza per la variabile Year",
align = "c",
booktabs = TRUE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
font_size = 14)
| year | Frequenza | Frequenza_percentuale |
|---|---|---|
| 2010 | 48 | 20 |
| 2011 | 48 | 20 |
| 2012 | 48 | 20 |
| 2013 | 48 | 20 |
| 2014 | 48 | 20 |
Variabile Year -> ogni anno compare 48 volte ed ha una frequenza del 20%, la distribuzione è perfettamente bilanciata
#tramite le funzioni kbl e kable_styling knitr e kableExtra visualizza i dati un una tabella
frequenze_month %>%
kbl(caption = "Distribuzione di frequenza per la variabile Month",
align = "c",
booktabs = TRUE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
font_size = 14)
| month | Frequenza | Frequenza_percentuale |
|---|---|---|
| 1 | 20 | 8.33 |
| 2 | 20 | 8.33 |
| 3 | 20 | 8.33 |
| 4 | 20 | 8.33 |
| 5 | 20 | 8.33 |
| 6 | 20 | 8.33 |
| 7 | 20 | 8.33 |
| 8 | 20 | 8.33 |
| 9 | 20 | 8.33 |
| 10 | 20 | 8.33 |
| 11 | 20 | 8.33 |
| 12 | 20 | 8.33 |
Variabile Month -> ogni mese compare 20 volte e la frequenza è di 8.33%, la distribuzione è perfettamente bilanciata
La variabile con la più alta variabilità è Volume che ha il coefficiente di variazione di 0.54
Questo indica che i valori sono abbastanza dispersi attorno al valore medio.
Sono giunto a questa conclusione osservando l’indice “coeff_var” che mette in relazione la devianzione standard con la media ed è un indice adimensionale.
La variabile con la distribuzione più asimmetrica è Volume con un indice skewness di 0.88, asimmetrica positiva.
Questo indica che la distribuzione è asimmetrica positivamente, cioè con una coda più lunga verso valori maggiori, questo suggerisce la presenza di alcuni valori elevati.
Sono giunto a questa conclusione osservando l’indice “skewness” che misura la simmetria o asimmetria della distribuzione di una variabile rispetto alla sua media.
skewness = 0 -> distribuzione perfettamente simmetrica
skewness > 0 -> distribuzione asimmetrica a destra positiva
skewness < 0 -> distribuzione asimmetrica a sinistra negativa
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.La variabile scelta per essere suddivisa in classi è Sales
# è una sequenza numerica che va da un valore minimo di 0 ad un valore massimo di 500 e un passo di 100
classi <- seq(0, 500, by = 100)
# crea la variabile sales_class utilizzando la sequenza numerica Classi per la variabile Sales
df <- df %>%
mutate(sales_class = cut(
sales,
breaks = classi, # numero di classi
include.lowest = TRUE,
right = FALSE, # intervalli chiusi a sinistra, aperti a destra
dig.lab = 10 # evita notazione scientifica
))
# tramite la funzione get_frequenze valorizza frequenze_sales_class con la frequenza delle varie classi calcolate nel precedente passaggio
frequenze_sales_class <- get_frequenze(sales_class)
# tramite le funzioni kbl e kable_styling viene creata la tabella da visualizzare
frequenze_sales_class %>%
kbl(caption = "Distribuzione di frequenza delle Classi della variabile Sales",
align = "c",
booktabs = TRUE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = TRUE,
font_size = 14)
| sales_class | Frequenza | Frequenza_percentuale |
|---|---|---|
| [0,100) | 20 | 8.33 |
| [100,200) | 127 | 52.92 |
| [200,300) | 67 | 27.92 |
| [300,400) | 23 | 9.58 |
| [400,500] | 3 | 1.25 |
index_gini_sales_class <- round( gini.index(df$sales_class) ,2)
L’indice di GINI per la variabile sales_class è 0.78 questo indica una concentrazione nella distribuzione delle classi, ovvero una classe o poche classi pesano più delle altre. Come si può osservare nella tabella “Distribuzione di frequenza delle Classi della variabile Sales” la classe 100,200 ha 127 occorrenze, corrispondente al 52.92% del totale.
# grafico a barre per la variabile sales_class
df %>%
count(sales_class) %>%
mutate(perc = round(n / sum(n) * 100, 1)) %>%
ggplot(aes(x = sales_class, y = perc)) +
geom_col() +
geom_text(aes(label = paste0(perc, "%")), vjust = -0.5) +
theme_minimal() +
labs(
title = "Distribuzione % delle Classi di Sales",
x = "Classi di Sales",
y = "Percentuale"
) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
# Calcolo della probabilità
# utilizzando la formalura -> numero di osservazioni con filtro (city = Beaumont o month = 7) diviso il numero totale delle osservazioni moltiplicato per 100 per avere il valore in percentuale
p_beaumont <- round((sum(df$city == "Beaumont") / nrow(df)) * 100,2)
p_luglio <- round((sum(df$month == 7) / nrow(df))* 100,2)
p_dicembre_2012 <- round((sum(df$month == 12 & df$year == 2012) / nrow(df))* 100,2)
La probabilità che preso un record a caso del dataset esso riporti:
la città di Beaumont è del 25%
Il mese di Luglio è dell’8.33%
Il mese di dicembre dell’anno 2012 è dell’1.67%
# crea nuova variabile mean_price in questo modo: dividendo il volume totale per il numero di vendite (volume / sales). Poiché 'volume' è espresso in milioni di dollari, lo moltiplichiamo per 1000000 per ottenere il valore in dollari prima della divisione.
df$mean_price <- (df$volume * 1000000) / df$sales
# calcola il minimo e il massimo della variabile mean_price
min_mean_price <- round( min(df$mean_price),2)
max_mean_price <- round( max(df$mean_price),2)
# estrae la città con il minimo mean_price ed il massimo mean_price, è stata usata la funzione slice per estrarre solo la prima città
city_min_mean_price <- df %>% filter(mean_price == min(mean_price)) %>% slice(1) %>% pull(city)
city_max_mean_price <- df %>% filter(mean_price == max(mean_price)) %>% slice(1) %>% pull(city)
il prezzo medio minore del dataset è di 97010.2 per la città di Wichita Falls
il prezzo medio maggiore del dataset è 213233.94 per la città di Bryan-College Station
#efficacia annunci
# crea nuova variabile listing_performance in questo modo: immobili venduti (sales) / immobili in listino (listings)
df <- df %>%
mutate(listing_performance = round(sales / listings, 2))
#listing_performance_percent, viene calcolata l'efficacia annunci in percentuale
df <- df %>%
mutate(listing_performance_percent = round((sales / listings) * 100, 2))
min_listing_performance <- min(df$listing_performance)
max_listing_performance <- max(df$listing_performance)
# estrae la città con il minimo listing_performance_percent ed il massimo listing_performance_percent, è stata usata la funzione slice per estrarre solo la prima città
city_min_listing_performance_perc <- df %>% filter(listing_performance_percent == min(listing_performance_percent)) %>% slice(1) %>% pull(city)
city_max_listing_performance_perc <- df %>% filter(listing_performance_percent == max(listing_performance_percent)) %>% slice(1) %>% pull(city)
min_listing_performance_perc <- min(df$listing_performance_percent)
max_listing_performance_perc <- max(df$listing_performance_percent)
la città con la più bassa efficacia degli annuncci è Tyler con un valore del 5.01%
la città con la più alta efficacia degli annuncci è Bryan-College Station con un valore del 38.71%
#utilizzando il pacchetto dplyr viene calcolata una summary statistica per le città, le varibili calcolate sono: la media del prezzo medio media_mean_price, la deviazione standard del prezzo medio sd_mean_price, la media delle vendite media_sales, la deviazione standard delle vendite sd_sales
summary_stats_city <- df %>%
group_by(city) %>%
summarise(
media_mean_price = mean(mean_price, na.rm = TRUE),
sd_mean_price = sd(mean_price, na.rm = TRUE),
media_sales = mean(sales, na.rm = TRUE),
sd_sales = sd(sales, na.rm = TRUE),
.groups = "drop"
)
#tabella per summary statistico delle città
summary_stats_city %>%
kbl(caption = "Summary Statistico delle città",
align = "c",
booktabs = TRUE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
font_size = 14)
| city | media_mean_price | sd_mean_price | media_sales | sd_sales |
|---|---|---|---|---|
| Beaumont | 146640.4 | 11232.13 | 177.3833 | 41.48395 |
| Bryan-College Station | 183534.3 | 15149.35 | 205.9667 | 84.98374 |
| Tyler | 167676.8 | 12350.51 | 269.7500 | 61.96380 |
| Wichita Falls | 119430.0 | 11398.48 | 116.0667 | 22.15192 |
# tramite la libreria ggplot2 viene creato il grafico per media_mean_price e ordinato per media_mean_price, viene usata la funzione geom_errorbar per creare le linee nere che rappresentano la variabilità dei dati ed è così calcolata: il minimo (ymin) media_mean_price - sd_mean_pric; il massimo (ymax) media_mean_price + sd_mean_price
ggplot(summary_stats_city, aes(x = reorder(city, media_mean_price), y = media_mean_price)) +
geom_col(fill = "lightblue") +
geom_errorbar(aes(ymin = media_mean_price - sd_mean_price,
ymax = media_mean_price + sd_mean_price),
width = 0.2, color = "black") +
theme_minimal() +
coord_flip() +
labs(
title = "Media del Prezzo Medio per Città con Deviazione Standard",
x = "Città",
y = "Media del prezzo medio"
)
Le barre azzurre rappresentano la media del prezzo medio per ogni città; le linee nere mostrano di quanto i prezzi possono variare rispetto alla media.
Bryan-College Station ha la media del prezzo medio delle case più alto, mentre Wichita Falls ha il più basso. La barra di errore più lunga di Bryan-College Station indica una deviazione standard maggiore, quindi i prezzi in questa città sono più dispersi e meno concentrati attorno alla media rispetto a Beaumont, Tyler e Wichita Falls.
# grafico di Sales per City, media e deviazione standard
ggplot(summary_stats_city, aes(x = reorder(city, media_sales), y = media_sales)) +
geom_col(fill = "lightblue") +
geom_errorbar(aes(ymin = media_sales - sd_sales,
ymax = media_sales + sd_sales),
width = 0.2, color = "black") +
theme_minimal() +
coord_flip() +
labs(
title = "Media delle Vendite per Città con Deviazione Standard",
x = "Città",
y = "Media delle Vendite"
)
Le barre azzurre rappresentano la media delle vendite per ogni città; le linee nere mostrano di quanto le vendite possono variare rispetto alla media.
Tyler ha la media delle vendite più alta di tutte le città con un valore di 269.75 mentre Wichita Falls ha la media delle vendite più bassa di tutte le città. La deviazione standard di Bryan-College Station è la maggiore e denota una variabilità maggiore nelle vendite mentre quella più bassa è di Wichita Falls che indica una maggiore stabilità nel numero delle vendite
#utilizzando il pacchetto dplyr viene calcolata una summary statistica per year, le varibili calcolate sono: la media del prezzo medio media_mean_price, la deviazione standard del prezzo medio sd_mean_price, la media delle vendite media_sales, la deviazione standard delle vendite sd_sales
summary_stats_year <- df %>%
group_by(year) %>%
summarise(
media_mean_price = mean(mean_price, na.rm = TRUE),
sd_mean_price = sd(mean_price, na.rm = TRUE),
media_sales = mean(sales, na.rm = TRUE),
sd_sales = sd(sales, na.rm = TRUE),
.groups = "drop"
)
#tabella per summary statistico per Year
summary_stats_year %>%
kbl(caption = "Summary Statistico per Anno",
align = "c",
booktabs = TRUE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
font_size = 14)
| year | media_mean_price | sd_mean_price | media_sales | sd_sales |
|---|---|---|---|---|
| 2010 | 150188.6 | 23279.55 | 168.6667 | 60.53708 |
| 2011 | 148250.6 | 24938.38 | 164.1250 | 63.87042 |
| 2012 | 150898.7 | 26438.50 | 186.1458 | 70.90509 |
| 2013 | 158705.2 | 26523.81 | 211.9167 | 83.99641 |
| 2014 | 163558.7 | 31740.53 | 230.6042 | 95.51490 |
# tramite la libreria ggplot2 viene creato il grafico per media_mean_price, viene usata la funzione geom_errorbar per creare le linee nere che rappresentano la variabilità dei dati ed è così calcolata: il minimo (ymin) media_mean_price - sd_mean_pric; il massimo (ymax) media_mean_price + sd_mean_price
ggplot(summary_stats_year, aes(x = year, y = media_mean_price)) +
geom_col(fill = "lightblue") +
geom_errorbar(aes(ymin = media_mean_price - sd_mean_price,
ymax = media_mean_price + sd_mean_price),
width = 0.2, color = "black") +
theme_minimal() +
coord_flip() +
labs(
title = "Media del Prezzo Medio per Anno con Deviazione Standard",
x = "Anno",
y = "Media del prezzo medio"
)
Le barre azzurre rappresentano la media del prezzo medio per ogni anno; le linee nere mostrano di quanto i prezzi possono variare rispetto alla media.
Dal 2010 al 2014, si osserva una crescita costante del prezzo medio delle case e della deviazione standard.
# grafico di Sales per Year, media e deviazione standard
ggplot(summary_stats_year, aes(x = year, y = media_sales)) +
geom_col(fill = "lightblue") +
geom_errorbar(aes(ymin = media_sales - sd_sales,
ymax = media_sales + sd_sales),
width = 0.2, color = "black") +
theme_minimal() +
coord_flip() +
labs(
title = "Media delle Vendite per Anno con Deviazione Standard",
x = "Anno",
y = "Media delle Vendite"
)
Le barre azzurre rappresentano la media delle vendite per ogni anno; le linee nere mostrano di quanto le vendite possono variare rispetto alla media.
Anche per le vendite si osserva una crescita costante nel periodo analizzato; il valore più alto della deviazione standard si registra nel 2014, il che suggerisce che il numero di case vendute ha mostrato maggiori fluttuazioni rispetto agli anni precedenti.
#utilizzando il pacchetto dplyr viene calcolata una summary statistica per month, le varibili calcolate sono: la media del prezzo medio media_mean_price, la deviazione standard del prezzo medio sd_mean_price, la media delle vendite media_sales, la deviazione standard delle vendite sd_sales
summary_stats_month <- df %>%
group_by(month) %>%
summarise(
media_mean_price = mean(mean_price, na.rm = TRUE),
sd_mean_price = sd(mean_price, na.rm = TRUE),
media_sales = mean(sales, na.rm = TRUE),
sd_sales = sd(sales, na.rm = TRUE),
.groups = "drop"
)
#tabella per summary statistico per Year
summary_stats_month %>%
kbl(caption = "Summary Statistico per Mese",
align = "c",
booktabs = TRUE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
font_size = 14)
| month | media_mean_price | sd_mean_price | media_sales | sd_sales |
|---|---|---|---|---|
| 1 | 145640.4 | 29819.11 | 127.40 | 43.38372 |
| 2 | 148840.5 | 25120.42 | 140.85 | 51.06783 |
| 3 | 151136.5 | 23237.92 | 189.45 | 59.17812 |
| 4 | 151461.3 | 26174.30 | 211.70 | 65.40489 |
| 5 | 158235.0 | 25787.19 | 238.85 | 83.11582 |
| 6 | 161545.8 | 23470.46 | 243.55 | 94.99832 |
| 7 | 156881.0 | 27220.12 | 235.75 | 96.27421 |
| 8 | 156455.6 | 28253.21 | 231.45 | 79.22883 |
| 9 | 156522.3 | 29669.41 | 182.35 | 72.51807 |
| 10 | 155897.4 | 32527.29 | 179.90 | 74.95395 |
| 11 | 154233.0 | 29684.87 | 156.85 | 55.46670 |
| 12 | 154995.5 | 27008.87 | 169.40 | 60.74658 |
# tramite la libreria ggplot2 viene creato il grafico per media_mean_price, viene usata la funzione geom_errorbar per creare le linee nere che rappresentano la variabilità dei dati ed è così calcolata: il minimo (ymin) media_mean_price - sd_mean_pric; il massimo (ymax) media_mean_price + sd_mean_price
#in questi due grafici viene usata la funzione scale_x_continuous per gestire la variabile month perchè ggplot2 mette automaticamente nell'asse delle x valori tipo 2,5 o 7,5 invece per la variabile month i valori devono essere quelli presenti nella tabella
ggplot(summary_stats_month, aes(x = month, y = media_mean_price)) +
geom_col(fill = "lightblue") +
geom_errorbar(aes(ymin = media_mean_price - sd_mean_price,
ymax = media_mean_price + sd_mean_price),
width = 0.2, color = "black") +
scale_x_continuous(breaks = summary_stats_month$month) +
theme_minimal() +
coord_flip() +
labs(
title = "Media del Prezzo Medio per Mese con Deviazione Standard",
x = "Mese",
y = "Media del prezzo medio"
)
Le barre azzurre rappresentano la media del prezzo medio per ogni mese; le linee nere mostrano di quanto i prezzi possono variare rispetto alla media.
L’analisi per mesi evidenzia una stagionalità dei prezzi di vendita, con prezzi alti nei mesi estivi e prezzi bassi nei mesi invernali come Gennaio e Febbraio mentre la deviazione standard non segue questo andamento infatti i valori più alti si registrano nei mesi autunnali ed invernali.
# grafico di Sales per Month, media e deviazione standard
ggplot(summary_stats_month, aes(x = month, y = media_sales)) +
geom_col(fill = "lightblue") +
geom_errorbar(aes(ymin = media_sales - sd_sales,
ymax = media_sales + sd_sales),
width = 0.2, color = "black") +
scale_x_continuous(breaks = summary_stats_month$month) +
theme_minimal() +
coord_flip() +
labs(
title = "Media delle Vendite per Mese con Deviazione Standard",
x = "Mese",
y = "Media delle Vendite"
)
Le barre azzurre rappresentano la media delle vendite per ogni mese; le linee nere mostrano di quanto le vendite possono variare rispetto alla media.
L’analisi per mesi evidenzia una stagionalità delle vendite, con numero di vendite alte nei mesi estivi e numero di vendite basse nei mesi invernali come Gennaio e Febbraio anche la deviazione standard segue questo andamento con valori alti nei mesi estivi.
ggplot2 per creare grafici personalizzati.
Assicurati di esplorare: - Boxplot per confrontare la distribuzione del
prezzo mediano tra le città. - Grafici a barre per confrontare il totale
delle vendite per mese e città. - Line charts per confrontare
l’andamento delle vendite in periodi storici differenti.# 1 boxplot per confrontare la distribuzione del prezzo mediano tra le varie città , fill = city
ggplot(df, aes(x = city, y = median_price)) +
geom_boxplot() +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(
title = "Distribuzione del prezzo mediano per città",
x = "Città",
y = "Prezzo Mediano",
fill = "Città"
)
Prezzi più alti: Bryan-College Station ha i prezzi mediani più elevati, con valori che si aggirano intorno ai 150.000-160.000 $.
Prezzi intermedi: Tyler mostra prezzi leggermente inferiori rispetto a Bryan-College Station, con una mediana intorno ai 140.000 $ e una distribuzione abbastanza ampia.
Prezzi più bassi: Beaumont ha prezzi poco più bassi, con una mediana di circa 130.000 $. Wichita Falls presenta i prezzi più bassi del gruppo, con una mediana intorno ai 100.000 $.
Variabilità: Bryan-College Station e Tyler mostrano una maggiore variabilità nei prezzi (box più ampie), mentre Beaumont e Wichita Falls hanno delle distribuzioni più concentrate.
Outliers: Si possono notare alcuni valori anomali a Bryan-College Station e a Wichita Falls.
Il grafico suggerisce la presenza di differenze importanti nel mercato immobiliare tra le città prese in esame.
# 2 distribuzione delle vendite tra le varie città e anni
# 2-1 Boxplot per confronto tra città , fill = city
ggplot(df, aes(x = city, y = sales)) +
geom_boxplot(alpha = 0.7) +
labs(title = "Distribuzione valore vendite per città",
x = "Città",
y = "Sales") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none")
Tyler al top: ha la mediana più alta (intorno a 275) e la seconda distribuzione più ampia. È il mercato più forte, con vendite che possono arrivare oltre 400.
Bryan-College Station interessante: ha una mediana più bassa di Tyler (circa 190), ma una distribuzione più ampia.
Beaumont stabile: ha una mediana intorno a 175 con una distribuzione meno ampia rispetto alle precedenti.
Wichita Falls ultima: ha una mediana bassa (circa 120) ed una distribuzione ristretta. È chiaramente il mercato più piccolo.
Variabilità: Tyler e Bryan-College Station hanno molta più variabilità nelle vendite rispetto a Beaumont e Wichita Falls
# 2-4 anni per ogni città
ggplot(df, aes(x = as.factor(year), y = sales)) +
geom_boxplot(alpha = 0.7) +
facet_wrap(~city, ncol = 2) +
labs(title = "Distribuzione valore vendite per anno e città",
x = "Anno",
y = "Sales") +
theme_minimal() +
theme(legend.position = "none")
Beaumont: rappresenta il mercato più stabile, con una mediana che, nel corso degli anni, resta sempre con valori intorno a 175-200.
Bryan-College Station: nel 2010-2011 ha un mercato stabile; nel 2012, pur con una mediana stabile rispetto agli anni precedenti si osserva un’ampia distribuzione verso l’alto che culmina nel 2014 con un notevole aumento anche della mediana.
Tyler: Cresce costantemente dal 2010 al 2014, raggiungendo il picco nel 2014 con mediana intorno a 340.
Wichita Falls: è sicuramente il mercato più piccolo, con valori di mediana sempre inferiori a 150 con il minimo raggiunto nel 2014.
# 3 grafico a barre sovrapposte per confrontare il totale delle vendite nei vari mesi
df %>%
group_by(month, city) %>% # Raggruppa per mese e città
summarise(total_sales = sum(sales, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = factor(month), y = total_sales, fill = city)) +
geom_bar(stat = "identity") +
labs(
title = "Totale Vendite per mese per città",
x = "Mese",
y = "Totale vendite",
fill = "Città"
) +
theme_minimal()
Il boom della primavera-estate: i mesi di maggio, giugno, luglio e agosto sono chiaramente i migliori, con vendite totali che superano le 4.500 unità, con giugno che rappresenta l’apice della crescita.
Autunno in calo: a partire dal mese di settembre si ha un calo progressivo delle vendite che culmina a novembre.
L’inverno è duro: i mesi invernali, in particolare gennaio e febbraio, sono i mesi più deboli, con vendite sotto le 3.000 unità.
È interessante vedere come tutte le città seguano lo stesso pattern stagionale, ma Tyler e Bryan-College Station amplificano molto di più l’effetto estate-inverno.
df %>%
group_by(month, city,year) %>%
summarise(total_sales = sum(sales, na.rm = TRUE), .groups = 'drop') %>%
group_by(month,year) %>%
mutate(perc_sales = total_sales / sum(total_sales)) %>%
ggplot(aes(x = factor(month), y = perc_sales, fill = city)) +
geom_bar(stat = "identity", position = "fill") +
labs(
title = "Distribuzione percentuale delle vendite per mese e città",
x = "Mese",
y = "Percentuale vendite",
fill = "Città"
) +
scale_y_continuous(labels = scales::percent) +
theme_minimal()
Beaumont costante: La fascia rossa è rappresentata in modo stabile nel corso dell’anno.
Bryan-College Station tiene bene: La fascia verde è ben rappresentata particolarmente nei mesi estivi, indice che questa città contribuisce notevolmente al totale delle vendite.
Tyler domina sempre: La fascia azzurra è la più ampia ogni mese, confermando che è il mercato più forte durante tutto l’anno.
Wichita Falls sempre piccola: La fascia viola è la meno rappresentata, confermando che è il mercato più piccolo.
#Efficacia percentuale nel tempo è stato utilizzato questo as.Date(paste(year, month, "01", sep = "-")) per creare un asse delle x con mese-anno, è stato utilizzato scale_x_date per migliorre la visualizzazione dei dati e mettere un break ogni 3 mesi altrimenti le osservazioni erano troppo sovrapposte
df %>%
mutate(date = as.Date(paste(year, month, "01", sep = "-"))) %>%
group_by(date, city) %>%
summarise(media_eff = mean(listing_performance_percent, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = date, y = media_eff, color = city)) +
geom_line(linewidth = 1) +
scale_x_date(
date_labels = "%b %Y",
date_breaks = "3 months" # una label ogni tre mesi
) +
labs(
title = "Efficacia percentuale nel tempo per città",
x = "Mese - Anno",
y = "Efficacia (%)",
color = "Città"
) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Beaumont mostra una lieve flessione nell’efficacia nel 2011 per poi cresce costantemente fino al 2014;
Bryan-College Station ha avuto un picco di crescita a partire dal 2012 arrivando a superare il 20% nel 2014, rappresentando la città con l’efficacia migliore;
Tyler rappresenta una crescita dell’efficacia costante pur rimanendo con la percentuale di efficacia minore;
Wichita Falls ha un andamento altalenante, tuttavia i valori iniziali e finali sono simili mostrando una buona efficacia.
# la variabile sales nel tempo
#media_sales nel tempo è stato utilizzato questo as.Date(paste(year, month, "01", sep = "-")) per creare un asse delle x con mese-anno, è stato utilizzato scale_x_date per migliorre la visualizzazione dei dati e mettere un break ogni 3 mesi altrimenti le osservazioni erano troppo sovrapposte
df %>%
mutate(date = as.Date(paste(year, month, "01", sep = "-"))) %>%
group_by(date, city) %>%
summarise(media_sales = mean(sales, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = date, y = media_sales, color = city)) +
geom_line(linewidth = 1) +
scale_x_date(
date_labels = "%b %Y",
date_breaks = "3 months" # una label ogni tre mesi
) +
labs(
title = "Andamento delle vendite negli anni",
x = "Mese - Anno",
y = "Vendite",
color = "Città"
) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
#dato che si è evidenziato un andamento stagionale delle vendite è stata aggiunta al dataset la variabile season calcolata in questo modo
df <- df %>%
mutate(season = case_when(
month %in% c(12, 1, 2) ~ "Winter",
month %in% c(3, 4, 5) ~ "Spring",
month %in% c(6, 7, 8) ~ "Summer",
month %in% c(9, 10, 11) ~ "Autumn"
))
df %>%
group_by(season, year) %>%
summarise(mean_sales = mean(sales, na.rm = TRUE), .groups = 'drop') %>%
ggplot(aes(x = season, y = mean_sales, color = factor(year), group = year)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
theme_minimal() +
labs(
title = "Vendite medie stagionali per anno",
x = "Stagione",
y = "Vendite medie",
color = "Anno"
)
Autunno e primavera le mezze stagioni: queste due stagioni hanno vendite simili, con la primavera che presenta vendite leggermente più alte.
Estate al primo posto: l’estate è chiaramente la stagione con più vendite, raggiungendo i picchi più alti soprattutto nel 2013 e 2014.
Inverno fanalino di coda: l’inverno è la stagione con vendite minori in tutti gli anni considerati.
Nel tempo: analizzando l’andamento delle vendite nel corso degli anni si nota una progressiva crescita dal 2011 con culmine nel 2014 in tutte le stagioni.
Dall’analisi dei grafici emerge un quadro interessante del mercato immobiliare delle quattro città studiate.
Bryan-College Station è il mercato più promettente: mostra un netto miglioramento nell’efficacia delle vendite con i prezzi più elevati.
Tyler conferma la promessa iniziale con una crescita costante con elevati valori di vendite.
Beaumont si posiziona in una fascia intermedia, con una crescita più lenta ma costante.
Wichita Falls presenta i valori più contenuti sia in termini di vendite che di prezzi.
Il dato più rilevante riguarda l’efficacia commerciale: anche se i tassi di conversione da annuncio a vendita sono generalmente bassi in tutte le città, si osservano miglioramenti per Beaumont e Tyler e un boom per quanto riguarda Bryan-College Station.
Investire in Bryan-College Station: l’aumento di efficacia suggerisce una dinamica favorevole.
Rafforzare le strategie di marketing per i mesi invernali su tutte le città.
Sfruttare i mesi estivi con campagne mirate, poiché è il periodo di picco per tutte le città.