| title: “Progetto di Statistica Descrittiva” |
| author: “Diego Amelio” |
| date: “2025-04-30” |
| output: html_document |
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)
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.
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
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
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.
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
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
db$inventory=round(db$months_inventory*db$sales,0)
db$listing_effectiveness=db$sales/db$listings
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.
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:
che i valori centrali delle distribuzioni sembrano seguire un andamento periodico, con un periodo di massimo da maggio ad agosto
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
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.
db_city_month_redditivity=my_summary(db, "city", "month", "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)]")
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.
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?).