title: “Progetto di Statistica Descrittiva”
author: “Diego Amelio”
date: “2025-04-30”
output: html_document

1. Analisi delle variabili

db = read.csv("realestate_texas.csv")
str(db)
## '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 ...
summary.data.frame(db)
##      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
head(db,5)
##       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

Le otto variabili (colonne) identificate nel database db (240 righe), tramite le funzioni str() e summary.data.frame() sono le seguenti:

city: città di riferimento, variabile qualitativa nominale (le modalità non hanno un ordinamento naturale)

year: anno di riferimento, variabile quantitativa discreta (int) su scala di intervalli

month: mese di riferimento, variabile quantitativa discreta (int) su scala di intervalli.

Nota1: si potrebbero combinare le variabili year e month aggiungendo una nuova varabile “date” di tipo date, per avere dei grafici “serie storica” di vari anni con passo mensile

Nota2: noi useremo year e month come dei fattori (variabili qualitative)

sales: numero totale di vendite, variabile quantitativa discreta (int) su scala di rapporti

volume: valore totale delle vendite (in milioni di dollari), variabile quantitativa continua (num) su scala di rapporti

median_price: prezzo mediano di vendita (in dollari), variabile quantitativa continua (num) su scala di rapporti

listings: numero totale di annunci attivi, variabile quantitativa discreta (int) su scala di rapporti.

Nota: per le variabili sales e listings, se si fosse espresso il valore in migliaia anziché in unità, sarebbe stato adeguato anche usare un tipo num (variabile quantitativa continua), anziché int

months_inventory: quantità di tempo necessaria per vendere tutte le inserzioni correnti, espresso in mesi, variabile quantitativa continua (num) su scala di rapporti

Sulle quantitative, continue (sales, volume, median_price, months_inventory) e discrete (listings), e loro derivate (es mean_price, inventory, listing_effectiveness - verranno definite successivamente) si possono eseguire analisi di tendenza centrale, dispersione, correlazione

Le quantitative discrete (year, month) e la qualitativa nominale (city) si possono usare per fare confronti tra gruppi (tra città) e individuare trend storici (di anno in anno) o ciclicità stagionali (variazioni mese per mese)

1.1 Analisi preliminare dei record del database

Prima di fare sul database analisi aggregate (non specifiche per città e/o mese e anno) controlliamo 1) se ci sono valori nulli 2) che le righe siano equamente distribuite tra le città e nel tempo (mesi e anni). Per fare questo controlliamo come si distribuiscono le frequenze delle righe per le varie città, anni e mesi

for (v in names(db)) {
  cat("Valori nulli nella variabile", v, "=", sum(is.na(db[[v]])), "\n")
}
## Valori nulli nella variabile city = 0 
## Valori nulli nella variabile year = 0 
## Valori nulli nella variabile month = 0 
## Valori nulli nella variabile sales = 0 
## Valori nulli nella variabile volume = 0 
## Valori nulli nella variabile median_price = 0 
## Valori nulli nella variabile listings = 0 
## Valori nulli nella variabile months_inventory = 0
N_records=dim(db)[1] #a N_records assegniamo il numero di record nel database
colors_by_city=c("lightblue", "green", "red", "yellow")
records_by_city=table(db$city)/N_records
barplot(records_by_city,
        main="Distribuzione dei record del database",
        xlab="Città",
        ylab="frequenze relative",
        col=colors_by_city,
        ylim = c(0, 0.3)     # range asse y
        )

records_by_year=table(db$year)/N_records
colors_by_year=heat.colors(length(records_by_year))
barplot(records_by_year,
        main="Distribuzione dei record del database",
        xlab="Anno",
        ylab="frequenze relative",
        col=colors_by_year,
        ylim = c(0, 0.3) 
        )

records_by_month=table(db$month)/N_records
colors_by_month=terrain.colors(length(records_by_month))
barplot(records_by_month,
        main="Distribuzione dei record del database",
        xlab="Mese",
        ylab="frequenze relative",
        col=colors_by_month,
        ylim = c(0, 0.12)
        )

Le tre distribuzioni risultano tutte uniformi, quindi non ci sono città, anni o mesi più rappresentati/misurati di altri. Nota: Le singole righe della tabella sono “registrazioni”, per città, mese e anno di un certo gruppo di vendite, non singole compravendite.

Procediamo con la determinazione degli indici di posizione, variabilità e forma delle variabili quantitative.

2 Indici di posizione, variabilità e forma

Costruiamo una funzione che, operando su una variabile, restituisce una lista contenente gli indici di posizione, variabilità e forma.

  indici = function(variabile){
    stat=summary(variabile)#assegniamo l'output della funzione summary al vettore temporaneo stat
    
    #indici di posizione
    minimo=stat[1]
    primoQ=stat[2]
    media=stat["Mean"]
    mediana=stat["Median"]
    terzoQ=stat[5]
    massimo=stat[6]
    
    #indici di variabilità
    range_=massimo-minimo
    DIQ=terzoQ-primoQ #differenza interquartile
    varianza=var(variabile)
    sigma=sd(variabile)#deviazione std
    if (media!=0){
      coeff_di_var=sigma/media}
      else{
        coeff_di_var=NA
      }
    
    
    
    #indici di forma
    asimmetria=skewness(variabile)
    if (asimmetria>0){
      print("asimmetria positiva (coda a destra)")
    } else if (asimmetria<0){
      print ("asimmetria negativa (coda a sinistra)")
    } else{
      print("perfettamente simmetrica")
      
    }
    curtosi=kurtosis(variabile)-3
    if (curtosi>0){
      print("curtosi positiva, leptocurtica")
    } else if (curtosi<0){
      print("curtosi negativa, platicurtica")
    } else{
      print("curtosi nulla, mesocurtica")
    }
    risultato = c( minimo, primoQ, mediana, media, terzoQ, massimo, range_,
                   DIQ,varianza,sigma, coeff_di_var, asimmetria, curtosi)
    #per comodità di accesso e manipolazione, visto l'elevato numero di indici contenuti nel vettore risultato, assegniamo anche dei nomi alle varie entry del vettore risultato
    names(risultato)=c( "minimo", "Q1", "mediana", "media", "Q3", "massimo", "range_",
                        "DIQ","varianza","sigma", "coeff_di_var", "asimmetria", "curtosi")
    
    return(risultato)
  }


variabili=c("sales", "volume", "median_price", "listings", "months_inventory") #definiamo un vettore di stringhe con i nomi delle variabili quantitative, che useremo per iterare sulle variabili che ci interessano
sommario_lista=list() #inizializziamo a lista vuota un oggetto che conterrà i vari output della funzione indici() chiamata su tutte le variabili di interesse

for (v in variabili){
  #stampa il nome della varibile
  print(v)
  sommario_lista[[v]]=indici(db[[v]])#ogni entry di sommario_lista prende l'output (vettore di statistiche) della funzione indici()
  
} 
## [1] "sales"
## [1] "asimmetria positiva (coda a destra)"
## [1] "curtosi negativa, platicurtica"
## [1] "volume"
## [1] "asimmetria positiva (coda a destra)"
## [1] "curtosi positiva, leptocurtica"
## [1] "median_price"
## [1] "asimmetria negativa (coda a sinistra)"
## [1] "curtosi negativa, platicurtica"
## [1] "listings"
## [1] "asimmetria positiva (coda a destra)"
## [1] "curtosi negativa, platicurtica"
## [1] "months_inventory"
## [1] "asimmetria positiva (coda a destra)"
## [1] "curtosi negativa, platicurtica"
sommario_db=as.data.frame(t(as.data.frame(sommario_lista)))#trasforma in dataframe e traspone

print(sommario_db, digits=4)
##                     minimo        Q1   mediana     media        Q3   massimo
## sales               79.000    127.00    175.50 1.923e+02    247.00    423.00
## volume               8.166     17.66     27.06 3.101e+01     40.89     83.55
## median_price     73800.000 117300.00 134500.00 1.327e+05 150050.00 180000.00
## listings           743.000   1026.50   1618.50 1.738e+03   2056.00   3296.00
## months_inventory     3.400      7.80      8.95 9.193e+00     10.95     14.90
##                     range_      DIQ  varianza     sigma coeff_di_var asimmetria
## sales               344.00   120.00 6.344e+03    79.651       0.4142    0.71810
## volume               75.38    23.23 2.773e+02    16.651       0.5371    0.88474
## median_price     106200.00 32750.00 5.136e+08 22662.149       0.1708   -0.36455
## listings           2553.00  1029.50 5.666e+05   752.708       0.4331    0.64950
## months_inventory     11.50     3.15 5.307e+00     2.304       0.2506    0.04098
##                  curtosi
## sales            -0.3132
## volume            0.1770
## median_price     -0.6230
## listings         -0.7918
## months_inventory -0.1744

3 Identificazione delle variabili con maggiori variabilità e asimmetria

Per determinare la variabile con più alta variabilità è opportuno usare il coefficiente di variazione, numero adimensionale definito come il rapporto tra la deviazione standard e la media, variabili dimensionali ma omogenee.

Il coefficiente di variazione, infatti, essendo adimensionale, permette di confrontare la variabilità tra variabili non omogenee, quindi non confrontabili direttamente (come ad esempio un prezzo e un numero di annunci). Corollario: essendo adimensionale, il coefficiente di variazione è, in particolare, anche invariante per fattori di scala: per esempio, la variabile prezzi può essere espressa indifferentemente in euro o in milioni di euro, il coefficiente di variazione non dipende dalla scala usata per misurare la variabile (il fattore di scala si semplifica tra numeratore e denominatore).

Nota: in questo caso non ci sono controindicazioni a usare il coefficiente di variazione (che ha la media a denominatore), in quanto tutte le variabili in gioco sono variabili positive (non avrebbero senso volumi, prezzi, annunci ecc. negativi o nulli). In ogni caso, basta osservare i minimi delle distribuzioni per constatare che tutte le distribuzioni si sviluppano interamente a destra dello zero.

La variabile con maggiore variabilità è il volume, con un coefficiente di variazione di 0.5370536 e si può identificare per ispezione del dataframe sommario_db. Qualora l’oggetto sommario_db contenesse molte righe (che poi sarebbero le variabili/colonne del database originario), si potrebbe cercare con una funzione il massimo della colonna coefficiente di variazione nell’oggetto sommario.

trova_massimo=function(db, X, abs_value=FALSE){
  if (abs_value){
    valore_massimo = max(abs(db[[X]]), na.rm=TRUE)
    riga_massima = which(abs(db[[X]])==valore_massimo)
    valore_massimo=db[riga_massima,X]
    
    
  }
  else {
    valore_massimo = max(db[[X]], na.rm=TRUE)
    riga_massima = which(db[[X]]==valore_massimo)
  }
  
  
  
  
  
  nome_riga = rownames(db)[riga_massima]

  # stampa risultato
  cat("Valore massimo:", valore_massimo, "\n")
  cat("Nome della riga:", nome_riga, "\n")
  
  
}

trova_massimo(sommario_db, "coeff_di_var")
## Valore massimo: 0.5370536 
## Nome della riga: volume

Per misurare l’asimmetria di una distribuzione possiamo utilizare il parametro “skewness”, definito come il momento di terzo ordine (ordine dispari per misurare l’asimmetria) della distribuzione rispetto alla media (=integrale degli scarti elevati al cubo pesati con la densità di frequenza relativa), normalizzato rispetto alla variabilità (deviazione standard), opportunamente elevata al cubo. La skewness risulta così anch’essa un parametro adimensionale.

La variabile con maggiore asimmetria (in valore assoluto - il segno della skewness identifica il verso dell’asimmetria) è il volume, con una skewness di 0.88474203. Il valore positivo della skewness indica una coda che si prolunga verso i valori elevati, che infatti alzano la media al di sopra della mediana. L’asimmetria positiva è quella tipica della distribuzione di variabili come ricchezza e reddito, con la maggioranza dei valori che si addensano al di sotto della media. Nel nostro caso essendo il volume delle vendite con asimmetria positiva, significa che nella maggioranza delle registrazioni si osservano volumi di vendite al di sotto della media, con una coda a destra (verso i valori elevati): in sostanza ci sono delle osservazioni (con frequenza bassa ma non trascurabile) di valori elevati - e molto elevati - di volumi di vendita.

Ricorrendo alla funzione trova_massimo, applicata alla statistica “asimmetria” si ha:

trova_massimo(sommario_db, "asimmetria", abs_value = TRUE)
## Valore massimo: 0.884742 
## Nome della riga: volume

Individuata una variabile di interesse, come ad esempio il volume, rappresentiamo ora la distribuzione di frequenze della variabile volume:

d=density(db$volume)

plot(d,
     main = "Distribuzione dei volumi di vendita",
     xlab = "Volume [M$/month]",
     ylab= "Densità di frequenza [1/M$]",
     col = "darkgreen",
     ylim=c(0,1.2*max(d$y)),
     lwd = 2)

abline(v = sommario_db["volume","minimo"], col = "green4", lty = 2)
abline(v = sommario_db["volume","Q1"], col = "blue", lty = 2)
abline(v = sommario_db["volume","mediana"], col = "red", lty = 2)
abline(v = sommario_db["volume","media"], col = "black", lty = 2)
abline(v = sommario_db["volume","Q3"], col = "blue", lty = 2)
abline(v = sommario_db["volume","massimo"], col = "green4", lty = 2)

# Aggiunta etichette (usiamo text())
y_pos =max(d$y) * 0.3  # posizione verticale per le etichette, sfalseranno le etichette ponendole a quota y_pos e 2 y_pos
text(sommario_db["volume","minimo"], 2*y_pos, "minimo", col = "green4", pos = 3, cex = 0.8)
text(sommario_db["volume","Q1"], y_pos, "Q1", col = "blue", pos = 3, cex = 0.8)
text(sommario_db["volume","mediana"], 2*y_pos, "Mediana", col = "red", pos = 3, cex = 0.8)
text(sommario_db["volume","media"], y_pos, "Media", col = "black", pos = 3, cex = 0.8)
text(sommario_db["volume","Q3"], 2*y_pos, "Q3", col = "blue", pos = 3, cex = 0.8)
text(sommario_db["volume","massimo"], y_pos, "massimo", col = "green4", pos = 3, cex = 0.8)

estremo_inferiore=sommario_db["volume","Q1"]-1.5*sommario_db["volume","DIQ"]

if(sommario_db["volume","minimo"]<estremo_inferiore){
  abline(v = estremo_inferiore, col = "purple", lty = 2)
  text(estremo_inferiore, 2*y_pos, "limite outlier", col = "purple", pos = 3, cex = 0.8)
  
}

estremo_superiore=sommario_db["volume","Q3"]+1.5*sommario_db["volume","DIQ"]

if(sommario_db["volume","massimo"]>estremo_superiore){
  abline(v = estremo_superiore, col = "purple", lty = 2)
  text(estremo_superiore, 2*y_pos, "limite outlier", col = "purple", pos = 3, cex = 0.8)
  
}

l’asimmetria della distribuzione della variabile volume si evince anche da

  1. ampiezza secondo quartile inferiore rispetto all’ampiezza del terzo quartile, e ampiezza primo quartile molto inferiore all’ampiezza del quarto quartile
  2. la presenza nella distribuzione di outlier per eccesso (ma senza che ci siano outliers per difetto)

4. Distribuzione classi di frequenze della variabile sales

Selezioniamo ora la variabile quantitativa sales.

cat("la variabile sales, numero di vendite, registra osservazioni tra un minimo di", sommario_db["sales", "minimo"], "e un massimo di", sommario_db["sales", "massimo"]) 
## la variabile sales, numero di vendite, registra osservazioni tra un minimo di 79 e un massimo di 423

Costruiamo un grafico a barre per rappresentare la distribuzione della variabile sales

divisioni_sales=seq(70,430,30)# crea un vettore di elementi da 70 a 430 con passo 30

db$sales_cl=cut(db$sales,breaks=divisioni_sales) #crea la variabile aggiuntiva sales_cl nel database assegnando come valore la classe tra le classi individuate dal vettore divisioni_sales 

ni=table(db$sales_cl) # ni raccoglie le frequenze assolute delle classi di numero di vendite
fi=ni/N_records #dividendo ni per il numero totale di righe si ottengono le frequenze relative

#creiamo un grafico a barre
barplot(fi,
        main="distribuzione numero di vendite",
        xlab="classi di numero di vendite [Nr./mese]",
        ylab="frequenze relative",
        ylim=c(0, round(max(fi),1)),
        col="lightblue")

La distribuzione di frequenze relative delle vendite si presenta come una distribuzione asimmetrica positiva (coda a destra). La maggiorparte delle registrazioni vedono un numero di vendite sotto la media. Un numero minoritario di registrazioni vedono un numero maggiore o molto maggiore della media. La distribuzione appare bimodale (classe 100-130 e classe 280-310), ma la seconda moda non è molto evidente e potrebbe essere dovuta al caso.

Calcoliamo ora l’indice di Gini di questa distribuzione, parametro che varia tra 0 (omogeneità massima, massima concentrazione) e 1 (eterogeneità massima, equidistribuzione)

numero_classi=length(fi)
gini= numero_classi/(numero_classi-1)*(1-sum(fi^2))

cat("L'indice di Gini della variabile sales è", round(gini,2))
## L'indice di Gini della variabile sales è 0.96

Essendo un valore prossimo a 1 si può concludere che la distribuzione delle vendite è molto eterogenea, prossima alla distribuzione uniforme.

5 Calcolo delle probabilità

La probabilità che una riga a caso di questo dataset riporti la città “Beaumont” è 25%. Infatti, nell’analisi preliminare del database abbiamo osservato che la frequenza relativa nel database delle righe con città= Beaumont era esattamente 0.25.

La probabilità che una riga a caso riporti il mese di luglio è, dall’analisi preliminare del database (risultava unadistribuzione uniforme tra i 12 mesi),

cat("1/12=", 1/12)
## 1/12= 0.08333333

La probabilità che una riga riporti dicembre 2012 è pari a

cat("4/240=1/60=", 1/60)
## 4/240=1/60= 0.01666667

Quest’ultimo risultato, a rigore, è stato ottenuto dall’esplorazione diretta del database, in cui ogni riga ha una combinazione unica di mese, anno e città (12 mesi x 5 anni x 4 città=240 righe tot). Supponendo di avere un database di dimensioni molto maggiori, impossibile da esplorare per ispezione diretta, contiamo in modo automatico le righe “favorevoli”

Nfavorevoli=sum(db$year == 2012 & db$month == 12)#contiamo le righe favorevoli, una riga è favorevole se ha contemporaneamente anno==2012 e mese ==12

probabilità=Nfavorevoli/N_records

cat("la probabilità di estrarre a caso dal database una riga relativa a dicembre 2012 è: ",probabilità)
## la probabilità di estrarre a caso dal database una riga relativa a dicembre 2012 è:  0.01666667

6 Creazione di nuove variabili

Analizzando un database è spesso utile esplicitare altre variabili, funzioni delle variabili disponibili.

Creiamo cinque nuove variabili: 1) la variabile mean_price, definita come il rapporto tra la variabile volume e la variabile sales

db$mean_price=db$volume*1000000/db$sales #il fattore 1000000 serve per convertire in dollari i milioni di dollari
  1. la variabile inventory, definita come il numero di case nel portafoglio, pari al prodotto di months_inventory con sales
db$inventory=round(db$months_inventory*db$sales,0)
  1. la variabile listing_effectiveness, che possiamo definire come il rapporto tra il tasso di vendita (sales/inventory) e il tasso di copertura degli annunci (listings/inventory).
db$listing_effectiveness=db$sales/db$listings
  1. la variabile listing_effectiveness2, che possiamo definire come il rapporto tra il volume venduto (dollari) e il numero di annunci.
db$listing_effectiveness2=round(db$volume*1000000/db$listings,2)

La variabile listing_effectiveness2 sottintende a) l’ipotesi (realistica) che i ricavi dell’agenzia siano proporzionali al volume venduto e b) (semplificativa) che i profitti per annuncio siano a loro volta proporzionali ai ricavi.

Non ci sono dati per evidenziare l’effetto sui volumi di altre variabili, oltre al numero di annunci, sotto il controllo dell’agenzia come l’efficacia/il tipo dell’annunncio, l’esperienza e la quantità del personale assegnato a una data zona ecc.

  1. la variabile redditivity, che possiamo definire come il rapporto tra listing_effectiveness2, e il numero di mesi di months_inventory. La variabile redditivity ha quindi dimensioni [dollari/(annuncio x mese)]. Il prodotto annunci x mese è una misura dell’impiego di risorse da parte dell’agenzia (il lavoro del personale e l’inserzione del ), e in prima approssimazione, dei costi.
db$redditivity = db$listing_effectiveness2/db$months_inventory

#7 Analisi condizionata

Vogliamo studiare l’effetto delle variabili città, mese e anno sulle variabili quantitative nel database.

Costruiamo una funzione che rappresenti la distribuzione della variabile quantitativa yy, al variare della variabile (fattore) xx.

Scriviamo una funzione che plotti la distribuzione di una variabile quantitativa yy tramite boxplot e violino (entrambi i tipi di grafico servono a rappresentare un’intera distribuzione, il violino integralmente, il boxplot in modo più riassuntivo/astratto ma più leggibile):

my_distribuzioni=function(db, xx, yy, UoMxx="", UoMyy=""){#i parametri UoMxx e UdMyy sono stringhe, le unità di misura delle variabili xx e yy  
 
  
  if (xx == "city") {
    set_colori = colors_by_city
  } else if (xx == "month") {
    set_colori = colors_by_month
    db[[xx]] = factor(db[[xx]], levels = 1:12, labels = month.abb)  # esempio: Gen, Feb...
  } else if (xx == "year") {
    set_colori = colors_by_year
    db[[xx]] = factor(db[[xx]])  # forza year come fattore
  } else {
    set_colori = NULL
  }
 
  g=ggplot(data=db)+
    labs(title=paste("Distribuzioni di",yy,"in funzione di",xx),
         x=paste(xx, UoMxx),
         y=paste(yy, UoMyy))
    
  
  xx =  sym(xx)
  yy = sym(yy)
  
  g=g+
    geom_half_boxplot(aes(x=!!xx, y=!!yy, fill=!!xx), side="l" )+
    geom_half_violin(aes(x=!!xx, y=!!yy, fill=!!xx), side="r")+
    stat_summary(aes(x = !!xx, y = !!yy, group = !!xx,linetype = "Media"),
                 fun = mean,
                 geom = "crossbar",
                 width = 0.8,
                 fatten = 1,
                 color = "black") +
    scale_linetype_manual(
                  name = "Statistiche",         # Titolo della legenda
                  values = c("Media" = "dashed") # Etichetta + tipo di linea
                  )+
    scale_fill_manual(values = set_colori)
  
return(g)
    
}

Rappresentiamo la distribuzione di median_price in funzione della variabile city

my_distribuzioni(db, "city", "median_price",UoMyy="[$]")

Le quattro distribuzioni sembrano quattro distribuzioni diverse, anche se servirebbe un test statistico per poterlo concludere con una certa confidenza. In particolare le distribuzioni verde e rossa e rossa e blu hanno una certa sovrapposizione e non è detto che non siano due campioni diversi di una stessa distribuzione. Limitandoci a descrivere quello che osserviamo dal grafico, le quattro distribuzioni di median_price hanno quattro valori mediani diversi. Bryan-College Station è il mercato con i prezzi più alti, Wichita Falls quello con prezzi più bassi. Le ampiezze delle distribuzioni (variabilità) sono simili in valore assoluto, Wichita Falls è quella con la ampiezza maggiore ed è comunque una variabilità contenuta (l’intero range è contenuto in circa +/- 25% del valore centrale). Bryan-College station è l’unica distribuzione asimmetrica con una certa asimmetria positiva (media maggiore della mediana e coda verso i valori elevati), le altre tre distribuzioni sono circa simmetriche, con piccola asimmetria negativa.

Prima di passare ad un altro fattore, esaminiamo come si distribuisce la variabile mean_price nelle varie città

my_distribuzioni(db, "city", "mean_price", UoMyy="[$]")

Otteniamo una indicazione analoga a quanto ricavabile da median_price. In questo caso le distribuzione di Bryan_College Station appare simmetrica.

Passiamo ora alla distribuzione dei volumi di vendita

my_distribuzioni(db, "city", "volume", UoMyy = "[M$/month]")

La città che porta un volume maggiore è Tyler, che supera Bryan-College Station. Questo suggerisce che sales di Tyler supera sales di Bryan-College, abbastanza da sovracompensare il fatto che i prezzi di Bryan-College sono maggiori dei prezzi di Tyler. Stavolta emergono forti differenze sui range delle distribuzioni. I range appaiono molto più ampi per Bryan-College e Tyler, suggerendo una variabilità nel numero di vendite tra un mese e l’altro e/o tra un anno e l’altro; è anche possibile che, “a parità di vendite”, le case più costose vengano vendute in un periodo e le case meno costose in un altro periodo. Vista l’ampia variabilità del volume, potrebbe essere che con una domanda variabile di case ci siano dei periodi a maggiore domanda in cui si vendono più case e anche a un prezzo maggiore (causando i picchi positivi di volume) e periodi a minore domanda in cui si vendono meno case e anche a un prezzo minore (causando i picchi negativi di volume). In valori assoluti il range di variazione di Wichita Falls è inferiore, indicando una domanda più costante nel tempo.

my_distribuzioni(db, "city", "sales", UoMyy = "[Nr./month]")

La distribuzione del numero di vendite mensili, molto simile alla distribuzione del volume, conferma che è Tyler la città dove si vendono più case al mese, almeno in valori assoluti. Per concludere che a Tyler il mercato sia “più fluido” rispetto alle altre città, con le case “più vendibili” servirebbe, oltre a un test statistico, anche normalizzare i numeri di vendite rispetto ad esempio al numero di case in tutta la città, o meglio ancora, il numero delle case in vendita. In sostanza dobbiamo normalizzare rispetto alla dimensione del mercato, in generale diverso da città a città. Ci può aiutare la variabile month_inventory che riporta l’ampiezza dell’insieme delle case in vendita (della nostra agenzia) espressa in numero di mesi di vendita (di attività della nostra agenzia), e che quindi è il rapporto tra case in vendita e vendite/mese.

my_distribuzioni(db, "city", "months_inventory", UoMyy = "[Nr.]")

Osservando queste distribuzioni del months_inventory sembra che Tyler, la città col maggior numero di vendite, sia anche quella con la “vendibilità” inferiore (months_inventory maggiore). Le due città con vendibilità maggiore sono Wichita Falls (che poi è quella con minore variabilità) e Bryan-College Station (che è quella con maggiore variabilità). La distribuzione del month_inventory è simmetrica per Tyler e Wichita Falls, asimmetrica negativa per Beaumont e Bryan-College Station. Dal semigrafico a violino si vede che Beaumont e Bryan-College Station station hanno delle distribuzioni bimodali, una moda maggiore vicina ai valori centrali e una moda minore vicina agli estremi inferiori, il che porterebbe a pensare a dei possibili picchi stagionali.

Esploriamo ora la distribuzione dell’efficacia degli annunci. Usiamo il più stategico listing_effectiveness2, che rapporta il volume mensile (dollari) e il numero di annunci

my_distribuzioni(db, "city", "listing_effectiveness2", UoMyy = "[$ / listing]")

Da questo grafico si nota che solo la distribuzione di Bryan-College Station si differenzia nettamente dalle altre. Mentre per le altre distribuzioni, valore mediano e medio del ritorno dell’annuncio sono entrambi circa 15000 dollari/annuncio, per Bryan-Collage Station si registra un valore mediano di 22000 dollari e medio (valore atteso) di 28000 dollari/annuncio, con outlier fino a 80000. A parità di altre condizioni, dovendo investire un dollaro aggiuntivo in annunci, converrebbe farlo sugli annunci di Bryan-College Station.

Vediamo ora come si comporta l’altro indice di merito, redditivity, che tiene conto anche del lavoro del personale attraverso anche il numero di mesi medi per i quali un immobile giace in agenzia.

my_distribuzioni(db, "city", "redditivity", UoMyy = "[$ / (listing x month)]")

Con l’indice di merito redditivity si osserva: 1) la differenziazione di Bryan-College Station con le altre città si fa più evidente. Dovendo investire in annunci e/o personale converrebbe farlo in questa città (volume generato più che doppio circa, a parità di risorse impiegate) 2) Wichita Falls, mercato con bassi volumi e minore variabilità (cioè minore rischio), si colloca alle spalle di Bryan-College Station. I costi fissi che incidono maggiormente in un mercato più piccolo e che non sono inclusi nel parametro redditivity, potrebbero però smentire questa indicazione.

Cambiamo variabili, e plottiamo le distribuzioni delle vendite in funzione dell’anno

my_distribuzioni(db, "year", "sales", UoMyy="[Nr. / month]")

Dal grafico si vede una crescita nel tempo del numero di vendite, eccezion fatta per l’anno 2011 rispetto al 2010. La variabilità delle vendite sembra aumentare con gli anni e appare elevata in generale, probabilmente per la componente di variabilità dovuta al mescolare registrazioni di mercati di città diverse.

Nota: Serve un upgrade della funzione my_distribuzioni in modo da considerare due variabili sull’asse x anziché una sola.

Continuiamo ad esplorare con la funzione my_distribuzioni()

my_distribuzioni(db, "year", "volume", UoMyy="[M$ / month]")

Le distribuzioni dei volumi di vendita assomigliano a quelle delle vendite.

my_distribuzioni(db, "month", "sales", UoMyy = "[Nr. / month]")

Con le vendite in funzioni dei mesi si nota:

  1. che i valori centrali delle distribuzioni sembrano seguire un andamento periodico, con un periodo di massimo da maggio ad agosto

  2. la variabilità delle registrazioni nel database non separate per città o anno è molto alta

Vediamo se c’è una stagionalità anche nei prezzi delle case

my_distribuzioni(db, "month", "median_price", UoMyy = "[$]")

Senza ulteriori analisi, solo da questo grafico, sembrerebbe ci sia una lieve tendenza all’aumento dei prezzi da gennaio ad agosto, il che, unitamente all’informazione che le vendite sembrano aumentare da gennaio all’estate, suggerisce che globalmente aumenti la domanda da gennaio ad agosto

my_distribuzioni(db, "month", "listing_effectiveness2", UoMyy="[$/listing]")

La resa degli annunci raggiunge un massimo da maggio ad agosto, che sembra quindi il periodo preferibile in cui spendere per maggiore promozione. Negli ultimi tre trimestri dell’anno la presenza di code a destra e outliers alza nettamente il valore atteso (media) rispetto al valore mediano

7. Analisi condizionata

Utilizziamo “dplyr” per manipolare i dati e creare dei summary di media, deviazione std e Coefficiente di variazione di una variabile yy raggruppata in base ai fattori xx1 e xx2.

my_summary=function(db, xx1, xx2, yy){#la funzione vuole riassumere media, deviazione std e CV, della variabile yy, raggruppata in base ai fattori xx1 e xx2
  xx1=sym(xx1)
  xx2=sym(xx2)
  yy=sym(yy)
  
  risultato=db%>%
    group_by(!!xx1, !!xx2)%>%
    summarise(media=mean(!!yy),
              dev.std=sd(!!yy), 
              CV=sd(!!yy)/mean(!!yy), 
              .groups="drop")
  
  
  
  return(risultato)
  
}
db_city_year_volume=my_summary(db, "city", "year", "volume")

Costruiamo poi una seconda funzione che a partire dal database-sommario realizzato, costruisca un grafico a barre di una statistica della variabile yy, media o Coefficiente di Variazione (CV), in funzione delle variabili fattori xx1 e xx2

my_barre=function(db, xx1, xx2, string_yy, statistic, UoMxx1="", UoMxx2="", UoMyy="", UoMstatistic="", pos="dodge", numdigits=2){
  
  #xx2 è la variabile che sarà usata per il colore di riempimento delle barre.
  if (xx2 == "city") {
    set_colori = colors_by_city
  } else if (xx2 == "month") {
    set_colori = colors_by_month
    db[[xx2]] = factor(db[[xx2]], levels = 1:12, labels = month.abb)  # esempio: Gen, Feb...
  } else if (xx2 == "year") {
    set_colori = colors_by_year
    db[[xx2]] = factor(db[[xx2]])  # forza year come fattore
  } else {
    set_colori = NULL
  }
  
  # Calcolo dinamico della larghezza
  n_groups = length(unique(db[[xx2]])) #conta quanti valori unici diversi ci sono nella variabile xx2, es. per mesi 12, anni 5, città 4
  width_dodge = ifelse(n_groups <= 5, 0.9, 1) #i valori 0.9 e 1 di larghezza sono stati trovati per tentativi lanciando questa funzione molte volte e osservando se il risultato grafico fosse soddisfacente
  
    if(pos=="dodge"){
      pos=position_dodge(width_dodge)
    }  
 
    string_xx1=xx1
    string_xx2=xx2
    string_statistic=statistic
    xx1 =  sym(xx1)
    xx2 =  sym(xx2)
    statistic = sym(statistic)
  
  
  
  
  g=ggplot(db, aes(x = factor(!!xx1), y = !!statistic, fill = !!xx2)) +
    geom_bar(stat = "identity",
           position = pos,
           color="black")+
    geom_text(aes(label = round(!!statistic, numdigits)),
              position = pos,
              angle = 90,           # ruota il testo
              hjust = 1.2,          # spinge il testo dentro la barra
              vjust = 0.4,          # centra verticalmente
              size = 2.3)+
    scale_fill_manual(values = set_colori)+
    labs(title=paste(string_statistic, "di",
                     string_yy, UoMstatistic,"in funzione di", string_xx2,
                     "raggruppati per", string_xx1, UoMxx1),
         x=paste(string_xx2, UoMxx2), 
         y=paste(string_statistic,"di",string_yy, UoMstatistic))
  
  return(g)
}
my_barre(db_city_year_volume, "city", "year", "volume","media",
         UoMstatistic="[M$/month]")

Wichita Falls a parte, che resta stabile, le altre tre città vedono un aumento di volumi di vendite nel corso dei 5 anni in esame. Beaumont e Wichita Falls hanno subito un lieve decremento dei volumi tra il 2010 e il 2011. Bryan-College Station e Tyler sono le due città non solo con i maggiori valori assoluti di volumi, ma mostrano anche i maggiori incrementi, che possono indicare due mercati immobiliari in sviluppo.

my_barre(db_city_year_volume, "city", "year", "volume","CV",UoMstatistic="[-]")

La variabilità dei volumi di vendita, rappresentato dal CV sembra rimanere costante da un anno all’altro. Bryan-College è l’unica città con una variabilità maggiore (CV medio circa 0.38), le altre città mostrano lo stesso valore di variabilità, circa 0.22.

I volumi medi mensili possono essere rappresentati anche invertendo l’ordine dei fattori, e cioè in funzione della città, raggruppati per anno.

my_barre(db_city_year_volume, "year", "city", "volume","media",UoMstatistic="[M$/month]")

Le informazioni in questo grafico sono le stesse del grafico precedente, all’interno di ogni gruppo (anno) si vede la classifica per volume, rosso, verde, blu, giallo; tra un gruppo e l’altro, si vede la crescita dei volumi, eccetto per il giallo (Wichita Falls).

Il volume, come le vendite, si presta a essere sommato, pertanto proviamo a rappresentare la stessa informazione con un grafico a barre sovrapposte:

my_barre(db_city_year_volume, "year", "city", "volume","media",UoMstatistic="[M$/month]", pos="stack")

Si nota sia la crescita complessiva, sia il cambio di proporzioni (rosso e verde crescono rispetto alle altre). Il cambio di proporzioni dei volumi di vendita nelle città negli anni si può evidenziare meglio con un grafico a barre sovrapposte normalizzato

my_barre(db_city_year_volume, "year", "city", "volume","media",UoMstatistic="[M$/month]", pos="fill")

Esploriamo ora l’andamento della variabile redditivity, che cerca di stimare la redditività dell’attività economica dell’agenzia.

  1. creiamo il database riassuntivo
db_city_month_redditivity=my_summary(db, "city", "month", "redditivity")
  1. usiamo il database riassuntivo per creare un grafico a barre della statistica “media” della variabile “redditivity”
my_barre(db_city_month_redditivity, "city", "month", "redditivity","media",
         UoMstatistic="[$/(listing xmonth)]", numdigits=0)

Da questo grafico si vede che la redditività di Bryan-College station è nettamente superiore alle altre città, al secondo posto Wichita Falls. Inoltre, all’interno di ciascun gruppo di barre (cioè per ciascuna città), si nota una andamento a S della redditività con i mesi dell’anno: cresce da gennaio all’estate, poi decresce e poi ha un rimbalzo positivo al mese di dicembre. La dinamica è simile per tutte le città, ma è molto accentuata per Bryan-College Station.

Rappresentando la variabilità (CV) si ottiene:

my_barre(db_city_month_redditivity, "city", "month", "redditivity","CV",
         UoMstatistic="[-]", numdigits=2)

Essendo i valori raggruppati per città e per mesi, la variabilità resta calcolata tra anni diversi. Si nota che la Bryan-College Station ha la variabilità massima (CV medio circa 0.9). Le altre città hanno registrato variabilità (negli anni) minore. La variabilità tende approssimativamente a salire nel corso dell’anno, cioè nel corso degli anni le redditività dei mesi di novembre sono variate tra loro più delle redditività dei mesi di febbraio.

my_barre(db_city_month_redditivity, "month", "city", "redditivity","media",
         UoMstatistic="[$/(listing xmonth)]", numdigits=0)

Da questo grafico si nota che la seconda redditività più alta, dietro a Bryan College Station, è il mercato di Wichita Falls.

Proviamo a correlare due statistiche della stessa variabile a partire da un database riassuntivo precedentemente preparato con la funzione my_summary().

my_plot=function(db, ff1, ff2, string_xx, string_yy, statistic_xx="media", statistic_yy="media", UoMstatistic_xx="", UoMstatistic_yy="", UoMff1="", UoMff2="", numdigits=2){
  
  #ff21 è la variabile che sarà usata per il colore di riempimento del cerchio esterno.
  if (ff1 == "city") {
    set_colori1 = colors_by_city
  } else if (ff1 == "month") {
    set_colori1 = colors_by_month
    db[[ff1]] = factor(db[[ff1]], levels = 1:12, labels = month.abb)  # esempio: Gen, Feb...
  } else if (ff1 == "year") {
    set_colori1 = colors_by_year
    db[[ff1]] = factor(db[[ff1]])  # forza year come fattore
  } else {
    set_colori1 = NULL
  }
  
  #ff2 è la variabile che sarà usata per il colore di riempimento del cerchio interno.
  if (ff2 == "city") {
    set_colori2 = colors_by_city
  } else if (ff2 == "month") {
    set_colori2 = colors_by_month
    db[[ff2]] = factor(db[[ff2]], levels = 1:12, labels = month.abb)  # esempio: Gen, Feb...
  } else if (ff2 == "year") {
    set_colori2 = colors_by_year
    db[[ff2]] = factor(db[[ff2]])  # forza year come fattore
  } else {
    set_colori2 = NULL
  }
  
  
 
    string_ff1=ff1
    string_ff2=ff2
    string_statistic_xx=statistic_xx
    string_statistic_yy=statistic_yy
    ff1 =  sym(ff1)
    ff2 =  sym(ff2)
    statistic_xx = sym(statistic_xx)
    statistic_yy = sym(statistic_yy)
  
  
  
  
  g=ggplot(db, aes(x = !!statistic_xx, y = !!statistic_yy)) +
    #punto esterno
    geom_point(aes(fill = !!ff1),size = 5, shape = 21, color = "black")+ 
    #punto interno
    geom_point(aes(fill = !!ff2),size = 3, shape = 21, color = "black")+ 
    
    #i colori sono passati con un vettore che concatena i due vettori di colori
    scale_fill_manual(values = c(set_colori2, set_colori1))+
    
    labs(
      title = paste(
        string_statistic_yy, "di", string_yy, UoMstatistic_yy, "\n",
        "in funzione di", string_statistic_xx, "di", string_xx, UoMstatistic_xx, "\n",
        "raggruppati per", string_ff1, UoMff1, "e", string_ff2, UoMff2
      ),
      x = paste(string_statistic_xx, "di", string_xx, UoMstatistic_xx),
      y = paste(string_statistic_yy, "di", string_yy, UoMstatistic_yy)
      ) +
      theme(
      plot.title = element_text(
        face = "bold",     # grassetto
        size = 10,         # dimensione del titolo
        hjust = 0.5,       # 0=sinistra, 0.5=centrato, 1=destra
        lineheight = 1.2   # altezza delle righe (migliora la leggibilità)
      )
      )#+
    #theme_classic()
  
  return(g)
}

Proviamo a correlare la media della redditività per mese e per città con la deviazione standard della redditività

my_plot(db_city_month_redditivity, "city", "month", "redditivity", "redditivity", statistic_xx="dev.std", statistic_yy="media", UoMstatistic_xx="[$/(listing x month)]", UoMstatistic_yy="[$/(listing x month)]", numdigits=0)

Media e devizione standard sembrano legate in media da una relazione lineare. Inoltre i punti gialli, blu e rossi sono addensati nella stessa area, da cui invece si discostano nettamente i punti verdi (Bryan-College Station), che appaiono separati anche tra loro.

Per cercare di evidenziare le differenze tra i punti eliminiamo il fattore di scala dalla variabilità, cioè correliamo la media della redditività con il coefficiente di variazione CV.

my_plot(db_city_month_redditivity, "city", "month", "redditivity", "redditivity", statistic_xx="CV", statistic_yy="media", UoMstatistic_xx="[-]", UoMstatistic_yy="[$/(listing x month)]", numdigits=2)

Se il CV (calcolato sulla variabilità nei cinque anni) fosse una misura di volatilità del mercato in generale, cioè una misura del rischio, allora a pari valore atteso (media, asse y), sarebbero preferibili i valori con volatilità minore (CV, asse x); a pari CV sarebbero preferibili punti a media maggiore. Con questi due criteri le coppie mese-città più redditizie su cui concentrare gli investimenti sarebbero Wichita-Falls, mesi di maggio, aprile, maggio, giugno, dicembre, unitamente a Bryan-College Station, mesi di novembre, maggio, agosto, luglio. Per individuare tra questi punti l’ottimo assoluto servirebbe conoscere la curva isopreferenza dell’investitore dell’agenzia.

Si noti che non ci sono punti ottimi di Tyler o Beaumont, che verrebbero tutti superati dai mesi migliori di Wichita-Falls.

Poiché però la variabilità è calcolata tra anni diversi, e negli anni i volumi medi sono aumentati (suggerendo che l’attività vada migliorando) una variabilità maggiore potrebbe indicare, piuttosto che un rischio maggiore, una crescita maggiore. Se la crescita passata fosse indicativa della crescita attesa, il CV maggiore sarebbe preferibile a un CV minore a pari redditività media. Con quest’altro criterio i punti verdi, cioè tutti i mesi di Bryan-College Station, sarebbero dominanti rispetto a tutti gli altri.

Raggruppiamo i dati per città-anno anziché città-mese:

db_city_year_redditivity=my_summary(db,"city", "year", "redditivity")
my_plot(db_city_year_redditivity, "city", "year", "redditivity", "redditivity", statistic_xx="CV", statistic_yy="media", UoMstatistic_xx="[-]", UoMstatistic_yy="[$/(listing x month)]", numdigits=2)

Gli anni più promettenti tra cui cercare l’ottimo assoluto sono Tyler 2013, Wichita Fallas 2014, Beaumont 2014, Bryan-College Station 2014 confermando che l’attività non sta aumentando solo di volume, ma anche di efficienza. Inoltre, la variabilità di ciascuna coppia anno-città è data dalla variabilità tra i mesi dell’anno: il mese peggiore della città verde, pur essendo “molto peggiore” della media con maggiore valore atteso, potrebbe risultare preferibile al migliore mese giallo.

In questo caso i punti preferibili diverrebbero tutti i punti verdi (tutti i mesi di Bryan-Colleg Station) e, a seguire, i punti rossi e blu.

Non ci resta che verificare gli andamenti storici della produttività per le quattro città, per ogni mese di ogni anno.

Aggiungiamo opportunamente una colonna “date” in cui combiniamo il contenuto delle colonne year e month (entrambi di tipo int) in una data

db$date = as.Date(paste(db$year, db$month, "28", sep = "-"))

Rappresentiamo le serie storiche

my_serie_storiche= function (db, ff, xx, yy, UoMff="" , UoMxx="" , UoMyy="")
  {#i parametri UoMff, UoMxx e UdMyy sono stringhe, le unità di misura delle variabili ff, xx e yy  
 
  
  if (ff == "city") {
    set_colori = colors_by_city
  } else if (ff == "month") {
    set_colori = colors_by_month
    db[[ff]] = factor(db[[ff]], levels = 1:12, labels = month.abb)  # esempio: Gen, Feb...
  } else if (ff == "year") {
    set_colori = colors_by_year
    db[[xx]] = factor(db[[xx]])  # forza year come fattore
  } else {
    set_colori = NULL
  }
  
  
 
  g=ggplot(data=db)+
    labs(title=paste("Serie storiche di ",yy,"per ogni",ff),
         x=paste(xx, UoMxx),
         y=paste(yy, UoMyy))
    
  
  xx =  sym(xx)
  yy = sym(yy)
  ff=sym(ff)
  g=g+
    geom_line(aes(x=!!xx, y=!!yy, color=!!ff))+
    scale_x_date(
    date_breaks = "1 year",
    date_minor_breaks = "1 month",
    date_labels = "%Y")+
    scale_color_manual(values = set_colori)
  
return(g)
    
}
my_serie_storiche(db, "city", "date", "redditivity", UoMyy="[$/(listing x month)]")

  1. La redditivity di Bryan-College Station si distacca dalle altre (blu e rossa mostrano un accenno di crescita, gialla circa costante).
  2. Sono evidenti i picchi stagionali in corrispondenza dell’estate.
  3. Bryan-College Station è la curva che esibisce la crescita più forte
my_serie_storiche(db, "city", "date", "sales", UoMyy="[Nr./month]")

Verde, Rossa e Blu sono mercati in crescita in termini di numero di vendite, il giallo sembra un mercato stazionario. La stagionalità (picchi di vendite in estate) si manifesta in ordine decrescente su Verde, Rossa, Blu e Gialla.

my_serie_storiche(db, "city", "date", "volume", UoMyy="[M$/month]")

I volumi vanno circa come le vendite, rappresentando il volume l’ampiezza delle oscillazioni di Bryan-College Station sembra accentuarsi rispetto alle altre curve.

my_serie_storiche(db, "city", "date", "listings", UoMyy="[Nr.]")

Il numero di annunci segue la stagionalità, sfasato in anticipo di qualche mese rispetto alle vendite. I parametri di merito listing_effectiveness, listing_effectiveness2 e redditivity probabilmente sarebbero definiti meglio se nel calcolo il numero di annunci al denominatore fosse quello di un mese diverso dal mese della variabile al numeratore, questo soprattutto per Bryan-College Station. Si nota, Wichita-Falls a parte che resta circa costante, una tendenza storica alla diminuzione, più accentuata nella curva Verde, e a seguire, Rossa e Blu, in modo analogo a quanto succede al numero di case in inventory dell’agenzia. Si nota anche che nonostante vendite simili tra Tyler e Bryan-College Station, Tyler “ha bisogno” di molti più annunci che coprono un inventory maggiore anch’esso rispetto a Bryan-College Station, dove quindi la promozione risulta più efficace o la domanda è maggiore.

my_serie_storiche(db, "city", "date", "inventory", UoMyy="[Nr. Houses]")

Si nota un periodo in cui l’agenzia “accumula” case da vendere e un periodo in cui si smaltisce l’accumulo. Tyler presenta le oscillazioni più ampie, Wichita-Falls le meno ampie.

Esploriamo il parametro di merito dato dal rapporto tra Numero di Vendite e numero di annunci:

my_serie_storiche(db, "city", "date", "listing_effectiveness", UoMyy="[Nr. sales/Nr. listing]")

A parte il 2010, in cui Bryan-College Station performa in modo paragonabile a Wichita-Falls, poi Bryan-College, con periodicità stagionale stacca le altre curve, che pure mostrano delle oscillazioni in fase e una lenta tendenza di fondo al miglioramento.

my_serie_storiche(db, "city", "date", "listing_effectiveness2", UoMyy="[$/listing]")

Rapportando al numero di annunci il Volume di vendita anziché il Numero di vendite la differenza tra Bryan-College Station e le altre città si fa più evidente.

my_serie_storiche(db, "city", "date", "months_inventory", UoMyy="[months]")

Il numero di case accumulate espresso in mesi di vendite mostra la consueta stagionalità; si nota poi una tendenza al miglioramento (riduzione di questo indice) in tutte le città, col miglioramento massimo per Bryan-College Station e minimo per Wichita-Falls

Esploriamo il parametro “cover factor”, definito come il rapporto tra il numero di annunci e il numero di case nel portafoglio dell’agenzia.

db$cover_factor=db$listings/db$inventory
my_serie_storiche(db, "city", "date", "cover_factor", UoMyy="[Nr. listing/ Nr. Houses]")

Questo parametro mostra valori molto simili fra tutte le città, con oscillazioni stagionali in fase e di ampiezza simile tra le varie curve. Le ampiezze maggiori sono per Bryan-College Station. I minimi delle oscillazioni sono al di sotto del valore 1, cioè ci sono dei periodi in cui non tutte le case in portafoglio sono coperte dagli annunci, il che potrebbe essere dovuta a una strategia (comune nelle quattro città) di pubblicare gli annunci in un periodo più favorevole e massimizzare l’effetto novità. L’ampiezza delle oscillazioni sembra smorzarsi leggermente.

9. CONCLUSIONI

L’attività dell’agenzia mostra un miglioramento negli anni (sia in termini di vendite, sia di volumi, sia di efficienza degli annunci, sia di redditività), e delle oscillazioni periodiche (picchi di vendite d’estate). Dei quattro mercati analizzati quello con maggiore variabilità e miglioramento è Bryan-College Station, quello più stabile è Wichita-Falls.

La redditività dell’agenzia sta aumentando in generale, il mercato di Bryan-College station sembra staccarsi nettamente in positivo dagli altri mercati. Il picco stagionale di Bryan-College Station, anche all’interno dell’andamento medio di Bryan-College Station stessa è netto e significativo.

Si suggerisce di indagare se i miglioramenti netti di Bryan-College siano dovuti a fattori esterni, del mercato (nel qual caso si suggerisce di indagare come intercettare al massimo ulteriore crescita della città, e in generale di investire preferibilmente su Bryan-College, mantenendo le altre posizioni per mitigare il rischio), oppure fattori interni all’agenzia (si usano strategie peculiari a Bryan-College Station che si possono replicare sulle altre sedi? il personale è molto diverso, per esperienza, età, familiarità con tecnologia?).