#Load libraries
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)
library(summarytools)
library(readr)
library(moments)
# Dataset Import
RETexas_ds <- read_csv("Real Estate Texas.csv", show_col_types = FALSE)
#0: Primo sguardo ai dati
RETexas_ds
## # A tibble: 240 × 8
## city year month sales volume median_price listings months_inventory
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Beaumont 2010 1 83 14.2 163800 1533 9.5
## 2 Beaumont 2010 2 108 17.7 138200 1586 10
## 3 Beaumont 2010 3 182 28.7 122400 1689 10.6
## 4 Beaumont 2010 4 200 26.8 123200 1708 10.6
## 5 Beaumont 2010 5 202 28.8 123100 1771 10.9
## 6 Beaumont 2010 6 189 27.2 122800 1803 11.1
## 7 Beaumont 2010 7 164 22.7 124300 1857 11.7
## 8 Beaumont 2010 8 174 25.2 136800 1830 11.6
## 9 Beaumont 2010 9 124 17.2 121100 1829 11.7
## 10 Beaumont 2010 10 150 23.9 138500 1779 11.5
## # ℹ 230 more rows
# Dall'import del dataset noto che è composto da 240 osservazioni e da 8 variabili
# Noto che le variaibli, ad esclusione di "city" che è del testo (character), sono tutte numeriche (double)
# Verifico se non ci sono valori mancanti
colSums(is.na(RETexas_ds))
## city year month sales
## 0 0 0 0
## volume median_price listings months_inventory
## 0 0 0 0
# Non sono presenti valori mancanti
#1: Analisi delle Variabili
RETexas_ds$city <- as.factor(RETexas_ds$city)
RETexas_ds$year <- as.factor(RETexas_ds$year)
RETexas_ds$month <- factor(RETexas_ds$month, levels = 1:12, labels = month.abb)
sapply(RETexas_ds, class)
## city year month sales
## "factor" "factor" "factor" "numeric"
## volume median_price listings months_inventory
## "numeric" "numeric" "numeric" "numeric"
# City è una variabile qualitativa nominale
# Year anche se ha valori numerici è stata considerata come una variabile qualitativa ordinale in quanto ha poco significato eseguire calcoli numerici su di essi
# Month, del tutto simile a Year, ha valori numerici, ma sono stati convertiti nei corrispondendeti mesi in formato testuale per facilitare la comprensione, e quindi la variabile è considerati variabile qualitativa ordinale
# Sales è una variabiale quantitativa discreta
# Volume è una variabile quantitativa continua
# Median Price è una variabile quantitativa continua
# Listings è una variabile quantitativa discreta
# Months Inventory è una variabile quantitativa continua
# Per le variabili qualitative ha senso constatare come sono distribuite, in modo da cogliere eventuali elementi maggioritari
# Mentre per le variabili quantitative si possono calcolare tutti gli indici di posizione in modo da avere una visione della loro distribuzione
#2: Indici di Posizione, Variabilità e Forma
num_var <- c("sales", "volume", "median_price", "listings", "months_inventory")
cat_var <- c("city", "year", "month")
# Creo una tabella che raccoglie tutte le informazioni statistiche delle variabili quantitative
num_var_stats <- data.frame(
Variable = num_var,
Min = round(sapply(RETexas_ds[num_var], min, na.rm = TRUE), 1),
Q1 = round(sapply(RETexas_ds[num_var], function(x) quantile(x, probs = 0.25, na.rm = TRUE)), 1),
Q3 = round(sapply(RETexas_ds[num_var], function(x) quantile(x, probs = 0.75, na.rm = TRUE)), 1),
Max = round(sapply(RETexas_ds[num_var], max, na.rm = TRUE), 1),
Range = round(sapply(RETexas_ds[num_var], function(x) max(x, na.rm = TRUE) - min(x, na.rm = TRUE)), 1),
IQR = round(sapply(RETexas_ds[num_var], IQR, na.rm = TRUE), 1),
Mean = round(sapply(RETexas_ds[num_var], mean, na.rm = TRUE), 2),
Median = round(sapply(RETexas_ds[num_var], median, na.rm = TRUE), 2),
Variance = round(sapply(RETexas_ds[num_var], var, na.rm = TRUE), 3),
Std_Dev = round(sapply(RETexas_ds[num_var], sd, na.rm = TRUE), 3),
RSD = round(sapply(RETexas_ds[num_var], function(x) (sd(x, na.rm = TRUE) / mean(x, na.rm = TRUE)) * 100), 3),
Skewness = round(sapply(RETexas_ds[num_var], skewness, na.rm = TRUE), 3),
Kurtosis = round(sapply(RETexas_ds[num_var], kurtosis, na.rm = TRUE), 3)
)
print(num_var_stats)
## Variable Min Q1 Q3 Max Range
## sales sales 79.0 127.0 247.0 423.0 344.0
## volume volume 8.2 17.7 40.9 83.5 75.4
## median_price median_price 73800.0 117300.0 150050.0 180000.0 106200.0
## listings listings 743.0 1026.5 2056.0 3296.0 2553.0
## months_inventory months_inventory 3.4 7.8 11.0 14.9 11.5
## IQR Mean Median Variance Std_Dev RSD
## sales 120.0 192.29 175.50 6.34430e+03 79.651 41.422
## volume 23.2 31.01 27.06 2.77271e+02 16.651 53.705
## median_price 32750.0 132665.42 134500.00 5.13573e+08 22662.149 17.082
## listings 1029.5 1738.02 1618.50 5.66569e+05 752.708 43.308
## months_inventory 3.2 9.19 8.95 5.30700e+00 2.304 25.060
## Skewness Kurtosis
## sales 0.718 2.687
## volume 0.885 3.177
## median_price -0.365 2.377
## listings 0.649 2.208
## months_inventory 0.041 2.826
# Dalla tabella contenente gli indici di posizione, variabilità e forma sulle variabili quantitative
# si nota come "volume" è la variabile maggiormente dispersa intorno alla sua media dato l'alto valore di RSD.
# Viceversa "median_price" è la variabile più concentrata intorno alla sua media.
# "sales, "volume" e "listing" sono variabili con distribuzione asimmettrica
# dato che il valore di skewness è positivo, quindi con valori maggiormente sotto la media.
# Mentre la variabile "median_price è distribuita asimmettricamente con skewness negativa,
# quindi con valori maggiormente sopra la media.
# Infine la variabile "months_inventory" è considerabile distribuita simmetricamente,
# poichè ha un valore di skewness vicino allo 0.
# Analizzando l'indice di curtosi si può dire che le variabili "volume" e "month_inventory" hanno una distribuzione vicina a quella normale,
# mentre le altre mostrano valori maggiormente inferiori a 3, ciò implica che hanno distribuzioni platicurtiche.
# Distribuzioni di frequenze delle variabili qualitative
for (var in cat_var){
print(var)
ni <- table(RETexas_ds[[var]])
fi <- round(100*prop.table(ni), 1)
print(cbind(ni, fi))
}
## [1] "city"
## ni fi
## Beaumont 60 25
## Bryan-College Station 60 25
## Tyler 60 25
## Wichita Falls 60 25
## [1] "year"
## ni fi
## 2010 48 20
## 2011 48 20
## 2012 48 20
## 2013 48 20
## 2014 48 20
## [1] "month"
## ni fi
## Jan 20 8.3
## Feb 20 8.3
## Mar 20 8.3
## Apr 20 8.3
## May 20 8.3
## Jun 20 8.3
## Jul 20 8.3
## Aug 20 8.3
## Sep 20 8.3
## Oct 20 8.3
## Nov 20 8.3
## Dec 20 8.3
# Dalla distribuzione dele variabili qualitative si evince che tutte le osservazioni sono distibuite equamente per ognuna di esse.
# Nello specifico abbiamo 60 osservazioni per ogni città distribuite in modo da avere 20 osservazioni per ogni mese dell'anno dal 2010 al 2014
# Questo significa che c'è una sola osservazione per ogni combinazione "City"-"Year"-"Month"
# E infatti se calcolo il numero minimo di osservazioni avendo 4 citta, 5 anni e 12 mesi ottengo proprio 240.
#3: Identificazione delle variabili con maggiore Variabilità e Asimmetria
print(paste("La variabile con maggiore variabilità è",
num_var_stats[which.max(num_var_stats$RSD),1],
"con valore", round(max(num_var_stats$RSD), 2)))
## [1] "La variabile con maggiore variabilità è volume con valore 53.7"
print(paste("La variabile più asimmetrica è",
num_var_stats[which.max(abs(num_var_stats$Skewness)),1],
"con valore", round(max(num_var_stats$Skewness), 2)))
## [1] "La variabile più asimmetrica è volume con valore 0.88"
# Dall'analisi per il calcolo della variabile con il maggior variabilità e asimmetria si è constato che per entambe risulta essere il volume
#4: Creazione di classi per una variabile quantitativa
# Come variabile quantitativa scelgo "sales"
# Prima di esegurie la suddivisione calcolo tramite la regola di Sturges il numero ottimale di classi da avere
n_sales <- length(RETexas_ds$sales) # numero di osservazioni della variabile (in questo caso del tutto analogo al numero di righe del dataset)
k_sales <- ceiling(1 + log2(n_sales)) # numero di classi secondo la regola di Sturges
# creo una lista per vedere gli estremi delle classi create
breaks_sales <- seq(min(RETexas_ds$sales, na.rm = TRUE), max(RETexas_ds$sales, na.rm = TRUE), length.out = k_sales + 1)
breaks_sales
## [1] 79.0000 117.2222 155.4444 193.6667 231.8889 270.1111 308.3333 346.5556
## [9] 384.7778 423.0000
# sfrutto gli estremi per rinominare le etichette delle classi in modo da essere esplicative
labels_sales <- paste0(round(head(breaks_sales, -1), 0), " - ", round(tail(breaks_sales, -1), 0))
labels_sales
## [1] "79 - 117" "117 - 155" "155 - 194" "194 - 232" "232 - 270" "270 - 308"
## [7] "308 - 347" "347 - 385" "385 - 423"
# creo una nuova variabile all'interno del dataset che indica a quale classe di sales ricade l'osservazione
# impongo che il valore inferiore del range sia contenuto nella classe
RETexas_ds$sales_class <- cut(RETexas_ds$sales,
breaks = breaks_sales,
include.lowest = TRUE,
labels = labels_sales)
# creo una tabella separata con le sole informazioni delle distribuzioni delle classi di sales
sales_class_freq <- as.data.frame(table(RETexas_ds$sales_class))
colnames(sales_class_freq) <- c("Sales_Range", "Frequenza")
print(sales_class_freq)
## Sales_Range Frequenza
## 1 79 - 117 46
## 2 117 - 155 51
## 3 155 - 194 44
## 4 194 - 232 27
## 5 232 - 270 23
## 6 270 - 308 26
## 7 308 - 347 10
## 8 347 - 385 9
## 9 385 - 423 4
# grafico la tabella delle distribuzioni delle classi
ggplot(sales_class_freq, aes(x = Sales_Range, y = Frequenza, fill = Sales_Range)) +
geom_bar(stat = "identity") +
geom_text(aes(label = Frequenza), vjust = -0.3, size = 5) +
theme_minimal() +
labs(title = "Distribuzione di Frequenze delle Classi di Sales",
x = "Intervalli di Sales",
y = "Frequenza") +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none")

# Dato che abbiamo categorizzato la variabile quantitativa sales è possibile constatare la sua eterogeneità tra le classi
# per fare ciò si può usare la misura dell'indice di eterogeneità di Gini
gini_index_sales <- 1 - sum((sales_class_freq$Frequenza/n_sales)^2)
print(paste("L'indice di Gini per le classi Sales:", round(gini_index_sales, 3)))
## [1] "L'indice di Gini per le classi Sales: 0.848"
# Per essere maggiormante significativo tale indice deve essere normalizzato tramite il valore massimo ottenibile
# il massimo indice possibile dipende dal numero di classi con cui è stata suddivisa la variabile
# una volta ottenuto basterà riportare il rapporto tra l'indice effettivo ed il massimo espresso in percentuale
max_gini_index_sales <- (k_sales - 1)/k_sales
gini_norm_index_sales <- (gini_index_sales/max_gini_index_sales)*100
print(paste("L'indice di Gini normalizzato per le classi Sales:", round(gini_norm_index_sales, 2), "%"))
## [1] "L'indice di Gini normalizzato per le classi Sales: 95.34 %"
# La variabile sales per come è stata distribuità presenta un elevato indice di eterogeneità, prossimo al massimo
# In modo del tutto analogo posso eseguire i vari step per la variabile medina_price
n_median_price <- length(RETexas_ds$median_price) # numero di osservazioni della variabile (in questo caso del tutto analogo al numero di righe del dataset)
k_median_price <- ceiling(1 + log2(n_median_price)) # numero di classi secondo la regola di Sturges
breaks_median_price <- seq(min(RETexas_ds$median_price, na.rm = TRUE), max(RETexas_ds$median_price, na.rm = TRUE), length.out = k_median_price + 1)
breaks_median_price
## [1] 73800 85600 97400 109200 121000 132800 144600 156400 168200 180000
# a differenza delle sales, divido per 1000 i valori in modo da portare l'unità di misura in M$ e facilitare la lettura
labels_median_price <- paste0(round(head(breaks_median_price, -1), 0)/1000, " - ", round(tail(breaks_median_price, -1), 0)/1000)
labels_median_price
## [1] "73.8 - 85.6" "85.6 - 97.4" "97.4 - 109.2" "109.2 - 121"
## [5] "121 - 132.8" "132.8 - 144.6" "144.6 - 156.4" "156.4 - 168.2"
## [9] "168.2 - 180"
RETexas_ds$median_price_class <- cut(RETexas_ds$median_price,
breaks = k_median_price,
include.lowest = TRUE,
labels = labels_median_price)
median_price_class_freq <- as.data.frame(table(RETexas_ds$median_price_class))
colnames(median_price_class_freq) <- c("Median_Price_Range", "Frequenza")
print(median_price_class_freq)
## Median_Price_Range Frequenza
## 1 73.8 - 85.6 2
## 2 85.6 - 97.4 18
## 3 97.4 - 109.2 26
## 4 109.2 - 121 22
## 5 121 - 132.8 39
## 6 132.8 - 144.6 49
## 7 144.6 - 156.4 53
## 8 156.4 - 168.2 21
## 9 168.2 - 180 10
ggplot(median_price_class_freq, aes(x = Median_Price_Range, y = Frequenza, fill = Median_Price_Range)) +
geom_bar(stat = "identity") +
geom_text(aes(label = Frequenza), vjust = -0.3, size = 5) +
theme_minimal() +
labs(title = "Distribuzione di Frequenze delle Classi di Median Price",
x = "Intervalli di Median Price [M$]",
y = "Frequenza") +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none")

gini_index_median_price <- 1 - sum((median_price_class_freq$Frequenza/n_median_price)^2)
print(paste("L'indice di Gini per le classi Median Price:", round(gini_index_median_price, 3)))
## [1] "L'indice di Gini per le classi Median Price: 0.848"
max_gini_index_median_price <- (k_median_price - 1)/k_median_price
gini_norm_index_median_price <- (gini_index_median_price/max_gini_index_median_price)*100
print(paste("L'indice di Gini normalizzato per le classi Median Price:", round(gini_norm_index_median_price, 2), "%"))
## [1] "L'indice di Gini normalizzato per le classi Median Price: 95.39 %"
# Anche la variabile median price per come è stata distribuità presenta un elevato indice di eterogeneità, prossimo al massimo
#5: Calcolo della probabilità
# Si vuole conoscere la probabilità che presa una riga a caso di questo dataset, essa riporti la città “Beaumont”
# Si vuole conoscere la probabilità che riporti il mese di Luglio
# Si vuole la probabilità che riporti il mese di dicembre 2012
# Per le prime due probabilità questi valori sono stati già ricavati durante il punto #2
# quando sono stati calcolate le frequenze relative per la variabili qualitative
# Quindi per la prima probabilità (city = Beaumont) il risultato è 0.25 (25%)
# Per la seconda probabilità ( month = Luglio) il risultato è 0.083 (8.3%)
# Per la terza probabiòlità ci basta fare il prodotto tra la frequenza relativa che sia dicembre (0.083) e quella che sia il 2012 (0.20)
0.20*0.083
## [1] 0.0166
# La probabilità di avere casualmente una osservazione del dicembre 2012 è 0.0166 (1.6%)
#6: Creazione di nuove variabili
# Devo creare una variabile che misuri il prezzo medio degli immobili
# per fare ciò, mi basta dividere il totale delle vendite (volume) di una osservazione per il rispettivo numero di vendite (sales)
# per semplicità di lettura, dato che il volume è espresso in milioni di dollari, moltiplico il valore per 10^6 in modo che il valore medio sia in dollari
RETexas_ds$mean_price <- round((RETexas_ds$volume/RETexas_ds$sales)*10^6, 0)
# Per misurare l'efficacia degli annunci eseguo un calcolo simile
# Divido il numero delle vendite effettuate (sales) per il numero di annunci attivi (listings)
# Per facilitare la lettura del dato molitplico per 100 il risultato così da avere un valore percentuale
RETexas_ds$listings_effectiveness <- round((RETexas_ds$sales/RETexas_ds$listings)*100, 2)
#7: Analisi condizionata
city_mean_price_stats <- RETexas_ds %>%
group_by(city) %>%
summarise(
city_mean_price = mean(mean_price, na.rm = TRUE),
sd_mean_price = sd(mean_price, na.rm = TRUE)
) %>%
ungroup()
print(city_mean_price_stats)
## # A tibble: 4 × 3
## city city_mean_price sd_mean_price
## <fct> <dbl> <dbl>
## 1 Beaumont 146640. 11232.
## 2 Bryan-College Station 183534. 15149.
## 3 Tyler 167677. 12351.
## 4 Wichita Falls 119430. 11398.
year_mean_price_stats <- RETexas_ds %>%
group_by(year) %>%
summarise(
year_mean_price = mean(mean_price, na.rm = TRUE),
sd_mean_price = sd(mean_price, na.rm = TRUE)
) %>%
ungroup()
print(year_mean_price_stats)
## # A tibble: 5 × 3
## year year_mean_price sd_mean_price
## <fct> <dbl> <dbl>
## 1 2010 150189. 23280.
## 2 2011 148251. 24938.
## 3 2012 150899. 26438.
## 4 2013 158705. 26524.
## 5 2014 163559. 31741.
month_mean_price_stats <- RETexas_ds %>%
group_by(month) %>%
summarise(
month_mean_price = mean(mean_price, na.rm = TRUE),
sd_mean_price = sd(mean_price, na.rm = TRUE)
) %>%
ungroup()
print(month_mean_price_stats)
## # A tibble: 12 × 3
## month month_mean_price sd_mean_price
## <fct> <dbl> <dbl>
## 1 Jan 145640. 29819.
## 2 Feb 148840. 25120.
## 3 Mar 151137. 23238.
## 4 Apr 151461. 26174.
## 5 May 158235. 25787.
## 6 Jun 161546. 23470.
## 7 Jul 156881. 27220.
## 8 Aug 156456. 28253.
## 9 Sep 156522. 29669.
## 10 Oct 155897. 32527.
## 11 Nov 154233. 29685.
## 12 Dec 154995. 27009.
ggplot(city_mean_price_stats, aes(x = city, y = city_mean_price/1000, fill = city)) +
geom_bar(stat = "identity", alpha = 0.7) +
geom_errorbar(aes(ymin = (city_mean_price - sd_mean_price)/1000, ymax = (city_mean_price + sd_mean_price)/1000),
width = 0.2, color = "black") + # Barre di errore
theme_minimal() +
labs(title = "Media delle Vendite per Città",
x = "Città", y = "Media Vendite [M$]") +
theme(legend.position = "none")

ggplot(year_mean_price_stats, aes(x = year, y = year_mean_price/1000, fill = year)) +
geom_bar(stat = "identity", alpha = 0.7) +
geom_errorbar(aes(ymin = (year_mean_price - sd_mean_price)/1000, ymax = (year_mean_price + sd_mean_price)/1000),
width = 0.2, color = "black") + # Barre di errore
theme_minimal() +
labs(title = "Media delle Vendite per Anno",
x = "Anno", y = "Media Vendite [M$]") +
theme(legend.position = "none")

ggplot(month_mean_price_stats, aes(x = month, y = month_mean_price/1000, fill = month)) +
geom_bar(stat = "identity", alpha = 0.7) +
geom_errorbar(aes(ymin = (month_mean_price - sd_mean_price)/1000, ymax = (month_mean_price + sd_mean_price)/1000),
width = 0.2, color = "black") + # Barre di errore
theme_minimal() +
labs(title = "Media delle Vendite per Mese",
x = "Mese", y = "Media Vendite [M$]") +
theme(legend.position = "none")

#8: Creazione di visualizzazioni con ggplot2
# Usare un boxplot per confrontare le distribuzioni dei prezzi mediani fra le città
ggplot(RETexas_ds, aes(x = city, y = median_price/1000, fill = city)) +
geom_boxplot(alpha = 0.7) + # Boxplot con trasparenza
theme_minimal() +
labs(title = "Distribuzione del Prezzo Mediano per Città",
x = "Città", y = "Prezzo Mediano (M$)") +
theme(legend.position = "none",
axis.text.x = element_text(angle = 45, hjust = 1))

# Usare un grafico a barre per confrontare il totale delle vendite per mese e città
sales_month_city <- RETexas_ds %>%
group_by(city, month) %>%
summarise(total_sales = sum(sales, na.rm = TRUE)) %>%
ungroup()
## `summarise()` has grouped output by 'city'. You can override using the
## `.groups` argument.
ggplot(sales_month_city, aes(x = month, y = total_sales, fill = city)) +
geom_bar(stat = "identity", position = "dodge", width = 0.8) + # Barre affiancate per ogni città
theme_minimal() +
labs(title = "Andamento Totale delle Vendite per Mese e Città",
x = "Mese", y = "Totale Vendite") +
scale_x_discrete(limits = month.abb) + # Ordina i mesi con abbreviazioni standard
theme(axis.text.x = element_text(angle = 45, hjust = 1))

ggplot(sales_month_city, aes(x = month, y = total_sales, fill = city)) +
geom_bar(stat = "identity", position = "stack") + # Barre impilate
geom_text(aes(label = total_sales),
position = position_stack(vjust = 0.5), # Posiziona le etichette al centro della barra
color = "black", size = 2) + # Imposta il colore e la dimensione del testo
theme_minimal() +
labs(title = "Vendite Totali per Mese e Città (Barre Impilate)",
x = "Mese", y = "Totale Vendite") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Usare dei grafici line chart per confrontare l'andamento delle vendite nel tempo
sales_time <- RETexas_ds %>%
group_by(year, month) %>%
summarise(total_sales = sum(sales, na.rm = TRUE)) %>%
ungroup()
## `summarise()` has grouped output by 'year'. You can override using the
## `.groups` argument.
ggplot(sales_time, aes(x = month, y = total_sales, color = year, group = year)) +
geom_line(linewidth = 1) + # Linee più spesse
geom_point(size = 2) + # Punti per maggiore leggibilità
theme_minimal() +
labs(title = "Andamento delle Vendite per Mese (Confronto tra Anni)",
x = "Mese", y = "Totale Vendite", color = "Anno") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

#9: Conclusioni
# Dalla analisi svolta si posso trarre le seguenti conclusioni:
# - Nel corso del tempo il prezzo medio e mediano di vendita delle case è stato più elevato nella città di Bryan-College Station, a seguire Tyler, Beaumont e infine Wichita Falss
# - La città in cui si finalizzano più vendite è Tyler, a seguire Bryan-College Station, Beaumont e infinte Wichita Falls
# - Non sono ci sono state nel corso degli anni sostanziali variazioni del prezzo medio di vendita
# - Il 2014 è stato l'anno che ha registrato il maggior numero di vendite per quasi ogni mese, mentre gli anni peggiori sono stati il 2010 e 2011
# - Si nota come nel corso degli anni l'azienda ha incrementato il numero di vendite
# - Seppur con una leggero rialzo durante i mesi di Giugno, non sono riscontrabili significative variazioni del prezzo medio di vendita tra i diversi mesi dell'anno
# - Tuttavia tra Maggio e Agosto si registrano in generale per tutte le città un maggior numero di vendite
# - Per ottimizzare le vendite bisogna cercare di replicare il modello di annunci impiegato nella città di Bryan-College Station tra il 2013 e il 2014 poichè sono quelli con la maggior efficacia
# In particolare modo bisogna applicarlo per la città di Tyler dove attualmente c'è un bassa efficacia degli annunci e quindi un potenziale margine da colmare per incrementare ulteriormente le vendite
# Questo risulta essere molto importante per i guadagni se si considera che Tyler è al secondo posto come prezzo medio di vendita delle case
# - Si potrebbe pensare di ridurre le risorse impiegate a Wichita Falls dato che attualmente è la città con il prezzo medio inferiore e che in valore assoluto registra il minor numero di vendite