library(ggplot2)
library(dplyr)
##
## Caricamento pacchetto: 'dplyr'
## I seguenti oggetti sono mascherati da 'package:stats':
##
## filter, lag
## I seguenti oggetti sono mascherati da 'package:base':
##
## intersect, setdiff, setequal, union
library(moments)
library(knitr)
dataset <- read.csv("realestate_texas.csv",sep = ",", fileEncoding = "latin1")
summary(dataset)
## city year month sales
## Length:240 Min. :2010 Min. : 1.00 Min. : 79.0
## Class :character 1st Qu.:2011 1st Qu.: 3.75 1st Qu.:127.0
## Mode :character Median :2012 Median : 6.50 Median :175.5
## Mean :2012 Mean : 6.50 Mean :192.3
## 3rd Qu.:2013 3rd Qu.: 9.25 3rd Qu.:247.0
## Max. :2014 Max. :12.00 Max. :423.0
## volume median_price listings months_inventory
## Min. : 8.166 Min. : 73800 Min. : 743 Min. : 3.400
## 1st Qu.:17.660 1st Qu.:117300 1st Qu.:1026 1st Qu.: 7.800
## Median :27.062 Median :134500 Median :1618 Median : 8.950
## Mean :31.005 Mean :132665 Mean :1738 Mean : 9.193
## 3rd Qu.:40.893 3rd Qu.:150050 3rd Qu.:2056 3rd Qu.:10.950
## Max. :83.547 Max. :180000 Max. :3296 Max. :14.900
attach(dataset)
Il dataset contiene le seguenti variabili:
E’ possibile analizzare i comportamenti delle variabili quantitative per produrre valutazioni sulla efficacia di vendita, sia impostare una confronto temporale su:
Tabulo i valori medi per le variabili continue sales, volume, median_price, listings e months_inventory Ho mantenuto la divisione per City e creato la colonna Saled (che è il totale di vendite nel quinquennio) come indice di confronto della dimensione di attività per ogni città
data_x_city <- dataset %>%
group_by(city)%>%
summarise(saled = sum(sales),
media_sales = mean(sales),
media_volume= mean(volume),
media_median_price = mean(median_price),
media_annunounc = mean(listings),
media_time = mean(months_inventory))
knitr::kable(head(data_x_city))
| city | saled | media_sales | media_volume | media_median_price | media_annunounc | media_time |
|---|---|---|---|---|---|---|
| Beaumont | 10643 | 177.3833 | 26.13160 | 129988.3 | 1679.3167 | 9.970000 |
| Bryan-College Station | 12358 | 205.9667 | 38.19160 | 157488.3 | 1458.1333 | 7.658333 |
| Tyler | 16185 | 269.7500 | 45.76738 | 141441.7 | 2905.0500 | 11.325000 |
| Wichita Falls | 6964 | 116.0667 | 13.93017 | 101743.3 | 909.5833 | 7.816667 |
Tabulo i valori di range e deviazione standard per sales, volume, median_price, listings e months_inventory raggruppate per città
variabilità_x_city <- dataset %>%
group_by(city)%>%
summarise(range_sales = max(sales)-min(sales),
dev_std_sales = sd(sales),
range_volume = max(volume)-min(volume),
dev_std_volume = sd(volume),
range_median_price = max(median_price)-min(median_price),
dev_std_price = sd(median_price),
range_listings = max(listings)-min(listings),
dev_std_listings = sd(listings),
range_time = max(months_inventory)-min(months_inventory),
dev_std_time = sd(months_inventory)
)
knitr::kable(head(variabilità_x_city))
| city | range_sales | dev_std_sales | range_volume | dev_std_volume | range_median_price | dev_std_price | range_listings | dev_std_listings | range_time | dev_std_time |
|---|---|---|---|---|---|---|---|---|---|---|
| Beaumont | 190 | 41.48395 | 28.532 | 6.970384 | 57100 | 10104.993 | 357 | 91.13382 | 5.6 | 1.6495814 |
| Bryan-College Station | 314 | 84.98374 | 68.396 | 17.248577 | 39300 | 8852.235 | 1102 | 252.52753 | 8.2 | 2.2472048 |
| Tyler | 280 | 61.96380 | 59.764 | 13.107146 | 41000 | 9336.538 | 1024 | 226.75458 | 8.0 | 1.8864032 |
| Wichita Falls | 88 | 22.15192 | 12.715 | 3.239766 | 61500 | 11320.034 | 309 | 73.75504 | 3.3 | 0.7809526 |
Tabulo i valori di range e deviazione standard per sales, volume, median_price, listings e months_inventory TOTALI
variabilità_tot <- dataset %>%
summarise(dev_std_sales = sd(sales),
dev_std_volume = sd(volume),
dev_std_price = sd(median_price),
dev_std_listings = sd(listings),
dev_std_time = sd(months_inventory))
knitr::kable(head(variabilità_tot))
| dev_std_sales | dev_std_volume | dev_std_price | dev_std_listings | dev_std_time |
|---|---|---|---|---|
| 79.65111 | 16.65145 | 22662.15 | 752.7078 | 2.303669 |
Tabulo i valori di asimmetria con l’indice di Skewness
asimmetria_tot <- dataset %>%
summarise(asim_sales = skewness(sales),
asim_volume = skewness(volume),
asim_price = skewness(median_price),
asim_listings = skewness(listings),
asim_time = skewness(months_inventory))
I valori della deviazione standard mostrano che i valori del median_price sono quelli con maggior variabilità (sd = 22662.15), mentre quelli di months_inventiry sono quelli con minore variabilità (sd = 2.30) Nel raggruppamento per city si vede che all’interno della variabile median_price la città di Wichita Falls ha massima variabilità (sd = 11320.034), mentre Bryan-College Station ha minor variabilità (sd = 8852.235). I dati riguardanti le asimmetrie delle distribuzioni mostrano una massima simmetria per i dati di months_inventory (skewness = 0.04), e massima asimmetria per volume (skewness = 0.88).
Complessivamente la distribuzione di months_inventory è quella più simmetrica e con minor variabilità.
dataset$date <- as.Date(paste(dataset$year, dataset$month, 1, sep = "-")) #aggiunge una colonna data con date in ordine cronologico per tutti i 5 anni in esame
Divido la variabile Sales in classi trimestrali, mantendo il raggruppamento per city
dataset_trim <- dataset %>%
select(city, month, sales) %>%
mutate(
trim = paste0(ceiling(month / 3))
) %>%
group_by(city, trim) %>%
summarise(trimestral_sales = sum(sales), .groups = "drop") %>%
left_join(
dataset %>%
group_by(city) %>%
summarise(total_sales = sum(sales), .groups = "drop"),
by = "city"
) %>%
mutate(
perc_on_total = round(trimestral_sales / total_sales * 100, 2)
)
knitr::kable(head(dataset_trim))
| city | trim | trimestral_sales | total_sales | perc_on_total |
|---|---|---|---|---|
| Beaumont | 1 | 2140 | 10643 | 20.11 |
| Beaumont | 2 | 3007 | 10643 | 28.25 |
| Beaumont | 3 | 2884 | 10643 | 27.10 |
| Beaumont | 4 | 2612 | 10643 | 24.54 |
| Bryan-College Station | 1 | 2168 | 12358 | 17.54 |
| Bryan-College Station | 2 | 4287 | 12358 | 34.69 |
Il grafico a barre rappresenta l’andamento nei 4 trimestri per ogni città, considerando i dati cumulati dell’intero quinquennio
ggplot(dataset_trim, aes(x = trim, y = trimestral_sales, fill = city)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Trimestre", y = "Vendite Trimestrali", fill = "Città", title = "Dati di vendite trimestrali nel quinquennio in analisi") +
theme_minimal()
Dal grafico si può osservare come in ogni città vi sia un trend differenziato nei trimestri, con il due trimestri centrali con più vendite Nel dataframe dataset_trim la colonna perc_on total indica i valori percentuali di ogni trimestre sul totale di vendite per città
Il trend differenziato tra i mesi si può osservare anche cumulando le vendite di tutte le città
total_dataset_monthly <- dataset %>%
select(month, sales) %>%
group_by(month) %>%
summarise(
monthly_sales = sum(sales),
.groups = "drop"
)
knitr::kable(head(total_dataset_monthly))
| month | monthly_sales |
|---|---|
| 1 | 2548 |
| 2 | 2817 |
| 3 | 3789 |
| 4 | 4234 |
| 5 | 4777 |
| 6 | 4871 |
ggplot(total_dataset_monthly, aes(x = month, y = monthly_sales)) +
geom_bar(stat = "identity", fill = "light blue", col = "blue") +
labs(x = "Mesi", y = "Vendite Mensili", title = "Dati complessivi di vendite mensili nel quinquennio in analisi") +
scale_x_continuous(breaks = seq(0,12,1))+
theme_minimal()
Dal grafico a barre si può immediatamente vedere la variazione di vendite nei differenti mesi (dati complessivi del quinquennio in analisi)
Funzione per calcolo indice di etereogenità di gini
gini <- function(x){
freq_ass = table(x)
freq_rel = freq_ass/sum(freq_ass)
gini <- 1- sum(freq_rel^2)
return(gini)
}
Su questo dataset calcolo gli indici di simmetria, variabilità ed etereogenità
index_monthly <- total_dataset_monthly %>%
reframe(v_medio = mean(monthly_sales),
v_median = median(monthly_sales),
dev= sd(monthly_sales),
asim= skewness(monthly_sales),
k = kurtosis(monthly_sales)-3,
gini = gini(monthly_sales))
knitr::kable(head(index_monthly))
| v_medio | v_median | dev | asim | k | gini |
|---|---|---|---|---|---|
| 3845.833 | 3718 | 797.5316 | -0.1254432 | -1.263172 | 0.9166667 |
I dati di index_monthly mostrano una distribuzione con deviazione stnd piuttosto alta, quindi disordinati rispetto al valore medio con un indice di simmetria basso (-0.12), quindi una buona simmetria un indice di curtosi negativo che rappresenta una distribuzione platicurtica (cioè più appiattita) e un coefficiente di gini vicino a 1, per cui una distribuzione disomogenea
Probabilità città di Beaumont
freq_city <- table(city)/sum(table(city))*100
La probabilià è del 25% per ogni città
Probabilità mese di luglio
freq_month <- table(month)/sum(table(month))*100
la probabilità è dell’8,33% (1/12) per ogni mese
Probabilità per dicembre 2012
freq_month_year <- table(year, month)/sum(table(year, month))*100
la probabilità è del 1,67% per ogni misura condizionata di mese e anno
Il calcolo del prezzo medio è derivato dal rapporto tra volume totale di vendite (in $) e il numero di vendite
mean_price <- dataset %>%
group_by(city, year, month, median_price)%>%
reframe(
mean_price = volume/sales*(10^6),
rate = mean_price/median_price,
notes = case_when(
rate > 1 ~ "asim positiva",
rate < 1 ~ "asim negativa",
near(rate, 1) ~ "simmetria"
)
)
knitr::kable(head(mean_price, 5))
| city | year | month | median_price | mean_price | rate | notes |
|---|---|---|---|---|---|---|
| Beaumont | 2010 | 1 | 163800 | 170626.5 | 1.041676 | asim positiva |
| Beaumont | 2010 | 2 | 138200 | 163796.3 | 1.185212 | asim positiva |
| Beaumont | 2010 | 3 | 122400 | 157697.8 | 1.288381 | asim positiva |
| Beaumont | 2010 | 4 | 123200 | 134095.0 | 1.088433 | asim positiva |
| Beaumont | 2010 | 5 | 123100 | 142737.6 | 1.159526 | asim positiva |
Ho aggiunto la colonna notes per commentare se i dati relativi a prezzo medio e mediano per ogni trimestre evidenziassero una asimmetria Essendo il prezzo medio maggiore del prezzo mediano in tutte le rilevazioni tranne una (Beaumont, novembre 2010), si può valutare che la distribuzione dei prezzi delle case abbia una asimmetria con code lunghe vero prezzi più alti
Efficacia annunci di vendita
Dalla tabella table_efficiency si vede il trend trimestrale per città di variazione di efficacia di vendita su numero di annunci
table_efficiency <- dataset %>%
mutate(city = factor(city, levels = sort(unique(city)))) %>%
arrange(year, city) %>%
mutate(
trim = paste0(ceiling(month / 3)),
middle_step = sales/listings,
) %>%
group_by(city, year, trim) %>%
reframe(
sales_anno = sum(sales),
listings_anno = sum(listings),
year_inventory = sum(months_inventory),
efficiency_listings = sales_anno/listings_anno*100,
weighted_efficiency_listings = sum(middle_step*months_inventory)/sum(months_inventory)*100
) %>%
ungroup()
Un coefficiente in grado di esprimere l’efficacia delle politiche di vendita può essere dato dal rapporto percentuale tra vendite e annunci. Ho provato a considerare una media del rapporto vendite/annunci pesata sul tempo months_inventory, ma la variazione non è apprezzabile nè maggiormente indicativa
table_efficiency$month_trim <- (as.numeric(table_efficiency$trim)) * 3
table_efficiency$date <- as.Date(paste(table_efficiency$year, table_efficiency$month_trim, 1, sep = "-"))
ggplot(table_efficiency, aes(x= date, y = efficiency_listings, color = city))+
geom_line()+
labs( x = "data", y = "efficienza % di vendita", title = "Andamento coefficente di efficacia" )
Dal grafico si può osservare anche un trand di miglioramento del coefficiente di efficacia all’interno del quinquennio in ogni città in analisi.
La tabella efficiency_skewness evidenzia i valori medi di efficienza e efficienza pesata per tutte le città. I ceoefficienti di skewness positivi indicano un allungamento della distribuzione verso valori più alti, quindi una misura differente di quanto era osservabile nel grafico precedente.
efficiency_skewness <- table_efficiency %>%
group_by(city)%>%
summarise(
mean(efficiency_listings),
skewness(efficiency_listings),
mean(weighted_efficiency_listings),
skewness(weighted_efficiency_listings)
)
knitr::kable(head(efficiency_skewness))
| city | mean(efficiency_listings) | skewness(efficiency_listings) | mean(weighted_efficiency_listings) | skewness(weighted_efficiency_listings) |
|---|---|---|---|---|
| Beaumont | 10.615742 | 0.3366012 | 10.612259 | 0.3391820 |
| Bryan-College Station | 14.735769 | 0.8760285 | 14.728776 | 0.8810173 |
| Tyler | 9.352381 | 0.6108735 | 9.349529 | 0.6077307 |
| Wichita Falls | 12.797652 | 0.7351822 | 12.790734 | 0.7504676 |
Studio la variazione nelle proporzioni di vendita nei differenti anni tra le città
vendite_per_citta_anno <- dataset %>%
group_by(year, city) %>%
reframe(
tot_vendite = sum(sales)
)%>%
mutate(city = factor(city, levels = sort(unique(city)))) %>%
arrange(year, city) %>%
group_by(year) %>%
mutate(
tot_annuo = sum(tot_vendite),
freq_citta = tot_vendite / tot_annuo,
perc = freq_citta*100,
pos = 1-cumsum(freq_citta)+(freq_citta/2)
) %>%
ungroup()
ggplot(vendite_per_citta_anno, aes(x = factor(year), y = freq_citta, fill = city)) +
geom_bar(stat = "identity", position = "fill") +
geom_text(aes(y = pos, label = sprintf("%.1f%%", perc)), color = "black") +
scale_y_continuous(breaks = seq(0, 1, 0.1), labels = scales::percent_format(accuracy = 1)) +
labs(y = "Frequenza (%)", x = "Anno", title = "Confronto quote di Vendite per Città e anno") +
theme_minimal()
Dal grafico precedente si possono vedere due lievi tendenze:
Può essere utile confrontare il grafico sulle quote di vendita con uno con le quote di annunci
listings_per_citta_anno <- dataset %>%
group_by(year, city) %>%
reframe(
tot_listings = sum(listings)
)%>%
mutate(city = factor(city, levels = sort(unique(city)))) %>%
arrange(year, city) %>%
group_by(year) %>%
mutate(
tot_annuo = sum(tot_listings),
freq_citta = tot_listings / tot_annuo,
perc = freq_citta*100,
pos = 1-cumsum(freq_citta)+(freq_citta/2)
) %>%
ungroup()
ggplot(listings_per_citta_anno, aes(x = factor(year), y = freq_citta, fill = city)) +
geom_bar(stat = "identity", position = "fill") +
geom_text(aes(y = pos, label = sprintf("%.1f%%", perc)), color = "black") +
scale_y_continuous(breaks = seq(0, 1, 0.1), labels = scales::percent_format(accuracy = 1)) +
labs(y = "Frequenza (%)", x = "Anno", title = "Confronto quote di Annunci per Città e anno") +
theme_minimal()
Da questo secondo grafico è possibile vedere differenze tra le quote di vendite e quelle di annunci per ogni città
ggplot(dataset, aes(x = city, y = median_price, fill = city)) +
geom_boxplot()+
labs(y = "Prezzo mediano", x = "Città", title = "Confronto distribuzione prezzo per le varie città")
Nei casi di Beaumont e Tyler ho provato a vedere se ci fosse una correlazione anche tra prezzo mediano e numero di vendite
Beaumont <- dataset %>%
filter(city == "Beaumont") %>%
select(sales, median_price, month, year, date)
breaksB <- seq(from = min(Beaumont$median_price, na.rm=TRUE),
to = max(Beaumont$median_price, na.rm=TRUE),
length.out = 6)
labelsB <- paste0(round(breaksB[-length(breaksB)], 0), "-", round(breaksB[-1], 0))
Beaumont <- Beaumont %>%
mutate(
fascia_median_price = cut(median_price,
breaks = breaksB,
labels = labelsB,
include.lowest = TRUE)
)
ggplot(Beaumont, aes(x = fascia_median_price, y = sales))+
geom_boxplot()+
labs(y = "Vendite", x = "Fasce di prezzo", title = "Analisi Beaumont")
Tyler <- dataset %>%
filter(city == "Tyler") %>%
select(sales, median_price, month, year, date)
breaksT <- seq(from = min(Tyler$median_price, na.rm=TRUE),
to = max(Tyler$median_price, na.rm=TRUE),
length.out = 6)
labelsT <- paste0(round(breaksT[-length(breaksT)], 0), "-", round(breaksT[-1], 0))
Tyler <- Tyler %>%
mutate(
fascia_median_price = cut(median_price,
breaks = breaksT,
labels = labelsT,
include.lowest = TRUE)
)
ggplot(Tyler, aes(x = fascia_median_price, y = sales))+
geom_boxplot()+
labs(y = "Vendite", x = "Fasce di prezzo", title = "Analisi Tyler")
I due boxplot precedenti non mostrano particolari tendenze di legame tra le fasce di prezzo delle vendite e il numero di vendite Nota: le fasce di prezzo nei due grafici risultano estremamente grezze, ma sono quelle che dividono in 5 fasce uguali i prezzi di vendita delle rispettive città
Grafici con serie storiche di dati
ggplot(dataset, aes(x= date, y = sales, color = city))+
geom_line()+
labs(x = "data", y = "vendite", title = "Serie storica delle vendite nel quinquennio")
ggplot(Tyler, aes(x= date, y = sales, color = year))+
geom_line()+
labs(x = "data", y = "vendite", title = "Serie storica delle vendite nel quinquennio per la città di Tyler")