Variabili nel dataset: tipologia e ipotesi di analisi.

Partiamo caricando il nostro dataset estratto dal file “realestate_texas.csv” assegnato a un dataframe.

#importiamo il dataset in csv nello spazio di lavoro
realestate_stats = read.csv("realestate_texas.csv", sep=",")

Per avere un’idea degli oggetti e delle variabili nel dataset, stampiamo le prime righe del dataframe e facciamo un conteggio di osservazioni e variabili presenti:

#leggiamo le prime righe del dataset e visualizziamo la quantità di oggetti e variabili

head(realestate_stats)
#leggiamo le prime righe del dataset e visualizziamo la quantità di oggetti e variabili
dim(realestate_stats)
## [1] 240   8

Procediamo a identificare le tipologie di variabili nel dataset, e a commentarle preliminarmente.

#Identifichiamo le tipologie di variabili nel dataset

str(realestate_stats)
## '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 ...

Il dataset allegato al progetto di analisi esplorativa del mercato immobiliare texano prevede 8 variabili statistiche con 240 oggetti, esse sono:

Analisi dei principali indici delle variabili.

Identificata la natura delle variabili presenti nel dataset, procediamo ad effettuare un’analisi dei principali indici statistici di ognuna. Il percorso logico applicato è quello di ridurre il problema generale (“la massa di dati da analizzare”), in problemi più piccoli che possiamo esplorare singolarmente (“Le informazioni restituite dall’elaborazione di ogni singola variabile”).

city:

R non prevede una funzione specifica per il calcolo della moda di una variabile, per cui decidiamo di costruire la nostra funzione personalizzata a questo scopo:

#La moda non è calcolabile su R tramite una funzione diretta
#quindi svilupperemo la funzione noi stessi

mode = function(x){
  u = unique(x)
  tab = tabulate(match(x, u))
  u[tab == max(tab)]
}

Procediamo quindi ad utilizzare la nostra funzione mode() per calcolare la moda della variabile city del dataset:

city_mode = c(realestate_stats$city)
mode(city_mode)
## [1] "Beaumont"              "Bryan-College Station" "Tyler"                
## [4] "Wichita Falls"

La soluzione ci suggerisce che possiamo trovarci davanti ad una variabile quadrimodale, per effettuare tale verifica chiamiamo la funzione table sulla variabile $city e osserviamo il risultato:

#Usiamo la funzione table per verificare la natura modale di city
table(realestate_stats$city)
## 
##              Beaumont Bryan-College Station                 Tyler 
##                    60                    60                    60 
##         Wichita Falls 
##                    60

Il risultato parla chiaro. city è una variabile quadrimodale con lo stesso numero di osservazioni per ogni città del dataset.

year:

Con city che svela la sua natura quadrimodale, possiamo ipotizzare che ciò dipenda da un periodo di osservazione uguale per ognuno degli agglomerati urbani di interesse. A questo punto verifichiamo che ciò sia vero trovando il min e il max della variabile year:

#min e max per la variabile year
min(realestate_stats$year)
## [1] 2010
max(realestate_stats$year)
## [1] 2014

Si tratta quindi di 5 anni di osservazioni, le quali potrebbero essere ulteriormente divise in mesi. Se così non fosse, non si spiegherebbero le 60 osservazioni per città sulla variabile city. La soluzione migliore è costruire una distribuzione di frequenze per avere un quadro chiaro.

#distribuzione di frequenze della variabile year
cytable = addmargins(table(realestate_stats$city, realestate_stats$year), 2)
print(cytable)
##                        
##                         2010 2011 2012 2013 2014 Sum
##   Beaumont                12   12   12   12   12  60
##   Bryan-College Station   12   12   12   12   12  60
##   Tyler                   12   12   12   12   12  60
##   Wichita Falls           12   12   12   12   12  60

Abbiamo quindi la conferma che, con 12 osservazioni per anno per ognuna delle città, il dataset deve essere diviso in mesi. Questo ci porta alla variabile successiva.

month:

Calcolando il range della variabile month possiamo sapere se tutti e 12 i mesi sono presenti.

#range variabile month
range(realestate_stats$month)
## [1]  1 12

e possiamo stampare il risultato esteso per una conferma visiva.

#Un'ultima verifica sulla presenza di tutti e 12 i mesi per ogni anno
#si può effettuare prendendo le prime 12 righe della variabile month dal dataset
print(realestate_stats$month[1:12])
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12

Presa in considerazione la natura di questa variabile, non avrebbe senso procedere col calcolo di altri indici di posizione, forma o variabilità per month, ma come variabile temporale potrà tornare molto utile successivamente.

sales:

Per la quantità di vendite effettuate mensilmente in ognuna delle città nell’arco dei cinque anni possiamo variare la risoluzione dei nostri calcoli su più livelli.

Innanzitutto calcoliamo gli indici di posizione globali per l’intera variabile sales, cominciando dal min/max.

#Variabile sales. Calcoliamo e stampiamo il min/max
minsales = min(realestate_stats$sales)
maxsales = max(realestate_stats$sales)
sprintf("Il minimo della variabile sales è: %i", minsales)
## [1] "Il minimo della variabile sales è: 79"
sprintf("Il massimo della variabile sales è: %i", maxsales)
## [1] "Il massimo della variabile sales è: 423"

Calcoliamo la mediana per la quantità di vendite di tutte le città nei 5 anni considerati:

#Calcoliamo la mediana
mediansales = median(realestate_stats$sales)
sprintf("La mediana della variabile sales é: %.2f", mediansales)
## [1] "La mediana della variabile sales é: 175.50"

Otteniamo anche la media della variabile sales:

#calcoliamo la media della variabile sales
meansales = mean(realestate_stats$sales)
sprintf("La media delle quantità vendute in tutte le città e in tutti gli anni considerati è: %.2f", meansales)
## [1] "La media delle quantità vendute in tutte le città e in tutti gli anni considerati è: 192.29"

Avendo già min/max e media, estrapoliamo i restanti quartili con la funzione quantile() come segue:

#calcoliamo i quartili di sales
quantile_sales = quantile(realestate_stats$sales, probs= c(.25,.75))
print(quantile_sales)
## 25% 75% 
## 127 247

Indici di variabilità per sales:

Partiamo calcolando l’intervallo di viariazione.

#calcoliamo l'intervallo di variazione di sales:
varinterval = (maxsales-minsales)
sprintf("L'intervallo di variazione per sales é: %i", varinterval)
## [1] "L'intervallo di variazione per sales é: 344"

Otteniamo il range interquartile con la funzione apposita.

#procediamo calcolando il range interquartile di sales:
intersales = IQR(realestate_stats$sales)
sprintf("Il range interquartile della variabile sales è: %i", intersales)
## [1] "Il range interquartile della variabile sales è: 120"

Otteniamo la varianza di sales con la funzione apposita.

#calcoliamo la varianza della variabile sales:
salesvar = var(realestate_stats$sales)
sprintf("La variabile sales presenta una varianza di: %.1f", salesvar)
## [1] "La variabile sales presenta una varianza di: 6344.3"

Otteniamo anche la deviazione standard di sales con la funzione apposita.

#Passiamo poi a calcolare la deviazione standard con la funzione apposita:
stand_dev_sales = sd(realestate_stats$sales)
sprintf("La deviazione standard di sales è: %.3f", stand_dev_sales)
## [1] "La deviazione standard di sales è: 79.651"

Non essendoci osservazioni nulle o negative nella variabile sales, possiamo calcolare anche il coefficiente di variazione, dovendoci però costruire una funzione apposita perchè assente dal pacchetto base di R.

#Creiamo la funzione del coefficiente di variazione.
coeff_var = function(x){
  return(sd(x)/mean(x)*100)
}
#Procediamo al calcolo per la variabile sales
salescv = coeff_var(realestate_stats$sales)
sprintf("Il coefficiente di variazione di sales è: %.3f", salescv)
## [1] "Il coefficiente di variazione di sales è: 41.422"

Non trattandosi di una variabile qualitativa, tralasceremo l’indice di eterogeneità di Gini perchè non avrebbe senso calcolarlo, passiamo agli indici di forma.

Indici di forma per sales:

Il primo indice di forma che vogliamo calcolare è l’indice di asimmetria di Fisher. Per questa prima variabile costruiremo le formule a mano a dimostrazione del processo utilizzato.

#Procediamo a calcolare, per questa prima volta, l'indice di asimmetria a mano
salesn = length(realestate_stats$sales)
salesm3 = sum((realestate_stats$sales-meansales)^3)/salesn

asimmetry_sales_index = salesm3/stand_dev_sales^3
plot(density(realestate_stats$sales))
abline(v=meansales, col="red")

sprintf("L'indice di asimmetria di sales è: %.3f", asimmetry_sales_index)
## [1] "L'indice di asimmetria di sales è: 0.714"

Calcoliamo ora la Curtosi costruendo la formula apposita.

#Calcoliamo la curtosi manualmente
salesm4 = sum((realestate_stats$sales-meansales)^4)/salesn
kurtosis_sale_index = salesm4/stand_dev_sales^4 -3 
sprintf("L'indice di curtosi di sales è: %.3f", kurtosis_sale_index)
## [1] "L'indice di curtosi di sales è: -0.336"

Notiamo come l’indice di asimmetria di Fisher restituisca un’asimmetria positiva. La distribuzione ha quindi una prevalenza di valori/modalità basse.

L’indice di curtosi ci comunica inoltre la tendenza della distribuzione ad essere platicurtica, cioè appiattita rispetto ad una distribuzione normale.

volume:

Variabile volume, indici di posizione.

#Passiamo alla variabile volume. Indici di posizione
minvolume = min(realestate_stats$volume)
maxvolume = max(realestate_stats$volume)
meanvolume = mean(realestate_stats$volume)
medianvolume = median(realestate_stats$volume)
quantile_volume = quantile(realestate_stats$volume, probs = c(.25, .75))
sprintf("La variabile volume ha un min/max di: %.3f %.3f", minvolume, maxvolume)
## [1] "La variabile volume ha un min/max di: 8.166 83.547"
sprintf("La variabile volume ha una media di: %.3f", meanvolume)
## [1] "La variabile volume ha una media di: 31.005"
sprintf("La variabile volume ha una mediana di: %.3f", medianvolume)
## [1] "La variabile volume ha una mediana di: 27.062"
print(quantile_volume)
##     25%     75% 
## 17.6595 40.8930

Variabile volume, indici di variabilità.

#volume, indici di variabilità
volumevarinterval = (maxvolume-minvolume)
interquartile_volume = IQR(realestate_stats$volume)
volumevar = var(realestate_stats$volume)
volumesd = sd(realestate_stats$volume)
volume_coeff_var = coeff_var(realestate_stats$volume)
sprintf("L'intervallo di variazione di volume è: %.3f", volumevarinterval)
## [1] "L'intervallo di variazione di volume è: 75.381"
sprintf("Il range interquartile di volume è: %.3f", interquartile_volume)
## [1] "Il range interquartile di volume è: 23.233"
sprintf("La varianza di volume è: %.3f", volumevar)
## [1] "La varianza di volume è: 277.271"
sprintf("La deviazione standard di volume è: %.3f", volumesd)
## [1] "La deviazione standard di volume è: 16.651"
sprintf("Il coefficiente di variazione di  volume è: %.3f", volume_coeff_var)
## [1] "Il coefficiente di variazione di  volume è: 53.705"

Variabile volume, indici di forma.

Per velocizzare il calcolo degli indici di forma da questo momento userò le funzioni skewness e kurtosis del pacchetto moments.

#volume, indici di forma
library("moments")
asimmetry_volume_index = skewness(realestate_stats$volume)
kurtosis_volume_index = kurtosis(realestate_stats$volume)-3
plot(density(realestate_stats$volume))
abline(v=meanvolume, col="red")

sprintf("L'indice di asimmetria di volume è: %.3f", asimmetry_volume_index)
## [1] "L'indice di asimmetria di volume è: 0.885"
sprintf("L'indice di curtosi di volume è: %.3f", kurtosis_volume_index)
## [1] "L'indice di curtosi di volume è: 0.177"

Volume ha un’asimmetria positiva, quindi anche per questa variabile si osservano modalità prevalentemente basse, con una curtosi pertinente ad una distribuzione leptocurtica.

median_price:

Variabile median_price, indici di posizione.

#median_price, indici di posizione
minmp = min(realestate_stats$median_price)
maxmp = max(realestate_stats$median_price)
meanmp = mean(realestate_stats$median_price)
medianmp = median(realestate_stats$median_price)
quantile_mp = quantile(realestate_stats$median_price, probs = c(.25, .75))
sprintf("La variabile median_price ha un min/max di: %i %i", minmp, maxmp)
## [1] "La variabile median_price ha un min/max di: 73800 180000"
sprintf("La variabile median_price ha una media di: %.3f", meanmp)
## [1] "La variabile median_price ha una media di: 132665.417"
sprintf("La variabile median_price ha una mediana di: %i", medianmp)
## [1] "La variabile median_price ha una mediana di: 134500"
print(quantile_mp)
##    25%    75% 
## 117300 150050

median_price, indici di variabilità.

#median_price, indici di variabilità
mpvarinterval = (maxmp-minmp)
interquartile_mp = IQR(realestate_stats$median_price)
mpvar = var(realestate_stats$median_price)
mpsd = sd(realestate_stats$median_price)
mp_coeff_var = coeff_var(realestate_stats$median_price)
sprintf("L'intervallo di variazione di median_price è: %i", mpvarinterval)
## [1] "L'intervallo di variazione di median_price è: 106200"
sprintf("Il range interquartile di median_price è: %i", interquartile_mp)
## [1] "Il range interquartile di median_price è: 32750"
sprintf("La varianza di median_price è: %.3f", mpvar)
## [1] "La varianza di median_price è: 513572983.089"
sprintf("La deviazione standard di median_price è: %.3f", mpsd)
## [1] "La deviazione standard di median_price è: 22662.149"
sprintf("Il coefficiente di variazione di  median_price è: %.3f", mp_coeff_var)
## [1] "Il coefficiente di variazione di  median_price è: 17.082"

median_price, indici di forma.

Per variare la grafica e creare qualcosa di più carino, in questo passaggio ho provato ad usare il modulo ggplot2 di R.

#median_price, indici di forma.
library("ggplot2")
asimmetry_mp_index = skewness(realestate_stats$median_price)
kurtosis_mp_index = kurtosis(realestate_stats$median_price)-3

ggplot()+
  geom_density(aes(x=realestate_stats$median_price), col="black", fill="palegreen")+
  geom_vline(xintercept =meanmp, linewidth=1.5, color = "lightcoral")+
  labs(x="Prezzo Mediano", y="Densità")+
  geom_text(aes(x = meanmp + 20000, y = 1.8e-05, label = sprintf("Media\n %.3f", meanmp)), inherit.aes = FALSE) +
  ylim(0, 2e-05)

sprintf("L'indice di asimmetria di median_price è: %.3f", asimmetry_mp_index)
## [1] "L'indice di asimmetria di median_price è: -0.365"
sprintf("L'indice di curtosi di median_price è: %.3f", kurtosis_mp_index)
## [1] "L'indice di curtosi di median_price è: -0.623"

La variabile median_price ha un’asimmetria negativa con una distribuzione platicurtica. La curva è appiattita e la maggior parte delle modalità osservate risultano alte.

listings:

#variabile listings, indici di posizione
minlist = min(realestate_stats$listings)
maxlist = max(realestate_stats$listings)
meanlist = mean(realestate_stats$listings)
medianlist = median(realestate_stats$listings)
quantile_list = quantile(realestate_stats$listings, probs = c(.25, .75))
sprintf("La variabile listings ha un min/max di: %i %i", minlist, maxlist)
## [1] "La variabile listings ha un min/max di: 743 3296"
sprintf("La variabile listings ha una media di: %.3f", meanlist)
## [1] "La variabile listings ha una media di: 1738.021"
sprintf("La variabile listings ha una mediana di: %.2f", medianlist)
## [1] "La variabile listings ha una mediana di: 1618.50"
print(quantile_list)
##    25%    75% 
## 1026.5 2056.0

listings, indici di variabilità.

#variabile listings, indici di variabilità
listvarinterval = (maxlist-minlist)
interquartile_list = IQR(realestate_stats$listings)
listvar = var(realestate_stats$listings)
listsd = sd(realestate_stats$listings)
list_coeff_var = coeff_var(realestate_stats$listings)
sprintf("L'intervallo di variazione di listings è: %i", listvarinterval)
## [1] "L'intervallo di variazione di listings è: 2553"
sprintf("Il range interquartile di listings è: %.2f", interquartile_list)
## [1] "Il range interquartile di listings è: 1029.50"
sprintf("La varianza di listings è: %.3f", listvar)
## [1] "La varianza di listings è: 566568.966"
sprintf("La deviazione standard di listings è: %.3f", listsd)
## [1] "La deviazione standard di listings è: 752.708"
sprintf("Il coefficiente di variazione di  listings è: %.3f", list_coeff_var)
## [1] "Il coefficiente di variazione di  listings è: 43.308"

listings, indici di forma.

#per determinare in maniera più precisa la scala di y
#tramite cui posizionare la scritta "media", ho usato la funzione density
#eseguita sulla variabile listings. l'indice max della densità di listings su y è stato usato
#per posizionare correttamente la scritta "media" nel grafico
density_data = density(realestate_stats$listings)
max_listdensity = max(density_data$y)

#variabile listings, indici di forma
library("ggplot2")
asimmetry_lists_index = skewness(realestate_stats$listings)
kurtosis_lists_index = kurtosis(realestate_stats$listings)-3

ggplot()+
  geom_density(aes(x=realestate_stats$listings), col="black", fill="palegreen")+
  geom_vline(xintercept = meanlist, linewidth=1.5, color = "lightcoral")+
  labs(x="Inserzioni attive", y="Densità")+
  geom_text(aes(x = meanlist+500, y = max_listdensity, label = sprintf("Media\n %.3f", meanlist)), inherit.aes = FALSE) +
  xlim(0, 5000)

sprintf("L'indice di asimmetria di listings è: %.3f", asimmetry_lists_index)
## [1] "L'indice di asimmetria di listings è: 0.649"
sprintf("L'indice di curtosi di listings è: %.3f", kurtosis_lists_index)
## [1] "L'indice di curtosi di listings è: -0.792"

L’indice di asimmetria di Fisher su listings è positivo. Si tratta di asimmetria positiva e la maggior parte delle modalità/valori sono bassi. La curtosi è negativa, quindi abbiamo una distribuzione platicurtica.

months inventory:

months inventory, indici di posizione.

#variabile months_inventory, indici di posizione
minmonths = min(realestate_stats$months_inventory)
maxmonths = max(realestate_stats$months_inventory)
meanmonths = mean(realestate_stats$months_inventory)
medianmonths = median(realestate_stats$months_inventory)
modemonths = mode(realestate_stats$months_inventory)
quantile_months = quantile(realestate_stats$months_inventory, probs = c(.25, .75))
sprintf("La variabile months_inventory ha un min/max di: %.2f %.2f", minmonths, maxmonths)
## [1] "La variabile months_inventory ha un min/max di: 3.40 14.90"
sprintf("La variabile months_inventory ha una media di: %.3f", meanmonths)
## [1] "La variabile months_inventory ha una media di: 9.193"
sprintf("La variabile months_inventory ha una mediana di: %.2f", medianmonths)
## [1] "La variabile months_inventory ha una mediana di: 8.95"
sprintf("La variabile months_inventory è unimodale: %.2f", modemonths)
## [1] "La variabile months_inventory è unimodale: 8.10"
print(quantile_months)
##   25%   75% 
##  7.80 10.95

months inventory, indici di variabilità.

#variabile months_inventory, indici di variabilità
monthsvarinterval = (maxmonths-minmonths)
interquartile_months = IQR(realestate_stats$months_inventory)
monthsvar = var(realestate_stats$months_inventory)
monthssd = sd(realestate_stats$months_inventory)
months_coeff_var = coeff_var(realestate_stats$months_inventory)
sprintf("L'intervallo di variazione di months_inventory è: %.2f", monthsvarinterval)
## [1] "L'intervallo di variazione di months_inventory è: 11.50"
sprintf("Il range interquartile di months_inventory è: %.2f", interquartile_months)
## [1] "Il range interquartile di months_inventory è: 3.15"
sprintf("La varianza di months_inventory è: %.3f", monthsvar)
## [1] "La varianza di months_inventory è: 5.307"
sprintf("La deviazione standard di months_inventory è: %.3f", monthssd)
## [1] "La deviazione standard di months_inventory è: 2.304"
sprintf("Il coefficiente di variazione di  months_inventory è: %.3f", months_coeff_var)
## [1] "Il coefficiente di variazione di  months_inventory è: 25.060"

months_inventory, indici di forma.

#variabile months_inventory, indici di forma
library("ggplot2")
asimmetry_months_index = skewness(realestate_stats$months_inventory)
kurtosis_months_index = kurtosis(realestate_stats$months_inventory)-3

invendensity = density(realestate_stats$months_inventory)
invenmaxdensity = max(invendensity$y)

ggplot()+
  geom_density(aes(x=realestate_stats$months_inventory), col="black", fill="palegreen")+
  geom_vline(xintercept = meanmonths, linewidth=1.5, color = "lightcoral")+
  labs(x="Tempo restante per smaltire\n le inserizioni attive", y="Densità")+
  geom_text(aes(x = meanmonths+2, y = invenmaxdensity, label = sprintf("Media\n %.3f", meanmonths)), inherit.aes = FALSE)+
  xlim(0,20)

sprintf("L'indice di asimmetria di months_inventory è: %.3f", asimmetry_months_index)
## [1] "L'indice di asimmetria di months_inventory è: 0.041"
sprintf("L'indice di curtosi di months_inventory è: %.3f", kurtosis_months_index)
## [1] "L'indice di curtosi di months_inventory è: -0.174"

months_inventory ha un’asimmetria positiva. Sono quindi più frequenti modalità basse. La curtosi è negativa per cui ci troviamo davanti a una distribuzione platicurtica.

Considerazioni preliminari su coefficiente di variazione e asimmetria.

Compariamo i coefficienti di variazione.

Utilizzerò un lollipop chart creato con ggplot2 per comparare i coefficienti di variazione delle variabili per i quali è stato calcolato.

#Effettuiamo i primi confronti su varianza e asimmetria per i dati a disposizione
#utilizziamo ggplot2 e un lollipop chart per evidenziare le differenze

#Confronto di variabilità

library("ggplot2")

cvarcomparison = data.frame(
  x = c(salescv, volume_coeff_var, mp_coeff_var, list_coeff_var, months_coeff_var),
  y = factor(c("Vendite", "Volume di Vendita", "Prezzo Mediano", "Inserzioni", "Mesi allo Smaltimento"),
             levels = c("Vendite", "Volume di Vendita", "Prezzo Mediano", "Inserzioni", "Mesi allo Smaltimento"))
)

# Creazione del lollipop chart con ggplot2
ggplot(cvarcomparison, aes(x = x, y = y)) +
  geom_segment(aes(x = 0, xend = x, y = y, yend = y), color = "grey") +
  geom_point(aes(x = x), color = "red", fill=alpha("lightcoral", 0.3), alpha=0.7, shape=21, stroke=1.5, size = 5) +
  geom_text(aes(label=round(x, 3)), hjust = -0.3, color= "black")+
  theme_light() +
  theme(
    panel.grid.major.x = element_blank(),
    panel.border = element_blank(),
    axis.ticks.x = element_blank(),
    plot.title.position = "plot"
    ) +
  xlab("Coefficienti di Variazione") +
  ylab("")+
  labs(title = "Comparazione dei coefficienti di variazione.",
       subtitle = "Utilizzo del dataset realestate_texas.csv opportunamente elaborato")+
  coord_flip()

Dal grafico emerge chiaramente che la variable volume (“Volume di vendita”) è quella col coefficiente di variazione più elevato. Procediamo a valutarne anche l’asimmetria tramite l’indice di asimmetria di fisher.

Compariamo gli indici di asimmetria di Fisher delle variabili.

#Confronto di asimmetria

asimmetrycomparison = data.frame(
  x = c(asimmetry_sales_index, asimmetry_volume_index, asimmetry_mp_index, asimmetry_lists_index, asimmetry_months_index),
  y = factor(c("Vendite", "Volume di Vendita", "Prezzo Mediano", "Inserzioni", "Mesi allo Smaltimento"),
             levels = c("Vendite", "Volume di Vendita", "Prezzo Mediano", "Inserzioni", "Mesi allo Smaltimento"))
)

# Creazione del lollipop chart con ggplot2
ggplot(asimmetrycomparison, aes(x = x, y = y)) +
  geom_segment(aes(x = 0, xend = x, y = y, yend = y), color = "grey") +
  geom_point(aes(x = x), color = "blue", fill=alpha("lightblue", 0.3), alpha=0.7, shape=21, stroke=1.5, size = 5) +
  geom_text(aes(label=round(x, 3)), hjust = -0.3, color= "black")+
  theme_light() +
  theme(
    panel.grid.major.x = element_blank(),
    panel.border = element_blank(),
    axis.ticks.x = element_blank(),
    plot.title.position = "plot"
  ) +
  xlab("Indice di asimmetria di Fisher") +
  ylab("")+
  labs(title = "Comparazione degli indici di asimmetria di Fisher",
       subtitle = "Utilizzo del dataset realestate_texas.csv opportunamente elaborato")+
  coord_flip()

Come si evince dal grafico, soltanto una delle variabili ha indice di asimmetria negativo, mentre Volume di Vendita (volume) dimostra, ancora una volta, essere la variabile con l’indice di asimmetria più elevato.

Distribuzione di frequenza e ulteriori valutazioni su variabile sales.

Scelgo la variabile sales per effettuare una divisione in classi delle modalità, costruire la distribuzione di frequenze, procedere poi a dimostrarle graficamente e calcolare l’indice di gini.

Divisione in classi e distribuzione di frequenza.

#Selezioniamo la variabile sales per effettuare una divisione in classe
#ne sviluppiamo la distribuzione di frequenza e la esplicitiamo in un grafico a barre.
#Procederemo poi al calcolo dell'indice di Gini della variabile scelta

#sales, divisione in classe.
salesclass = cut(realestate_stats$sales, breaks = seq(50,450, by=50), right = FALSE)

#calcoliamo le frequenze ed organizziamo la distribuzione

sales_ndistribution = table(salesclass)
sales_frtable = sales_ndistribution/sum(sales_ndistribution)
sales_cumsum = cumsum(sales_ndistribution)
sales_cumrel = sales_cumsum/sum(sales_ndistribution)

finaltable = cbind(ni=sales_ndistribution, fi=sales_frtable, Ni=sales_cumsum, Fi=sales_cumrel)
colnames(finaltable) = c("Fr. Assolute", "Fr. Relative", "Fr. Assolute cumulate", "Fr. relative cumulate")
print(finaltable)
##           Fr. Assolute Fr. Relative Fr. Assolute cumulate Fr. relative cumulate
## [50,100)            20   0.08333333                    20            0.08333333
## [100,150)           69   0.28750000                    89            0.37083333
## [150,200)           58   0.24166667                   147            0.61250000
## [200,250)           33   0.13750000                   180            0.75000000
## [250,300)           34   0.14166667                   214            0.89166667
## [300,350)           14   0.05833333                   228            0.95000000
## [350,400)            9   0.03750000                   237            0.98750000
## [400,450)            3   0.01250000                   240            1.00000000

Inseriamo la distribuzione di frequenze in un grafico creato con ggplot2 che prenda in considerazione le n osservazioni e le classi della variabile.

#Inseriamo la distribuzione in un grafico con ggplot2

#creiamo il dataframe da passare al grafico
saled_distribution_data = data.frame(
  salesclass = as.factor(names(sales_ndistribution)),
  n = as.vector(sales_ndistribution)
)

ggplot(saled_distribution_data, aes(x=salesclass, y = n, fill = salesclass))+
  geom_bar(stat = "identity", fill="grey")+
  scale_x_discrete(limits = levels(salesclass))+
  labs(x = "Classi della variabile", y = "Numero di osservazioni")+
  theme(legend.position = "none",
        plot.title.position = "plot")+
  labs(title = "Distribuzione di frequenze variabile sales",
        subtitle = "Per le n osservazioni divise in classi")

Ora calcoliamo l’indice di eterogeneità di Gini della distribuzione di frequenza per sales appena costruita.

#calcoliamo l'indice di gini di sales 
#creiamo la funzione apposita
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)
}

#procediamo al calcolo
salesgini = gini.index(salesclass)
sprintf("La variabile sales ha un indice di eterogeneità di Gini pari a: %.3f", salesgini)
## [1] "La variabile sales ha un indice di eterogeneità di Gini pari a: 0.923"

Eseguiamo il calcolo dell’indice di eterogeneità di Gini sulla distribuzione in classi della variabile sales. Il risultato è 0.923, per cui notiamo di essere vicini a una condizione di massima eterogeneità prevista (gini=1)

Esempi di calcolo delle probabilità sulle variabili.

Quale probabilità abbiamo di estrarre casualmente “Beaumont” fra le città nella variabile city?

#Calcolo delle probabilità

#Prendiamo in considerazione la probabilità che, con un numero sufficiente di prove, la città di Beaumont venga estratta dal dataset.
#costruiamo il relativo grafico

library("ggplot2")
library("gganimate")
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("gifski")
library("knitr")

frames = lapply(1:10, function(i){
  data.frame(city = sample(realestate_stats$city, 1000000, replace = TRUE),
             frame = paste("Frame", i))
})

framedata = do.call(rbind, frames)

framedata_summary = framedata %>%
  group_by(city, frame) %>%
  summarise(count = n(), .groups = "drop")

animated_plot = ggplot(framedata_summary, aes(x = city, y = count, fill = city)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = "Città", y = "Numero di estrazioni") +
  transition_states(
    frame,
    transition_length = 2,
    state_length = 1
  ) +
  ease_aes('linear')+
  labs(title = "Probabilità di estrazione casuale per una delle modalità di city",
       subtitle = "Frame: {closest_state}")+
  theme(legend.position = "none")

cityanimation = animate(animated_plot, fps = 15, duration = 5, nframes = 30, renderer = gifski_renderer())
anim_save("city_probability_animation.gif", animation = cityanimation)
knitr::include_graphics("city_probability_animation.gif")

#Otteniamo la probabilità classica per la variabile city

city_classic_prob = (60/240)
city_relative_prob = (city_classic_prob*100)
sprintf("Il grafico rappresenta visivamente ciò che il calcolo della probabilità classica ci dice della variabile city. Con un numero sufficiente di tentativi di estrazione, la variabile city restituirà un probabilità del %.1f%% di ottenere La città di Beaumont", city_relative_prob)
## [1] "Il grafico rappresenta visivamente ciò che il calcolo della probabilità classica ci dice della variabile city. Con un numero sufficiente di tentativi di estrazione, la variabile city restituirà un probabilità del 25.0% di ottenere La città di Beaumont"

Dimostriamo, attraverso il grafico e l’uso della probabilità classica, che l’estrazione casuale della città di Beaumont fra le righe della variabile city ha un 25% di probabilità di estrazione con un numero sufficiente di tentativi.

Quale probabilità abbiamo di estrarre casualmente il mese di Luglio dalle righe della variabile month?

#Prendiamo ora in considerazione la variabile month per il mese di Luglio
#Costruiamo anche il relativo grafico

library("ggplot2")
library("gganimate")
library("dplyr")
library("gifski")
library("knitr")

frames_month = lapply(1:10, function(i){
  data.frame(months = sample(realestate_stats$month, 1000000, replace = TRUE),
             frame = paste("Frame", i))
})

frame_month_data = do.call(rbind, frames_month)

framedatamonth_summary = frame_month_data %>%
  group_by(months, frame) %>%
  summarise(count = n(), .groups = "drop")

animated_plot_months = ggplot(framedatamonth_summary, aes(x = months, y = count, fill = months)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = "Mesi", y = "Numero di estrazioni") +
  transition_states(
    frame,
    transition_length = 2,
    state_length = 1
  ) +
  ease_aes('linear')+
  labs(title = "Probabilità di estrazione casuale per una delle modalità di month",
       subtitle = "Frame: {closest_state}")+
  theme(legend.position = "none")

monthsanimation = animate(animated_plot_months, fps = 15, duration = 5, nframes = 30, renderer = gifski_renderer())
anim_save("months_probability_animation.gif", animation = monthsanimation)
knitr::include_graphics("months_probability_animation.gif")

#Otteniamo la probabilità classica per la variabile month

month_classic_prob = (20/240)
month_relative_prob = (month_classic_prob*100)
sprintf("Il grafico rappresenta visivamente ciò che il calcolo della probabilità classica ci dice della variabile month. Con un numero sufficiente di tentativi di estrazione, la variabile month restituirà un probabilità del %.1f%% di ottenere il mese di Luglio", month_relative_prob)
## [1] "Il grafico rappresenta visivamente ciò che il calcolo della probabilità classica ci dice della variabile month. Con un numero sufficiente di tentativi di estrazione, la variabile month restituirà un probabilità del 8.3% di ottenere il mese di Luglio"

Dimostriamo, attraverso il grafico e l’uso della probabilità classica, che l’estrazione casuale del mese di Luglio fra le righe della variabile month ha un 8.3% di probabilità di estrazione con un numero sufficiente di tentativi.

Che probabilità abbiamo di estrarre Dicembre 2012 dalle righe del dataset?

#Valutiamo la probabilità che dal dataset si estragga il mese di dicembre 2012

#costruiamo il grafico
library("ggplot2")
library("gganimate")
library("dplyr")
library("gifski")
library("knitr")


#calcolo della probabilità
twentyt_classic_prob = (4/240)
twentyt_relative_prob = (twentyt_classic_prob*100)

sprintf("Il grafico rappresenta visivamente ciò che il calcolo della probabilità classica ci dice. Con un numero sufficiente di tentativi di estrazione, la modalità Dicembre 2012 restituirà una probabilità del %.1f%% di essere estratta", twentyt_relative_prob)
## [1] "Il grafico rappresenta visivamente ciò che il calcolo della probabilità classica ci dice. Con un numero sufficiente di tentativi di estrazione, la modalità Dicembre 2012 restituirà una probabilità del 1.7% di essere estratta"
set.seed(42) 
months_full_dataset = c(rep(1:59, each = 4), rep(60, times = 4))

frames_twentyt = lapply(1:10, function(i) {
  data.frame(
    month_category = sample(months_full_dataset, 1000000, replace = TRUE),
    frame = paste("Frame", i)
  )
})

frame_twentyt_data = do.call(rbind, frames_twentyt)

framedatatwentyt_summary = frame_twentyt_data %>%
  group_by(month_category, frame) %>%
  summarise(count = n(), .groups = "drop") %>%
  mutate(color_group = ifelse(month_category == 60, "Dicembre", "Altri mesi"))

animated_plot_twentyt = ggplot(framedatatwentyt_summary, aes(x = as.factor(month_category), y = count, fill = color_group)) +
  geom_bar(stat = 'identity', position = "dodge", width = 0.8) +
  theme_minimal() +
  labs(x = "Categorie di Mesi", y = "Numero di estrazioni") +
  transition_states(
    frame,
    transition_length = 2,
    state_length = 1
  ) +
  ease_aes('linear')+
  labs(title = "Probabilità di estrazione casuale per Dicembre 2012",
       subtitle = "Frame: {closest_state}")+
  scale_fill_manual(values = c("Dicembre" = "lightcoral", "Altri mesi" = "grey"))+
  theme(legend.position = "none",
        axis.text.x = element_text(angle = 90, hjust = 1),
        plot.margin = margin(1, 1, 1, 1, "cm"))

twentytanimation = animate(animated_plot_twentyt, 
                           fps = 15, 
                           duration = 5, 
                           nframes = 30, 
                           renderer = gifski_renderer()
                           )
anim_save("twentyt_probability_animation.gif", animation = twentytanimation)
knitr::include_graphics("twentyt_probability_animation.gif")

Come notiamo dal calcolo della probabilità e dal grafico, otteniamo uguale probabilità dell’1,7% di estrarre Dicembre 2012 dal dataset con un numero sufficiente di estrazioni.

Aggiunta del prezzo medio al dataset.

Approfittiamo dei dati a disposizione per aggiungere la colonna del prezzo medio mensile per ogni riga del dataset, essendoci attualmente soltanto il prezzo mediano.

#Aggiungiamo al dataset una colonna con il prezzo medio degli immobili

realestate_stats$mean_price = (realestate_stats$volume/realestate_stats$sales)*1000000

Valutare l’efficacia delle inserzioni.

Procediamo ora a rapportare numero di vendite a inserzioni attive per verificare l’efficacia di conversione delle inserzioni in vendite, rappresentando tutto in un lollipop chart.

#Per valutare l'efficacia degli annunci di vendita, rapportiamo le vendite mensili alle inserzioni attive dello stesso mese

realestate_stats$listings_efficiency = realestate_stats$sales/realestate_stats$listings

#prima di poter procedere a costruire il grafico, necessitiamo delle medie della variabile listings_efficiency per poter meglio rappresentare l'efficacia per città

realestate_listingse_summary = realestate_stats %>%
  group_by(city) %>%
  summarise(listings_efficiency = mean(listings_efficiency))

#costruiamo il grafico 

ggplot(realestate_listingse_summary, aes(x=listings_efficiency, y=city)) +
  geom_segment(aes(x=0, xend=listings_efficiency, y=city, yend=city), color="grey", size = 1) +
  geom_point(aes(x= listings_efficiency, y = city), color="lightcoral", size=5) +
  theme_light() +
  theme(
    panel.grid.major.x = element_blank(),
    panel.border = element_blank(),
    axis.ticks.x = element_blank(),
    plot.title.position = "plot"
  ) +
  labs(x="Efficacia delle inserzioni", y="Città", 
       title = "Grafico di efficacia delle inserzioni",
       subtitle = "Rappresentazione della media del rapporto fra vendite effettuate e inserzioni totali per ogni mese")
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Come si evince dal grafico. Bryan-College Station ha la maggior efficienza di conversione delle inserzioni attive in vendite per ogni mese.

Di seguito mostriamo anche un print dei dati utilizzati.

print(realestate_listingse_summary)
## # A tibble: 4 × 2
##   city                  listings_efficiency
##   <chr>                               <dbl>
## 1 Beaumont                           0.106 
## 2 Bryan-College Station              0.147 
## 3 Tyler                              0.0935
## 4 Wichita Falls                      0.128

Convertendo il rapporto in percentuale, ci rendiamo conto che:

realestate_listingse_summary$percent = realestate_listingse_summary$listings_efficiency*100
print(realestate_listingse_summary)
## # A tibble: 4 × 3
##   city                  listings_efficiency percent
##   <chr>                               <dbl>   <dbl>
## 1 Beaumont                           0.106    10.6 
## 2 Bryan-College Station              0.147    14.7 
## 3 Tyler                              0.0935    9.35
## 4 Wichita Falls                      0.128    12.8

Bryan-College Station in media converte il 14.7% di inserzioni attive su scala mensile.

Ulteriori considerazioni sul dataset.

Costruzione di una serie storica con dati di vendita mensile.

#Ulteriori considerazioni sul dataset

#Creiamo una serie storica delle vendite delle 4 città del dataset comparandole in un unico grafico

#Innanzitutto creiamo un gruppo con le città del dataset

sales_group_data = realestate_stats %>%
  group_by(city, year, month) %>%
  summarise(total_sales = sum(sales, na.rm = TRUE)) %>%
  ungroup() %>%
  mutate(date = as.Date(paste(year, month, "01", sep = "-")))
## `summarise()` has grouped output by 'city', 'year'. You can override using the
## `.groups` argument.
#Costruiamo il grafico

ggplot(sales_group_data, aes(x = date, y = total_sales, group = city, color = city))+
  geom_line(size = 1.2)+
  theme_minimal()+
  labs(title = "Serie storica comparativa delle vendite per città",
       x = "Anno",
       y = "Numero di vendite",
       color = "Città")+
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5))+
  facet_wrap(~ city, scales="free_y")

Le prime considerazioni sul grafico mostrano una certa stagionalità del numero di vendite, che tendono a scendere considerevolmente nel periodo invernale in tutte le città per poi risalire nei mesi centrali con un comportamento a “onda”.

Notiamo anche come le vendite sembrino in trend di salita in tutte le città tranne che a Wichita Falls, in cui non si registrano tendenza in salita significative nei 5 anni.

Uso dei boxplot per confrontare la distribuzione del prezzo mediano nelle città.

#Confrontiamo la distribuzione del prezzo mediano delle case per le varie città
#utilizzando 4 boxplot differenti

#costruiamo il grafico
ggplot(realestate_stats, aes(x = city, y = median_price))+
  geom_boxplot(
    color = "indianred4",
    fill = "indianred3",
    alpha = 0.2,
    outlier.colour = "mediumvioletred",
    outlier.fill = "mediumvioletred",
    outlier.size = 3,
  )+
  theme_minimal()+
  labs(title = "Distribuzione del prezzo mediano per le varie città",
       x = "Città",
       y = "Prezzo Mediano")+
  theme(plot.title = element_text(hjust = 0.5))

Come visibile dalla comparazione dei boxplot, Bryan-College Station è la città che mostra una distribuzione del prezzo mediano dalle modalità più alte rispetto a tutte le altre città, mentre Wichita Falls quella con le modalità più basse. Tyler è l’unica città a non presentare valori outliers nella distribuzione.

Uso di un grafico a barre per rappresentare il volume totale di vendita categorizzato per città e diviso per anni.

#Prendiamo in considerazione ora il valore totale delle vendite diviso per città e anni

#Usiamo la library hrbrthemes e poi aggreghiamo i dati.
library("hrbrthemes")

volume_group = realestate_stats %>%
  group_by(year, city) %>%
  summarise(total_volume_data = sum(volume, na.rm = TRUE)) %>%
  ungroup()

#costruiamo il grafico

ggplot(volume_group, aes(x = city, y = total_volume_data, fill = factor(year)))+
  geom_bar(stat="Identity", color="#e9ecef", position=position_dodge(), alpha=0.6)+
  scale_fill_manual(values = c("#69b3a2", "#404080", "#FF6347", "#4682B4", "#FFA500"))+
  theme_ipsum()+
  labs(fill = "Anni", title = "Distribuzione del volume delle vendite",
       subtitle = "Dati divisi per anno e città",
       x= "Città", y ="Volume totale in mil$")+
  theme(axis.text.x = element_text(angle=45, hjust=1),
        plot.title.position = "plot")

Il grafico evidenzia chiaramente come Bryan-College Station e Tyler abbiano aumentato i volumi di vendita nel 2013 e 2014, effetto che si osserva moderatamente anche in Beaumont. Wichita Falls invece ha volumi di vendita (in mil$) più bassi rispetto a tutte le altre città del dataset.

Grafico del totale vendite mensili per città.

#grafico a barre sovrapposte con totale delle vendite

sales_grouping = realestate_stats %>%
  group_by(city, month) %>%
  summarise(total_sales = sum(sales, na.rm = TRUE)) %>%
  ungroup()

ggplot(sales_grouping, aes(x = as.factor(month), y = total_sales, fill = city)) +
  geom_bar(stat = "identity", position = "Stack") +
  scale_fill_hue(c = 40)+
  theme_minimal()+
  labs(title = "Totale delle vendite mensili per ogni città",
       x = "Mese",
       y = "Totale vendite",
       fill = "Città")+
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  )

Consideriamo anche la versione normalizzata del grafico.

ggplot(sales_grouping, aes(x = as.factor(month), y = total_sales, fill = city)) +
  geom_bar(stat = "identity", position = "fill") +
  scale_fill_hue(c = 40)+
  theme_minimal()+
  labs(title = "Distribuzione normalizzata delle vendite mensili",
       x = "Mese",
       y = "Totale vendite",
       fill = "Città")+
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  )+
  scale_y_continuous(labels = scales::percent)

Come ipotizzato da precedenti considerazioni sulla serie storica e sulla distribuzione del volume delle vendite, confermiamo che Tyler e Bryan-College Station sono le città che mostrano il maggior numero di vendite, con Wichita che presenta dati marginali rispetto alle altre quattro. I dati di Tyler e Bryan-College sembrano occupare in percentuale la maggior parte della distribuzione.

Procediamo a divedere il grafico non normalizzato per anni, inserendo quindi una divisione per mesi, anni e città.

#Proviamo a includere anche la divisione in anni creando grafici a barre sovrapposte divisi.

sales_grouping = realestate_stats %>%
  group_by(city, year, month) %>%
  summarise(total_sales = sum(sales, na.rm = TRUE)) %>%
  ungroup()

ggplot(sales_grouping, aes(x = as.factor(month), y = total_sales, fill = city)) +
  geom_bar(stat = "identity", position = "stack") +
  scale_fill_hue(c = 40) +
  theme_minimal() +
  labs(title = "Totale delle vendite mensili per ogni città",
       x = "Mese",
       y = "Totale vendite",
       fill = "Città") +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  ) +
  facet_wrap(~ year, ncol = 1)

Come esercizio grafico, possiamo rappresentare la medesima situazione con una heatmap.

#usiamo gli stessi dati per una heatmap

library(ggplot2)
library(dplyr)

monthly_sales_grouping = realestate_stats %>%
  group_by(city, year, month) %>%
  summarise(total_sales = sum(sales, na.rm = TRUE)) %>%
  ungroup()

heatmap_plot = ggplot(monthly_sales_grouping, aes(x = factor(month, levels = 1:12), y = city, fill = total_sales)) +
  geom_tile(color = "white") +
  facet_wrap(~ year, ncol = 1) +
  scale_fill_gradient(low = "white", high = "lightcoral") +
  labs(title = "Heatmap delle Vendite Mensili per Città e Anno",
       x = "Mese",
       y = "Città",
       fill = "Vendite Totali") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 0, hjust = 1))

print(heatmap_plot)

Avendo aggiunto la variabile al dataset, vale inoltre la pena esplorare l’evoluzione del prezzo medio su una serie storica divisa per città, utilizzando uno stacked area chart.

#Approfittiamo per costruire una serie storia sul prezzo medio
mean_group_data = realestate_stats %>%
  group_by(city, year, month) %>%
  summarise(total_mean_price = sum(mean_price, na.rm = TRUE)) %>%
  ungroup() %>%
  mutate(date = as.Date(paste(year, month, "01", sep = "-")))

#Costruiamo il grafico

ggplot(mean_group_data, aes(x = date, y = total_mean_price, group = city, fill = city))+
  geom_area(alpha = 0.6, color = "black", size = 0.5)+
  theme_minimal()+
  labs(title = "Serie storica del prezzo medio per città",
       x = "Anno",
       y = "Prezzo medio",
       fill = "Città")+
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5))+
  facet_wrap(~ city, scales = "free_y")+
  scale_y_continuous(labels = scales::comma)

Ulteriori considerazioni.

Analizzando quanto emerso dai dati elaborati in questo dataset, possiamo partire dal grafico di efficacia delle inserzioni per notare come Wichita Falls, seconda per media del rapporto fra vendite effettuate e inserzioni totali, in realtà sia anche quella che mostra un andamento più piatto delle vendite in termini di valori assoluti in mil$ e per numero assoluto di vendite negli anni considerati. Questi dati e la distribuzione del prezzo mediano di Wichita Falls rappresentata nel box plot ci fanno ipotizzare un momento di crisi del mercato immobiliare di quell’area del Texas, con una domanda generalmente bassa.

Anche il prezzo medio degli immobili di Wichita Falls non presenta significativi trend o evoluzioni nell’arco dei cinque anni considerati. Al contrario, Bryan-College Station subisce un chiaro trend di salita del prezzo medio negli ultimi due anni del dataset, in parte visibile anche in Tyler.

Per quanto riguarda la città di Tyler osserviamo come i dati in volume e numero di vendite, confrontati con l’efficacia relativamente inferiore di conversione delle inserzioni, ci suggeriscano che si possa ottimizzare il dato sull’efficacia di conversione per portare il mercato di quell’area ad ottenere performance potenzialmente superiori.