In questa fase iniziale vengono caricati i pacchetti necessari per l’analisi dei dati (dply per la manipolazione dei dati e ggplot2 per la visualizzazione grafica) e successivamente viene importato il dataset “realestate_texas.csv”.
Le funzioni head() e str() vengono utilizzate per effettuare una prima esplorazione dei dati: la prima permette di visualizzare le prime osservazioni del dataset, mentre la seconda consente di analizzarne la struttura, il tipo delle variabili e il numero di osservazioni disponibili.
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(ggplot2)
dati <- read.csv("realestate_texas.csv")
head(dati)
## city year month sales volume median_price listings months_inventory
## 1 Beaumont 2010 1 83 14.162 163800 1533 9.5
## 2 Beaumont 2010 2 108 17.690 138200 1586 10.0
## 3 Beaumont 2010 3 182 28.701 122400 1689 10.6
## 4 Beaumont 2010 4 200 26.819 123200 1708 10.6
## 5 Beaumont 2010 5 202 28.833 123100 1771 10.9
## 6 Beaumont 2010 6 189 27.219 122800 1803 11.1
str(dati)
## 'data.frame': 240 obs. of 8 variables:
## $ city : chr "Beaumont" "Beaumont" "Beaumont" "Beaumont" ...
## $ year : int 2010 2010 2010 2010 2010 2010 2010 2010 2010 2010 ...
## $ month : int 1 2 3 4 5 6 7 8 9 10 ...
## $ sales : int 83 108 182 200 202 189 164 174 124 150 ...
## $ volume : num 14.2 17.7 28.7 26.8 28.8 ...
## $ median_price : num 163800 138200 122400 123200 123100 ...
## $ listings : int 1533 1586 1689 1708 1771 1803 1857 1830 1829 1779 ...
## $ months_inventory: num 9.5 10 10.6 10.6 10.9 11.1 11.7 11.6 11.7 11.5 ...
La variabile sales rappresenta il numero di vendite immobiliari effettuate in ciascun periodo. Trattandosi di una variabile quantitativa discreta, è possibile analizzarla tramite le principali misure di posizione e di dispersione.
In particolare, vengono calcolate: - la media e la mediana, per valutare il livello medio delle vendite e confrontare la tendenza centrale; - il valore minimo e il valore massimo, per individuare gli estremi osservati; - i quantili, per descrivere la distribuzione delle vendite; - la deviazione standard e la varianza, per misurare la variabilità dei dati; - l’ampiezza del campo di variazione, calcolata come differenza tra valore massimo e minimo, per valutare l’estensione complessiva dei valori assunti dalla variabile.
sales <- dati$sales
head(sales,5)
## [1] 83 108 182 200 202
mean(sales)
## [1] 192.2917
median(sales)
## [1] 175.5
min(sales)
## [1] 79
max(sales)
## [1] 423
quantile(sales)
## 0% 25% 50% 75% 100%
## 79.0 127.0 175.5 247.0 423.0
sd(sales)
## [1] 79.65111
var(sales)
## [1] 6344.3
diff(range(sales))
## [1] 344
Per approfondire l’analisi della variabile sales, vengono calcolate alcune misure sintetiche che permettono di confrontare la variabilità e la forma della distribuzione.
In particolare: - il coefficiente di variazione (CV) è ottenuto come rapporto tra deviazione standard e media, espresso in percentuale. Questa misura consente di valutare la variabilità delle vendite in relazione al loro valore medio; - l’indice di asimmetria (skewness) permette di valutare se la distribuzione delle vendite è simmetrica oppure sbilanciata verso valori più bassi o più alti; - l’indice di curtosi (kurtosis) fornisce informazioni sulla forma della distribuzione, indicando se i dati risultano più o meno concentrati attorno alla media rispetto a una distribuzione normale.
cv <- function(x){
return(sd(x)/mean(x)*100)
}
cv(sales)
## [1] 41.42203
moments::skewness(sales)
## [1] 0.718104
moments::kurtosis(sales)
## [1] 2.686824
Il coefficiente di variazione delle vendite è pari a circa 41%, indicando una variabilità piuttosto elevata rispetto al valore medio. L’indice di asimmetria è positivo (0,72), segnalando una distribuzione asimmetrica a destra, con una maggiore concentrazione di osservazioni su valori di vendita più bassi. La curtosi risulta inferiore a 3, suggerendo una distribuzione leggermente più appiattita rispetto alla distribuzione normale.
Ho fatto la stessa cosa con le restanti variabili:
volume <- dati$volume
mean(volume)
## [1] 31.00519
median(volume)
## [1] 27.0625
min(volume)
## [1] 8.166
max(volume)
## [1] 83.547
quantile(volume)
## 0% 25% 50% 75% 100%
## 8.1660 17.6595 27.0625 40.8930 83.5470
sd(volume)
## [1] 16.65145
var(volume)
## [1] 277.2707
diff(range(volume))
## [1] 75.381
cv(volume)
## [1] 53.70536
moments::skewness(volume)
## [1] 0.884742
moments::kurtosis(volume)
## [1] 3.176987
Il volume delle vendite mostra un’elevata variabilità relativa (CV ≈ 54%), indicando forti differenze tra le osservazioni. La media è maggiore della mediana e l’indice di asimmetria positivo segnala una distribuzione asimmetrica a destra. La curtosi leggermente superiore a 3 suggerisce una distribuzione moderatamente più appuntita rispetto alla normale.
median_price <- dati$median_price
mean(median_price)
## [1] 132665.4
median(median_price)
## [1] 134500
min(median_price)
## [1] 73800
max(median_price)
## [1] 180000
quantile(median_price)
## 0% 25% 50% 75% 100%
## 73800 117300 134500 150050 180000
sd(median_price)
## [1] 22662.15
var(median_price)
## [1] 513572983
diff(range(median_price))
## [1] 106200
cv(median_price)
## [1] 17.08218
moments::skewness(median_price)
## [1] -0.3645529
moments::kurtosis(median_price)
## [1] 2.377038
Il prezzo mediano degli immobili ha una variabilità relativamente
contenuta (CV ≈ 17%), con valori che vanno da circa 73.800 a 180.000
$.
L’asimmetria negativa indica una leggera concentrazione di osservazioni
verso valori più alti, mentre la curtosi inferiore a 3 suggerisce una
distribuzione leggermente più piatta rispetto alla normale.
listings <- dati$listings
head(listings,5)
## [1] 1533 1586 1689 1708 1771
mean(listings)
## [1] 1738.021
median(listings)
## [1] 1618.5
min(listings)
## [1] 743
max(listings)
## [1] 3296
quantile(listings)
## 0% 25% 50% 75% 100%
## 743.0 1026.5 1618.5 2056.0 3296.0
sd(listings)
## [1] 752.7078
var(listings)
## [1] 566569
diff(range(listings))
## [1] 2553
cv(listings)
## [1] 43.30833
moments::skewness(listings)
## [1] 0.6494982
moments::kurtosis(listings)
## [1] 2.20821
La variabile listings presenta una dispersione piuttosto elevata, come evidenziato dal coefficiente di variazione pari a circa 43%. La distribuzione risulta moderatamente asimmetrica a destra, indicando una maggiore concentrazione di valori medio-bassi e alcuni valori più elevati. La curtosi inferiore a 3 suggerisce una distribuzione leggermente più piatta rispetto alla normale.
months_inventory <- dati$months_inventory
head(months_inventory,5)
## [1] 9.5 10.0 10.6 10.6 10.9
mean(months_inventory)
## [1] 9.1925
median(months_inventory)
## [1] 8.95
min(months_inventory)
## [1] 3.4
max(months_inventory)
## [1] 14.9
quantile(months_inventory)
## 0% 25% 50% 75% 100%
## 3.40 7.80 8.95 10.95 14.90
sd(months_inventory)
## [1] 2.303669
var(months_inventory)
## [1] 5.306889
diff(range(months_inventory))
## [1] 11.5
cv(months_inventory)
## [1] 25.06031
moments::skewness(months_inventory)
## [1] 0.04097527
moments::kurtosis(months_inventory)
## [1] 2.825552
La variabile months_inventory mostra una variabilità contenuta, come indicato dal coefficiente di variazione pari a circa 25%. La distribuzione risulta pressoché simmetrica, con un valore di asimmetria molto vicino a zero, mentre la curtosi prossima a 3 suggerisce una forma simile a quella di una distribuzione normale. Questo indica una buona stabilità del numero di mesi di inventario nel periodo analizzato.
Le variabili mostrano livelli di variabilità diversi: sales e volume sono le più disperse e asimmetriche, mentre median_price e months_inventory risultano più stabili e con distribuzioni quasi simmetriche.
Di seguito vengono analizzate le variabili qualitative del dataset, in particolare city e month, attraverso distribuzioni di frequenza assolute e relative, al fine di descriverne la composizione.
N <- nrow(dati)
freq_ass_city <- table(dati$city)
freq_rel_city <- table(dati$city) / N
distr_freq_city <- cbind(freq_ass_city, freq_rel_city)
distr_freq_city
## freq_ass_city freq_rel_city
## Beaumont 60 0.25
## Bryan-College Station 60 0.25
## Tyler 60 0.25
## Wichita Falls 60 0.25
freq_ass_month <- table(dati$month)
freq_rel_month <- table(dati$month) / N
distr_freq_month <- cbind(freq_ass_month, freq_rel_month)
distr_freq_month
## freq_ass_month freq_rel_month
## 1 20 0.08333333
## 2 20 0.08333333
## 3 20 0.08333333
## 4 20 0.08333333
## 5 20 0.08333333
## 6 20 0.08333333
## 7 20 0.08333333
## 8 20 0.08333333
## 9 20 0.08333333
## 10 20 0.08333333
## 11 20 0.08333333
## 12 20 0.08333333
La distribuzione della variabile city risulta perfettamente uniforme: ciascuna città è rappresentata da 60 osservazioni, pari al 25% del totale. Anche la variabile month mostra una distribuzione uniforme, con 20 osservazioni per ogni mese (circa l’8,3%), indicando che i dati sono equamente distribuiti nel tempo e tra le città.
cv(sales)
## [1] 41.42203
cv(volume)
## [1] 53.70536
cv(median_price)
## [1] 17.08218
cv(listings)
## [1] 43.30833
cv(months_inventory)
## [1] 25.06031
Per determinare qual’è la variabile con più variabilità ho scelto di utilizzare il coefficiente di variazione perchè confronta variabili con unità diverse: il coefficiente di variazione mostra che la variabile con maggiore variabilità relativa è volume, indicando che il valore totale delle vendite cambia in modo significativo tra città e periodi diversi.
Per determinare invece qual è la variabile con più asimmetria utilizzo la funzione skewness:
moments::skewness(sales)
## [1] 0.718104
moments::skewness(volume)
## [1] 0.884742
moments::skewness(median_price)
## [1] -0.3645529
moments::skewness(listings)
## [1] 0.6494982
moments::skewness(months_inventory)
## [1] 0.04097527
Sapendo che più il valore si allontana da zero e più c’è asimmetria: il volume delle vendite risulta la variabile più asimmetrica, mentre i mesi di inventario mostrano una distribuzione quasi simmetrica.
sales <- dati$sales
n <- length(sales)
sales_cl <- cut(
sales,
breaks = seq(min(sales), max(sales)+50, 50)
)
table(sales_cl)
## sales_cl
## (79,129] (129,179] (179,229] (229,279] (279,329] (329,379] (379,429]
## 62 60 44 29 27 12 4
distr_freq <- as.data.frame(
cbind(
ni = table(sales_cl),
fi = table(sales_cl)/n,
Ni = cumsum(table(sales_cl)),
Fi = cumsum(table(sales_cl)/n)
)
)
distr_freq
## ni fi Ni Fi
## (79,129] 62 0.25833333 62 0.2583333
## (129,179] 60 0.25000000 122 0.5083333
## (179,229] 44 0.18333333 166 0.6916667
## (229,279] 29 0.12083333 195 0.8125000
## (279,329] 27 0.11250000 222 0.9250000
## (329,379] 12 0.05000000 234 0.9750000
## (379,429] 4 0.01666667 238 0.9916667
ggplot(data=dati)+
geom_bar(aes(x=sales_cl),
stat="count",
col="black",
fill="#69b3a2")+
labs(title="Distribuzione delle vendite immobiliari",
x="Classi di vendite",
y="Frequenze assolute")+
theme_classic()+
theme(panel.grid.major.y = element_line(color="grey90"),
panel.grid.minor.y = element_line(color="grey95"))
## Coefficiente di Gini
fi <- distr_freq$fi
gini <- 1 - sum(fi^2)
gini
## [1] 0.8071181
La variabile sales è stata suddivisa in classi di ampiezza pari a 50. Dalla distribuzione di frequenza emerge che la maggior parte delle osservazioni si concentra nelle classi con valori di vendita più bassi. In particolare, oltre il 50% delle osservazioni rientra nelle prime due classi, comprese tra 79 e 179 vendite.All’aumentare delle classi, le frequenze diminuiscono progressivamente, mentre le classi con valori di vendita più elevati presentano un numero ridotto di osservazioni. Questo andamento suggerisce una distribuzione asimmetrica a destra, caratterizzata dalla presenza di una coda verso i valori più alti.L’indice di eterogeneità di Gini risulta pari a circa 0,81, valore elevato che indica una marcata eterogeneità nella distribuzione delle vendite tra le classi. Ciò significa che le osservazioni non sono distribuite in modo uniforme, ma risultano concentrate principalmente in alcune classi.
n <- nrow(dati)
P_beaumont <- sum(dati$city == "Beaumont") / n
P_beaumont
## [1] 0.25
La probabilità che un’osservazione riporti la città di Beaumont è stata calcolata come frequenza relativa delle righe corrispondenti a questa città sul totale del dataset.
P_luglio <- sum(dati$month == 7) / n
P_luglio
## [1] 0.08333333
La probabilità che un’osservazione riporti il mese di luglio è stata calcolata come frequenza relativa del mese 7 sul totale delle osservazioni.
P_dic2012 <- sum(dati$month == 12 & dati$year == 2012) / n
P_dic2012
## [1] 0.01666667
La probabilità che un’osservazione corrisponda a dicembre 2012 è stata calcolata considerando la combinazione del mese 12 e dell’anno 2012, divisa per il totale delle osservazioni.
dati$avg_price <- dati$volume * 1e6 / dati$sales
head(dati[, c("sales","volume","avg_price")])
## sales volume avg_price
## 1 83 14.162 170626.5
## 2 108 17.690 163796.3
## 3 182 28.701 157697.8
## 4 200 26.819 134095.0
## 5 202 28.833 142737.6
## 6 189 27.219 144015.9
dati$efficacy <- dati$sales / dati$listings
head(dati[, c("sales","listings","efficacy")])
## sales listings efficacy
## 1 83 1533 0.05414220
## 2 108 1586 0.06809584
## 3 182 1689 0.10775607
## 4 200 1708 0.11709602
## 5 202 1771 0.11405985
## 6 189 1803 0.10482529
min(dati$avg_price)
## [1] 97010.2
max(dati$avg_price)
## [1] 213233.9
min(dati$efficacy)
## [1] 0.05014025
max(dati$efficacy)
## [1] 0.3871278
La variabile avg_price mostra che il prezzo medio degli immobili varia tra circa 97.000 e 213.000 dollari.
Per quanto riguarda l’efficacia degli annunci (efficacy), i valori variano tra circa 5% e 39%, mostrando che nella maggior parte dei casi solo una piccola parte degli annunci porta a vendite effettive.
library(dplyr)
dati %>%
group_by(city) %>%
summarise(
avg_price_mean = mean(avg_price),
avg_price_sd = sd(avg_price),
efficacy_mean = mean(efficacy),
efficacy_sd = sd(efficacy)
)
## # A tibble: 4 × 5
## city avg_price_mean avg_price_sd efficacy_mean efficacy_sd
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Beaumont 146640. 11232. 0.106 0.0267
## 2 Bryan-College Station 183534. 15149. 0.147 0.0729
## 3 Tyler 167677. 12351. 0.0935 0.0235
## 4 Wichita Falls 119430. 11398. 0.128 0.0247
dati %>%
group_by(year) %>%
summarise(
avg_price_mean = mean(avg_price),
avg_price_sd = sd(avg_price),
efficacy_mean = mean(efficacy),
efficacy_sd = sd(efficacy)
)
## # A tibble: 5 × 5
## year avg_price_mean avg_price_sd efficacy_mean efficacy_sd
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 2010 150189. 23280. 0.0997 0.0337
## 2 2011 148251. 24938. 0.0927 0.0232
## 3 2012 150899. 26438. 0.110 0.0281
## 4 2013 158705. 26524. 0.135 0.0448
## 5 2014 163559. 31741. 0.157 0.0618
dati %>%
group_by(month) %>%
summarise(
avg_price_mean = mean(avg_price),
avg_price_sd = sd(avg_price),
efficacy_mean = mean(efficacy),
efficacy_sd = sd(efficacy)
)
## # A tibble: 12 × 5
## month avg_price_mean avg_price_sd efficacy_mean efficacy_sd
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 145640. 29819. 0.0831 0.0230
## 2 2 148840. 25120. 0.0878 0.0219
## 3 3 151137. 23238. 0.116 0.0346
## 4 4 151461. 26174. 0.125 0.0380
## 5 5 158235. 25787. 0.141 0.0503
## 6 6 161546. 23470. 0.142 0.0576
## 7 7 156881. 27220. 0.143 0.0740
## 8 8 156456. 28253. 0.142 0.0526
## 9 9 156522. 29669. 0.112 0.0348
## 10 10 155897. 32527. 0.112 0.0360
## 11 11 154233. 29685. 0.102 0.0293
## 12 12 154996. 27009. 0.117 0.0379
Avg_price_mean varia da circa 119.000 $ a 183.000 $, con Wichita Falls la città con prezzo medio più basso e Bryan-College Station la più alta. Efficacy_mean varia tra circa 9% e 15%, con Bryan-College Station che ha annunci più efficaci e Tyler quelli meno efficaci.
Il prezzo medio cresce leggermente dal 2010 (150.000 $) al 2014 (163.000 $), mostrando un trend positivo. Anche l’efficacia degli annunci aumenta negli anni, da circa 10% nel 2010 a 16% nel 2014, suggerendo un miglioramento complessivo della performance degli annunci nel tempo.
Il prezzo medio varia tra 145.000 $ e 161.000 $, con valori più alti nei mesi estivi (maggio-luglio).
L’efficacia degli annunci è più alta nei mesi estivi (giugno-luglio, circa 14%), mentre nei primi mesi dell’anno è più bassa (gennaio-febbraio, circa 8-9%).
library(ggplot2)
ggplot(dati, aes(x = city, y = avg_price)) +
geom_boxplot(fill = "#82c8d9", color = "black") +
labs(
title = "Distribuzione del prezzo medio degli immobili per città",
x = "Città",
y = "Prezzo medio ($)"
) +
theme_minimal()+
theme(
panel.grid.major.y = element_line(color="grey90"),
panel.grid.minor.y = element_line(color="grey95"),
axis.text.x = element_text(angle=45, hjust=1))
ggplot(dati, aes(x = city, y = volume)) +
geom_boxplot(fill = "#f4a261", color = "black") +
labs(
title = "Distribuzione del volume totale delle vendite per città",
x = "Città",
y = "Volume delle vendite (milioni $)"
) +
theme_minimal()+
theme(
panel.grid.major.y = element_line(color="grey90"),
panel.grid.minor.y = element_line(color="grey95"),
axis.text.x = element_text(angle=45, hjust=1))
sales_tot <- aggregate(sales ~ city + month, data = dati, sum)
ggplot(data = sales_tot, aes(x = factor(month), y = sales, fill = city)) +
geom_col(color = "black") +
labs(
title = "Vendite totali per mese e città",
x = "Mese",
y = "Vendite totali"
) +
scale_fill_brewer(palette = "Set2") +
theme_classic() +
theme(
legend.position = "bottom",
axis.text.x = element_text(angle = 0, hjust = 0.5),
panel.grid.major.y = element_line(color = "grey90"),
panel.grid.minor.y = element_line(color = "grey95")
)
ggplot(data = sales_tot, aes(x = factor(month), y = sales, fill = city)) +
geom_col(position = "fill", color = "black") +
labs(
title = "Distribuzione relativa delle vendite per mese e città",
x = "Mese",
y = "Frequenze relative"
) +
scale_y_continuous(breaks = seq(0, 1, 0.1)) +
scale_fill_brewer(palette = "Set2") +
theme_classic() +
theme(
panel.grid.major.y = element_line(color = "grey90"),
panel.grid.minor.y = element_line(color = "grey95"),
axis.text.x = element_text(angle = 0, hjust = 0.5),
legend.position = "bottom"
)
sales_mean <- aggregate(sales ~ city + year, data = dati, mean)
ggplot(data = sales_mean, aes(x = year, y = sales, color = city, group = city)) +
geom_line() +
geom_point(size = 3) +
labs(
title = "Andamento medio delle vendite nel tempo per città",
x = "Anno",
y = "Vendite medie"
) +
scale_color_brewer(palette = "Set2") +
theme_grey() +
theme(
legend.position = "bottom",
panel.grid.major.y = element_line(color = "grey90"),
panel.grid.minor.y = element_line(color = "grey95")
)