Descrizione del Progetto

Obiettivi del Progetto

L’azienda Texas Realty Insights desidera analizzare le tendenze del mercato immobiliare nello stato del Texas, sfruttando i dati storici relativi alle vendite di immobili. L’obiettivo è fornire insight statistici e visivi che supportino le decisioni strategiche di vendita e ottimizzazione delle inserzioni immobiliari.

Obiettivi Specifici

  • Identificare e interpretare i trend storici delle vendite immobiliari in Texas
  • Valutare l’efficacia delle strategie di marketing delle inserzioni immobiliari
  • Offrire una rappresentazione grafica dei dati che evidenzi la distribuzione dei prezzi e delle vendite tra città, mesi e anni

Valore Aggiunto

L’analisi statistica proposta permetterà a Texas Realty Insights di ottimizzare le loro strategie di mercato, identificando città con opportunità di crescita e valutando l’efficacia delle inserzioni immobiliari nel tempo. Grazie a una visione chiara e strutturata dei dati, l’azienda potrà prendere decisioni basate su informazioni concrete, migliorando la gestione delle vendite immobiliari in Texas.

Dataset

Il dataset “Real Estate Texas.csv” contiene le seguenti variabili:

  • city: città di riferimento
  • year: anno di riferimento
  • month: mese di riferimento
  • sales: numero totale di vendite
  • volume: valore totale delle vendite (in milioni di dollari)
  • median_price: prezzo mediano di vendita (in dollari)
  • listings: numero totale di annunci attivi
  • months_inventory: quantità di tempo necessaria per vendere tutte le inserzioni correnti, espresso in mesi

Setup e Caricamento Dati

#Carichiamo le librerie
library(ggplot2)
library(moments)
library(dplyr)
library(tidyr)
#Iniziamo andando a caricare il nostro dataset(ps. userò come simbolo di assegnazione
#il simbolo di ugualianza "=", piuttosto che "<-")
dati = read.csv("realestate_texas.csv")
#visualizziamo i dati
head(dati)
##       city year month sales volume median_price listings months_inventory
## 1 Beaumont 2010     1    83 14.162       163800     1533              9.5
## 2 Beaumont 2010     2   108 17.690       138200     1586             10.0
## 3 Beaumont 2010     3   182 28.701       122400     1689             10.6
## 4 Beaumont 2010     4   200 26.819       123200     1708             10.6
## 5 Beaumont 2010     5   202 28.833       123100     1771             10.9
## 6 Beaumont 2010     6   189 27.219       122800     1803             11.1
#Andiamo a fare un'analisi delle variabili nel dataset
str(dati)
## 'data.frame':    240 obs. of  8 variables:
##  $ city            : chr  "Beaumont" "Beaumont" "Beaumont" "Beaumont" ...
##  $ year            : int  2010 2010 2010 2010 2010 2010 2010 2010 2010 2010 ...
##  $ month           : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ sales           : int  83 108 182 200 202 189 164 174 124 150 ...
##  $ volume          : num  14.2 17.7 28.7 26.8 28.8 ...
##  $ median_price    : num  163800 138200 122400 123200 123100 ...
##  $ listings        : int  1533 1586 1689 1708 1771 1803 1857 1830 1829 1779 ...
##  $ months_inventory: num  9.5 10 10.6 10.6 10.9 11.1 11.7 11.6 11.7 11.5 ...
#esploriamo in profonditò le variabili
summary(dati)
##      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

Analisi delle Variabili Statistiche

Classificazione delle Variabili

#dal risultato possiamo vedere che abbiamo un dataset con 240 record e 8 variabili
#Le variabili(o features) in questione sono le seguenti:
#city : variabile qualitativa su scala nominale
#year : variabile quantitativa discreta su scala di intervalli(non esiste un zero assoluto che indica assenza di anno)
#month : variabile quantitativa discreta su scala di intervalli
#sales : variabile quantitativa discreta su scala di rapporti(esiste lo zero assoluto in questo caso)
#volume : variabile quantitativa continua su scala di rapporti
#median_price : variabile quantitativa continua su scala di rapporti
#listings : variabile quantitativa discreta su scala di rapporti
#months_inventory : variabile quantitativa continua su scala di rapporti

### VARIABILI TEMPORALI ###
#Per quanto riguarda le variabili che sottointendono il tempo ovvere year e months
#meritano una riflessione particolare. Possono permetterci di costruire delle
#serire storiche che sono sequenze di osservazioni della stessa variabile rilevante
#in tempi diversi sullo stesso soggetto(le città in questo caso)


#Per quanto riguarda la gestione di queste variabili ho pensato di stabvilire diverse strategie:
#BREVE PERIODO: usando la variabile month si potrebbero: 1) pianificare campagne di marketing,
#2) Gestire il months investory in base a mesi più o meno attivi, 3)Ottimizzare
#i prezzi per periodi ad alta/bassa domanda

#MEDIO PERIODO: Usando la variabile year : 1) identificare trend di crescita o declino,
#2)Valutare l'impatto di politiche economiche

#LUNGO PERIODO: combinando year e month: 1)Identificare pattern complessi,
#2)capire come i trend stagionali variano nel tempo

### TIPI DI ANALISI PER CIASCUNA VARIABILI ###
#andrò a fare una distinzione per le variabili qualitative, quantitative discrete e continue
#city: distribuzioni di frequenze assolute e relative, calcolo della moda,
#rappresentazioni grafiche(esempio grafico a torta), indice di Gini per misurare 
#la concentrazione delle vendite per città


##Quantitative discrete(year, month, sales, listings):
#1)Calcolo degli indici di posizione(media, mediana, moda),2)Indici di variabilità
#(range, deviazione standard, coefficiente di variazione), 3)Rappresentazioni grafiche come istogrammi, box plot
#4)Analisi di correlazione tra variabili

##Quantitative continue(volume, median_price, months_inventory):
#1)Analisi completa con tutti gli indici statistici
#2)Possibilità di suddivisione in classi se necessario
#3)Grafici più sofisticati come density plots
#4)Analisi di forma (asimmetria e curtosi)

#Prima di partire facciamo un attach suddividendo singolarmente le variabili del dataset
attach(dati)
#assegnamo la variabile n che può esserci sempre utile
n=nrow(dati)

Analisi della Variabile City (Qualitativa)

#Partiamo con lo studio della variabile city: andando ad effettuare un'analisi delle frequenze:
freq_city=table(city)
#calcoliamo anche le frequenze relative
freq_rel_city=freq_city/n
print(freq_rel_city)
## city
##              Beaumont Bryan-College Station                 Tyler 
##                  0.25                  0.25                  0.25 
##         Wichita Falls 
##                  0.25
#dal risultato è chiaro che le variabili riguardo alla città sono equidistribuite
#ma comunque andiamo a rappresentare un piechart, calcolare l'indice di gini che sicuramente
#sarà uguale ad 1
#andiamo a costruire un piechart per visualizzare in modo migliore i risultati
percentuali = round(freq_rel_city * 100, 1)
#Definiamo delle etichette
etichette_complete = paste(names(freq_city), "\n", percentuali, "%", sep="")
#definiamo dei colori che distinguono le varie città ma che creino comunque armonia
colori_city = c("#2E86AB", "#A23B72", "#F18F01", "#C73E1D", "#592E83")

#andiamo adesso a creare il piechart
pie(freq_city,
    labels = etichette_complete,
    col= colori_city,
    main="distribuzione delle osservazioni per la \n variabile city",
    cex.main=1.1,#dimensione del titolo
    cex = 0.9, #dimensione delle etichette
    radius = 0.6)#raggio del grafico

#Aggiungiamo anche una legenda per rendere il grafico ancora più immediato(non che già non lo sia)
legend(-1.3,-0.7,  # Coordinate specifiche sotto il grafico
       legend = names(freq_city),
       fill = colori_city,
       cex = 0.6,
       bty = "n")  

#Andiamo a calcolare l'indice di gini che sappiamo già il risultato che otterremo
#calcola G, che sarà il complemento a 1 della sommatoria delle frequenze relative al quadrato
# Calcoliamo l'indice di Gini grezzo
G = 1 - sum(freq_rel_city^2)
print(paste("Indice di Gini grezzo (G):", round(G, 3)))
## [1] "Indice di Gini grezzo (G): 0.75"
# Calcoliamo il numero di categorie
J = length(freq_city)
print(paste("Numero di categorie (J):", J))
## [1] "Numero di categorie (J): 4"
# Calcoliamo il valore massimo teorico
max_teorico = (J-1)/J
print(paste("Valore massimo teorico:", round(max_teorico, 3)))
## [1] "Valore massimo teorico: 0.75"
# Calcoliamo l'indice di Gini normalizzato
G_primo = G / max_teorico
print(paste("Indice di Gini normalizzato (G'):", round(G_primo, 3)))
## [1] "Indice di Gini normalizzato (G'): 1"
#Otteniamo effettivamente quello che ci aspettavamo ovvero massima etereogenità
#Quindi equidistribuzione delle classi

Analisi delle Variabili Quantitative Discrete

Variabile Sales

#Procediamo con lo studio delle variabili QUANTITATIVE DISCRETE
### SALES ###
#andiamo a vedere innanzitutto le statistiche di questa variabile
summary(sales)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    79.0   127.0   175.5   192.3   247.0   423.0
#quindi come possiamo notare dalle statistiche il numero minimo di vendite è 79,
#il numero max è 423, circa il 75% dei dati(180) ha vendite che variano da 247 a 79.
#Questo ci lascia presagire anche vedendo la differenza tra il max ed il 3rd. QU.che 
#la distribuzione sara asimmetrica positiva. vediamola
plot(density(sales))
#grafichiamo anche la media
abline(v=mean(sales),col=2)

#A prima vista sembrerebbe bimodale, questo vuol dire che ci sono 2 valori che sono
#più frequenti all'interno di questa distribuzione
#Questo mostra che esitono 2 regimi di mercato. Potrebbero ad esempio provenire da periodi
#o cità con attività di mercato normale(picco intorno ai 150) oppureperiodi o attività
#di mercato elevata(picchi intorno a 300)
#Questa dualità potrebbe riflettere differenze stagionali, 
#differenze tra città, o periodi di boom VS periodi normali nel mercato immobiliare.
#calcoliamo la devazione standard
dev_standard_sales=sd(sales)
#questa deviazione ci dice che le vendite si discostano dal valore medio di +/- 80
#varianza
varianza_sales = var(sales)
#coefficiente di variazione che potrebbe essere utile per confronti relativi tra diverse variabili
coeff_variazione_sales = (dev_standard_sales / mean(sales)) * 100
#stampiamoli
print(paste("Deviazione standard:", round(dev_standard_sales, 2)))
## [1] "Deviazione standard: 79.65"
print(paste("Varianza:", round(varianza_sales, 2)))
## [1] "Varianza: 6344.3"
print(paste("Coefficiente di variazione:", round(coeff_variazione_sales, 2), "%"))
## [1] "Coefficiente di variazione: 41.42 %"
# Calcoliamo anche alcuni percentili per capire meglio le code
percentili_sales = quantile(sales, probs = c(0.1, 0.9))
print(paste("Percentili 10° e 90°:", percentili_sales))
## [1] "Percentili 10° e 90°: 101.9" "Percentili 10° e 90°: 302.1"
print(percentili_sales)
##   10%   90% 
## 101.9 302.1
#come possiamo notare da questi risultati il 90%dei dati si trova al di sotto de
#valore corrispondente alla seconda moda con un quindi il 10% di valori compresei tra
#302 e 423 circa 24, questo indica che esiste un mercato ad alta intensità, che potrebbe
#richiedere strategie diverse dal 90% delle situazioni normali.
#calcoliamo allora l'indice di asimmetria di fisher o skewness
skew_sales= moments::skewness(sales)
#infatti come abbiamo gioà accennato la distribuzione è asimmetrica positiva indica
kurt_sales=moments::kurtosis(sales)
#stampiamo i risultati
print(paste("Asimmetria:", round(skew_sales, 4)))
## [1] "Asimmetria: 0.7181"
print(paste("Kurtosis:", round(kurt_sales, 4)))
## [1] "Kurtosis: 2.6868"
#con la distribuzione che è leptocurtica, di fatti ha code più pesanti rispetto alla normale,
#il che significa che valori estremi(sia alti che bassi) sono più frequenti di quanto ci si aspetterebbee
#da una distribuzione normale
#Vediamo adesso di capire come le vendite sono distribuite per territorio, andiamo a studiare i 
#boxplot delle vendite per le diverse città del Texas, in modo da avere una visione chiara
#da poter allineare con i risultati ottenuti dalla distribuzione e  i risultati degli indici di formna

#Creiamo delle abbreviazioni per i nomi delle città perchè potrebbero disturbare la visualizzazione
dati$city_short <- factor(dati$city, 
                          levels = c("Beaumont", "Bryan-College Station", "Tyler", "Wichita Falls"),
                          labels = c("Beaumont", "Bryan-CS", "Tyler", "W. Falls"))

ggplot(dati, aes(x=city_short, y=sales, fill=city))+
    geom_boxplot(alpha=0.8,
                 outlier.color = 2,
                 outlier.size = 3,
                 outlier.alpha = 0.7)+
    # Aggiungiamo i punti della media per ogni città
    stat_summary(fun = mean, geom = "point", 
                 shape = 3, size = 3, color = "black")+
    # Miglioramo le etichette e il titolo
    labs(title = "Distribuzione delle vendite per le diverse \n città del Texas",
         subtitle = "Numero totale di vendite",
         x = "",
         y = "Numero di vendite",
         fill = "Città",
         caption="Le croci al centro dei Boxplot, indicano i valori medi") +
    theme_minimal()+
    theme(axis.text.x = element_text(angle=90, vjust = 0.5,hjust = 1, size = 11))

Interpretazione dei Risultati Sales

Variabile Listings

#Ora studieremo la seconda variabile quantitativa
### LISTINGS
#stampiamo alcune statistiche della variabile
summary(listings)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     743    1026    1618    1738    2056    3296
#quindi come possiamo notare dalle statistiche il numero minimo di annunci attivi 743,
#il numero max è 3296, circa il 75% dei dati ha vendite che variano da 2056 a 743.
#Anche in questo caso sembrebbe che la distribuzione sia asimmetrica positiva, ma andiamo a vedere
plot(density(listings))
#grafichiamo anche la media
abline(v=mean(listings),col=2)

#In questo caso,come possiamo vedere dall'immagine, sembrerebbe che la nostra distribuzione
#sia trimodale, come se ci trovassimo in diversi regimi di mercato, con annunci attivi su diversi
#range di valori. In questo caso si potrebbe osservare che il calcolo degli indici
#di variabilità potrebbero darci delle interpretazioni fuorvianti, questo perchè
#i punti sono distribuiti(a quanto sembra dalla rappresentazione) intorno a centri differenti.
#Vediamo:

#calcoliamo la devazione standard
dev_standard_listings=sd(listings)
#questa deviazione ci dice che gli annunci attivi si discostano dal valore medio di +/- 750
#Questo è quello che potremmo dire se la distribuzione fosse unimodale, ma cosi non è infatti
#se prendessimo il valore medio ed aggiungessimo 750, ci accorgeremo che il valore cade in
#prossimità di 2300, dove troviamo un punto di minimo della funzione, quindi non cosidera
#i valori successivi.
#A questo punto secondo me non ha senso calcolare questi indici, come non ha senso calcolare
#gli indici di forma come invece abbiamo fatto nel caso precedente.
#Andiamo invece a studiare i boxplot, cercare di capire se gli annunci attivi, dipendono dalle zone
#diverse del Texas

ggplot(dati, aes(x=city_short, y=listings, fill=city))+
    geom_boxplot(alpha=0.8,
                 outlier.color = 2,
                 outlier.size = 3,
                 outlier.alpha = 0.7)+
    # Aggiungiamo i punti della media per ogni città
    stat_summary(fun = mean, geom = "point", 
                 shape = 3, size = 3, color = "black")+
    # Miglioramo le etichette e il titolo
    labs(title = "Distribuzione degli annunci attivi per Città",
         x = "",
         y = "Annunci attivi",
         fill = "Città",
         caption="Le croci al centro dei Boxplot, indicano i valori medi") +
    theme_minimal()+
    theme(axis.text.x = element_text(angle=90, vjust = 0.5,hjust = 1, size = 11))

Interpretazione Listings

Analisi delle Variabili Quantitative Continue

Variabile Volume

###VOLUME
#Stampiamo le statistiche
summary(volume)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   8.166  17.660  27.062  31.005  40.893  83.547
#Andiamo a plottare la densità
plot(density(volume))
#grafichiamo anche il valore medio
abline(v=mean(volume), col=2)

#Allora rispetto alle altre, a parte qualche irregolarità, sembrerebbe  essere una
#distribuzione normale con un'evidente asimmetria positiva e con una chiara leptocurtosi
#Andiamo a calcolare gli indici di variabilità
#deviazione standard
dev_standard_volume=sd(volume)
#varianza
var_volume=var(volume)
#coefficiente di variazione
coeff_variazione_volume=(dev_standard_volume/mean(volume))*100
#adesso stampiamo i risultati
print(paste("deviazione standard volume : ", round(dev_standard_volume,2)))
## [1] "deviazione standard volume :  16.65"
print(paste("Varianza volume : ", round(var_volume,2)))
## [1] "Varianza volume :  277.27"
print(paste("Coefficiente di variazione volume : ", round(coeff_variazione_volume,2),"%"))
## [1] "Coefficiente di variazione volume :  53.71 %"
#quindi osservando la deviazione standard, possiamo dire che i dati variano intorno
#al valore medio di +/- 16.65 e questo possiamo notarlo anche dal summary iniziale
#andiamo a calcolare ora gli indici di forma
#asimmetria
skew_volume=skewness(volume)
#kurtosi
kurt_volume=kurtosis(volume)-3
#stampiamo i risultati
print(paste("Asimmetria:", round(skew_volume, 4)))
## [1] "Asimmetria: 0.8847"
print(paste("Kurtosis:", round(kurt_volume, 4)))
## [1] "Kurtosis: 0.177"
#I risultati di asimmetria e curtosi erano quelli che ci aspettavamo anche dal density plot, ovvero
#asimmetria positiva(anche se non di molto) ed una mesucurtosi, quindi quasi normale
#A questo punto andiamo a studiare come fatto anche con le altre il boxplot dei volumi
#rispetto alle città del nostro dataset
# Prima creiamo etichette abbreviate per le città


ggplot(dati, aes(x=city_short, y=volume, fill=city))+
    geom_boxplot(alpha=0.8,
                 outlier.color = 2,
                 outlier.size = 3,
                 outlier.alpha = 0.7)+
    # Aggiungiamo i punti della media per ogni città
    stat_summary(fun = mean, geom = "point", 
                 shape = 3, size = 3, color = "black")+
    # Miglioramo le etichette e il titolo
    labs(title = "Distribuzione del Volume di Vendite per Città",
         subtitle = "Volume totale delle vendite immobiliari (in milioni di dollari)",
         x = "",
         y = "Volume (Milioni di $)",
         fill = "Città",
         caption="Le croci al centro dei Boxplot, indicano i valori medi") +
    theme_minimal()+
    theme(axis.text.x = element_text(angle=90, vjust = 0.5,hjust = 1, size = 11))

Interpretazione Volume

Variabile Median Price

### MEDIAN-PRICE
#andiamo ad analizzare la variabile median-price
summary(median_price)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   73800  117300  134500  132665  150050  180000
#Andiamo a plottare la densità
plot(density(median_price))
#grafichiamo anche il valore medio
abline(v=mean(median_price), col=2)

#Questa variabile sembrerebbe essere bimodale, ma questa volta con un'asimmetria negativa
#Andiamo a calcolare gli indici di variabilità
#deviazione standard
dev_standard_median_prince=sd(median_price)
#varianza
var_median_price=var(median_price)
#coefficiente di variazione
coeff_variazione_median_price=(dev_standard_median_prince/mean(median_price))*100
#adesso stampiamo i risultati
print(paste("deviazione standard median-price : ", round(dev_standard_median_prince,2)))
## [1] "deviazione standard median-price :  22662.15"
print(paste("Varianza median-price : ", round(var_median_price,2)))
## [1] "Varianza median-price :  513572983.09"
print(paste("Coefficiente di variazione median-price : ", round(coeff_variazione_median_price,2)))
## [1] "Coefficiente di variazione median-price :  17.08"
#quindi osservando la deviazione standard, possiamo dire che i dati variano intorno
#al valore medio di +/- 22662.15 e questo possiamo notarlo anche dal summary iniziale
#Un indice di variazione cosi basso ci lascia presagire che questi prezzi sono stabili
#quindi è difficile che ci siano strategie di vendita differenti
#andiamo a calcolare ora gli indici di forma
#asimmetria
skew_median_price=skewness(median_price)
#kurtosi
kurt_median_price=kurtosis(median_price)-3
#stampiamo i risultati
print(paste("Asimmetria:", round(skew_median_price, 4)))
## [1] "Asimmetria: -0.3646"
print(paste("Kurtosis:", round(kurt_median_price, 4)))
## [1] "Kurtosis: -0.623"
#I risultati di asimmetria e curtosi erano quelli che ci aspettavamo anche dal density plot, ovvero
#asimmetria negativa(anche se non di molto) ed una leggera platicurtosi
#A questo punto andiamo a studiare come fatto anche con le altre il boxplot dei mean-price
#rispetto alle città del nostro dataset

ggplot(dati, aes(x=city_short, y=median_price, fill=city))+
    geom_boxplot(alpha=0.8,
                 outlier.color = 2,
                 outlier.size = 3,
                 outlier.alpha = 0.7)+
    # Aggiungiamo i punti della media per ogni città
    stat_summary(fun = mean, geom = "point", 
                 shape = 3, size = 3, color = "black")+
    # Miglioramo le etichette e il titolo
    labs(title = "Distribuzione dei prezzi medi per città",
         subtitle = "Prezzo mediano di vendita (in dollari)",
         x = "",
         y = "Mean Price(Milioni di $)",
         fill = "Città",
         caption="Le croci al centro dei Boxplot, indicano i valori medi") +
    theme_minimal()+
    theme(axis.text.x = element_text(angle=90, vjust = 0.5,hjust = 1, size = 11))

Interpretazione Median Price

Variabile Months Inventory

### MONTHS_INVENTORY
#Andiamo a calcolare le statistiche della variabile
summary(months_inventory)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   3.400   7.800   8.950   9.193  10.950  14.900
#Vediamo che la quantità di tempo necessaria per vendere le inserzioni contenuta in un
#intervallo ristretto. Ma vediamolo nel dettaglio
plot(density(months_inventory))
abline(v=mean(months_inventory), col=2)

#nonstante sia molto contenuto l'intervallo abbiamo una distribuzione non regolare
#con massimi e minimi, questo potrebbe essere dovuto al fatto che nelle diverse città
#esistono tempi molto diversi per vendere le inserzioni
#studiamo gli indici di variabilità
dev_standard_months_inventory=sd(months_inventory)
var_months_inventory=var(months_inventory)
coeff_variazione_months_inventory=(sd(months_inventory)/mean(months_inventory))*100
#andiamo a stampare le variabili calcolate
print(paste("Deviazione standard month inventory : ", round(dev_standard_months_inventory,2)))
## [1] "Deviazione standard month inventory :  2.3"
print(paste("Varianza month inventory : ", round(var_months_inventory,2)))
## [1] "Varianza month inventory :  5.31"
print(paste("Coefficiente di variazione di month inventory : ", round(coeff_variazione_months_inventory,2)))
## [1] "Coefficiente di variazione di month inventory :  25.06"
#Allora per quanto riguarda la deviazione standard, notiamo che comunque i valori di distribuiscono
#intorno al valore medio con un intervallo di +/-2.3 e ci stà
#il coefficiente di variazione cosi basso, vuol dire che la variazione dei tempi di ventita, è
#molto bassa, cioè che i tempi di mercato sono più prevedibili
#ora calcoliamo gli indici di forma
skew_months_inventory=skewness(months_inventory)
kurt_month_inventory=kurtosis(months_inventory)-3
#stampiamole
print(paste("Asimmetria di months inventory : ", round(skew_months_inventory,4)))
## [1] "Asimmetria di months inventory :  0.041"
print(paste("Kurtosi di months inventory : ", round(kurt_month_inventory,4)))
## [1] "Kurtosi di months inventory :  -0.1744"
#L'indice di asimmetria quasi zero indica che è quasi simmetrica, tendendo ad una normale
#l'indice di Kurtosi sta ad indicare che questa distribuzione è leggermente platicurtica
#ma diciamo quasi assente che indica una distribuzione mesocurtica, ovvero normale
#Andiamo a graficare i boxplot divisi per città

ggplot(dati, aes(x=city_short, y=months_inventory, fill=city))+
    geom_boxplot(alpha=0.8,#trasparenza
                 outlier.color = 2,
                 outlier.size = 3,
                 outlier.alpha = 0.7 )+
    stat_summary(fun = mean, geom = "point", 
                 shape = 3, size = 3, color = "black")+
    labs(title = "Distribuzione del tempo di vendita per città",
         x="",
         y="Months Inventory",
         fill="città",
         caption="Le croci al centro dei Boxplot, indicano i valori medi")+
    theme_minimal()+
    theme(axis.text.x = element_text(angle=90, vjust = 0.5,hjust = 1, size = 11))

Interpretazione Months Inventory

Analisi delle Variabili Temporali

Variabile Year

#Ora andiamo a lavorare le variabili temporali

###YEAR
freq_year=table(year)
print(freq_year)
## year
## 2010 2011 2012 2013 2014 
##   48   48   48   48   48
#frequenze relative
freq_rel_year= (freq_year/n)
print(freq_rel_year)
## year
## 2010 2011 2012 2013 2014 
##  0.2  0.2  0.2  0.2  0.2
#Indice di Gini per verificare se i dati sono bilanciati temporalmente
gini_year=1-sum(freq_rel_year^2)
print(paste("Indice di Gini grezzo (G):", round(gini_year, 3)))
## [1] "Indice di Gini grezzo (G): 0.8"
# Calcoliamo il numero di categorie
j_year = length(freq_year)
print(paste("Numero di categorie (J):", j_year))
## [1] "Numero di categorie (J): 5"
#indice massimo teorico
gini_max_teorico_year=(j_year-1)/j_year
print(paste("Gini massimo teorico :", gini_max_teorico_year))
## [1] "Gini massimo teorico : 0.8"
#Indice di gini normalizato
gini_normalizzato_year=gini_year/gini_max_teorico_year
print(paste("Indice di Gini per year:", round(gini_normalizzato_year, 3)))
## [1] "Indice di Gini per year: 1"
#Allora dai risultati ottenuti dall'indice normalizzato di year che è pari a 1
#sembrerebbe esserci un bilanciamento temporale tra le osservazioni
# Grafico a barre per year
ggplot(dati, aes(x = as.factor(year),fill=year)) +
    geom_bar( alpha = 0.8) +
    labs(title = "Distribuzione delle Osservazioni per Anno",
         x = "Anno", y = "Frequenza") +
    theme_minimal()

Variabile Month

### MONTHS
#Andiamo a studiare i months per capire se possiamo presagire qualche stagionalità
freq_month=table(month)
print(freq_month)
## month
##  1  2  3  4  5  6  7  8  9 10 11 12 
## 20 20 20 20 20 20 20 20 20 20 20 20
#frequenze relative
freq_rel_month= (freq_month/n)
print(round(freq_rel_month,4))
## month
##      1      2      3      4      5      6      7      8      9     10     11 
## 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 
##     12 
## 0.0833
#Indice di Gini per verificare se i dati sono bilanciati temporalmente
gini_month=1-sum(freq_rel_month^2)
print(paste("Indice di Gini grezzo (G):", round(gini_month, 3)))
## [1] "Indice di Gini grezzo (G): 0.917"
# Calcoliamo il numero di categorie
j_month = length(freq_month)
print(paste("Numero di categorie (J):", j_month))
## [1] "Numero di categorie (J): 12"
#indice massimo teorico
gini_max_teorico_month=(j_month-1)/j_month
print(paste("Gini massimo teorico :", round(gini_max_teorico_month,4)))
## [1] "Gini massimo teorico : 0.9167"
#Indice di gini normalizato
gini_normalizzato_month=gini_month/gini_max_teorico_month
print(paste("Indice di Gini per year:", round(gini_normalizzato_month, 3)))
## [1] "Indice di Gini per year: 1"
#Anche in questo caso sembrerebbe esserci un'equidistribuzione temporale
#Andiamo a graficare le freqwuenze

ggplot(dati, aes(x=as.factor(month)), fill=month)+
    geom_bar(alpha=0.8)+
    labs(title="Distribuzione delle osservazioni per mese",
         x="mese",
         y="Frequenza")+
    theme_minimal()

Identificazione Variabili con Maggiore Variabilità e Asimmetria

#FINITA L'ANALISI DESCRITTIVA DELLE VARIABILI ORA PROCEDIAMO AD IDENTIFICARE LA VARIABILE
#CON MAGGIORE VARIABILITA E ASIMMETRIA

print(paste("coefficiente di variazione volume", round(coeff_variazione_volume,2), "%"))
## [1] "coefficiente di variazione volume 53.71 %"
print(paste("coefficiente di variazione Sales", round(coeff_variazione_sales,2), "%"))
## [1] "coefficiente di variazione Sales 41.42 %"
print(paste("coefficiente di variazione Median Price", round(coeff_variazione_median_price,2), "%"))
## [1] "coefficiente di variazione Median Price 17.08 %"
print(paste("coefficiente di variazione Month Inventory", round(coeff_variazione_months_inventory,2), "%"))
## [1] "coefficiente di variazione Month Inventory 25.06 %"
#QUindi il coefficiente di variazione più elevato è dato dalla variabile volume,
#questo perchè accumala la variabilità di q.tà X prezzo rendendola più volatile
print(paste("Indice di asimmetria volume", round(skew_volume,4)))
## [1] "Indice di asimmetria volume 0.8847"
print(paste("Indice di simmetria Sales", round(skew_sales,4)))
## [1] "Indice di simmetria Sales 0.7181"
print(paste("Indice di asimmetria Median Price", round(skew_median_price,4)))
## [1] "Indice di asimmetria Median Price -0.3646"
print(paste("indice di asimmetrias Month Inventory", round(skew_months_inventory,4)))
## [1] "indice di asimmetrias Month Inventory 0.041"
#Anche in questo caso il valore più alto + quello corrispondente a volume


#Volume vince in entrambe le categorie perché è una variabile derivata (sales × prezzi medi)
#che amplifica le fluttuazioni di entrambe le componenti. Per Texas Realty Insights, questo
#significa che i ricavi sono la metrica più imprevedibile e richiedono maggiore attenzione
#nella pianificazione strategica.

Creazione di Classi per Variabile Quantitativa

Suddivisione in Classi della Variabile Sales

#Adesso procederemo alla creazione di classi per una variabile,nel nostro caso,
#utilizzeremo la variabile sales
summary(sales)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    79.0   127.0   175.5   192.3   247.0   423.0
#come abbiamo visto il max è 423 e minimo 76 quindi, volendo dividere in 4 classi:
ampiezza=(max(sales)-min(sales))/4
break_sales=seq(from=min(sales),
                to= max(sales)+0.1,
                by=ampiezza)

#Andiamo a visualizzare il ricultato
print("Breaks delle classi:")
## [1] "Breaks delle classi:"
print(break_sales)
## [1]  79 165 251 337 423
#andiamo a creare la suddivisione

sales_classi=cut(sales, breaks=break_sales,
                 labels = c("79 -| 165 (Basse)", "165 -| 251 (Medie)", " 251 -| 337 (medie Alte)",
                            "337 -| 423 (Alte)"),
                 include.lowest = TRUE)
# Verifichiamo che non ci siano NA
print(paste("Valori non classificati:", sum(is.na(sales_classi))))
## [1] "Valori non classificati: 0"
#Andiamo a generare le frequenze assolute
freq_ass_sales=table(sales_classi)
#frequenza relative
freq_rel_sales=freq_ass_sales/n
#frequenze cumulate assolute
freq_cum_sales=cumsum(freq_ass_sales)
#frequenze cumulate relative
freq_cum_rel_sales=cumsum(freq_rel_sales)

#creiamo la tabella completa
distribuzione_sales = data.frame(
  Classi = names(freq_ass_sales),
  "Freq. Assolute" = as.numeric(freq_ass_sales),
  "Freq. Relative" = round(as.numeric(freq_rel_sales), 4),
  "Freq. Cum. Assolute" = as.numeric(freq_cum_sales),
  "Freq. Cum. Relative" = round(as.numeric(freq_cum_rel_sales), 4))

print("========== DISTRIBUZIONE DI FREQUENZE DELLE VENDITE ==========")
## [1] "========== DISTRIBUZIONE DI FREQUENZE DELLE VENDITE =========="
print(distribuzione_sales)
##                     Classi Freq..Assolute Freq..Relative Freq..Cum..Assolute
## 1        79 -| 165 (Basse)            110         0.4583                 110
## 2       165 -| 251 (Medie)             71         0.2958                 181
## 3  251 -| 337 (medie Alte)             45         0.1875                 226
## 4        337 -| 423 (Alte)             14         0.0583                 240
##   Freq..Cum..Relative
## 1              0.4583
## 2              0.7542
## 3              0.9417
## 4              1.0000
#Dalla tabella creata cosa possiamo dire?
#Vvediamo che da una classe all'altra le vendite sono decrescenti dalle vendite
#più basse fino alle più alte. Gurdando alle cumulate, poi, vediamo che il 45% delle
#osservazioni è nell'intervallo tra 79-165, il 75.42% tra 251 e 79, il 94.17% tra 337
#e 79 ed infino il 100% si trova da 423 a 79
#andiamo a creare la tabella di contingengenza tra sales e città

#aggiungiamo le classi al dataset
dati$sales_classi=sales_classi

# Tabella di contingenza
contingenza_sales_city <- table(sales_classi, city)
print("========== TABELLA DI CONTINGENZA: Classi Sales × Città ==========")
## [1] "========== TABELLA DI CONTINGENZA: Classi Sales × Città =========="
print(contingenza_sales_city)
##                           city
## sales_classi               Beaumont Bryan-College Station Tyler Wichita Falls
##   79 -| 165 (Basse)              24                    24     3            59
##   165 -| 251 (Medie)             32                    18    20             1
##    251 -| 337 (medie Alte)        4                    12    29             0
##   337 -| 423 (Alte)               0                     6     8             0
#guardando alla tabella di contingenza possiamo dire che:
#il numero maggiore di vendite più basse si registra in Wichita Falls, medie in
#beaumont, medie--alte in Tyler e Bryan college, tendenza che si ripete nelle 
#vendite alte. Tutto ciò segue esattamente quello che avevamo visto nei risultati
#delle variabili studiate precedentemente

Rappresentazioni Grafiche delle Classi

#Andiamo infine a rappresentare i bar_plot delle distribuzioni

#istogramma delle frequenze assolute
ggplot(dati, aes(x=sales_classi))+
  geom_bar(fill=3, alpha=0.8, color= "white",width=0.7)+
  labs(title="Distribuzione delle vendite per Classi",
       subtitle= "Classi con ampiezza 86 unità",
       x="Classi di vendite", y="Frequenze assolute")+
  theme_minimal()+
  theme(axis.text.x = element_text(angle = 45,hjust = 1, size=10))+
  geom_text(stat='count', aes(label=after_stat(count)),
            vjust= -0.5, size=3, fontface="bold")

# Grafico a barre sovrapposte per la contingenza
ggplot(dati, aes(x = sales_classi, fill = city)) +
  geom_bar(alpha = 0.8, position = "stack") +
  labs(title = "Distribuzione delle Classi di Vendite per Città",
       subtitle = "Tabella di contingenza visualizzata",
       x = "Classi di Vendite", y = "Frequenza",
       fill = "Città") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

#grafico a barre affincate
ggplot(dati, aes(x = sales_classi, fill = city)) +
  geom_bar(alpha = 0.8, position = "dodge") +
  labs(title = "Distribuzione delle Classi di Vendite per Città",
       subtitle = "Tabella di contingenza visualizzata",
       x = "Classi di Vendite", y = "Frequenza",
       fill = "Città") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Calcolo Indice di Gini per le Classi

# CALCOLO CORRETTO DELL'INDICE DI GINI PER LE CLASSI
# Le frequenze relative che abbiamo calcolato
freq_rel_sales <- freq_ass_sales / n
print("Frequenze relative delle classi:")
## [1] "Frequenze relative delle classi:"
print(round(freq_rel_sales, 4))
## sales_classi
##        79 -| 165 (Basse)       165 -| 251 (Medie)  251 -| 337 (medie Alte) 
##                   0.4583                   0.2958                   0.1875 
##        337 -| 423 (Alte) 
##                   0.0583
# Calcolo Gini GREZZO (un solo valore!)
gini_grezzo_classi <- 1 - sum(freq_rel_sales^2)
print(paste("Gini grezzo:", round(gini_grezzo_classi, 4)))
## [1] "Gini grezzo: 0.6639"
# Numero di classi
j_classi <- length(freq_ass_sales)
print(paste("Numero di classi:", j_classi))
## [1] "Numero di classi: 4"
# Gini massimo teorico per 4 classi
gini_max_classi <- (j_classi - 1) / j_classi
print(paste("Gini massimo teorico:", round(gini_max_classi, 4)))
## [1] "Gini massimo teorico: 0.75"
# Gini normalizzato (DEVE essere ≤ 1!)
gini_normalizzato_classi <- gini_grezzo_classi / gini_max_classi
print(paste("Gini normalizzato:", round(gini_normalizzato_classi, 4)))
## [1] "Gini normalizzato: 0.8851"
#Alta Eterogeneità: 88.51% dell'eterogeneità massima possibile
#La distribuzione delle vendite per classi è fortemente sbilanciata
#NON c'è equidistribuzione tra le fasce di vendite
#Il mercato è altamente stratificato con chiara concentrazione nelle fasce basse

Calcolo delle Probabilità

#Passiamo al calcolo della probabilità, utilizzando l'approccio della probabilità
#classica ovvero P(evento)=Casi favorevoli/casi possibili, nel nostro dataset, i 
#casi possibili sono n=240

#Calcoliamo dapprima la probabilità che presa a caso una riga del dataset, essa sia
#beaumont:

casi_beaumont=sum(city=="Beaumont")
prob_beaumont= casi_beaumont/n
#stampiamo i risultati
print("========== DOMANDA 1 ==========")
## [1] "========== DOMANDA 1 =========="
#casi favorevoli
print(paste("Casi favorevoli :", casi_beaumont))
## [1] "Casi favorevoli : 60"
#Probabilità
print(paste("La probabilità di Beaumont è:", prob_beaumont))
## [1] "La probabilità di Beaumont è: 0.25"
#in percentuale
print(paste("Probabilità Beaumont (%): ", round(prob_beaumont*100,2), "%"))
## [1] "Probabilità Beaumont (%):  25 %"
##Mese di luglio
casi_luglio=sum(month==7)
prob_luglio=casi_luglio/n
#stampiamo i risultati
print("========== DOMANDA 2 ==========")
## [1] "========== DOMANDA 2 =========="
#casi favorevoli
print(paste("Casi favorevoli mese di Luglio: ",casi_luglio))
## [1] "Casi favorevoli mese di Luglio:  20"
#Probabilità
print(paste("La probabilità di Luglio è:", prob_luglio))
## [1] "La probabilità di Luglio è: 0.0833333333333333"
#in percentuale
print(paste("La probabilità di luglio (%) è :", round(prob_luglio*100,2), "%"))
## [1] "La probabilità di luglio (%) è : 8.33 %"
#Probabilità del mese di Dicembre 2012
casi_favorevoli_12_12=sum(month==12 & year==2012)
prob_12_12= casi_favorevoli_12_12/n
#stapiamo i risultati
print("========== DOMANDA 3 ==========")
## [1] "========== DOMANDA 3 =========="
print(paste("Casi favorevoli (Dicembre 2012):", casi_favorevoli_12_12))
## [1] "Casi favorevoli (Dicembre 2012): 4"
print(paste("Probabilità Dicembre 2012:", round(prob_12_12, 4)))
## [1] "Probabilità Dicembre 2012: 0.0167"
print(paste("Probabilità Dicembre 2012 (%):", round(prob_12_12 * 100, 2), "%"))
## [1] "Probabilità Dicembre 2012 (%): 1.67 %"
#Cosa possiamo dire sui risultati delle probabilità?
#Bene per quanto riguarda la probabilità di beaumont, possiamo dire che essendo 4 le città, 
#il dataset è equidistribuito per città
#Per quanto riguarda i mesi, anche questo sono equidistribuiti per 12 mesi
#Per quanto riguarda la probabilità combinata, possiamo dire che eventi specifici, logicamente
#hanno delle probabilità più basse

Creazione di Nuove Variabili

Prezzo Medio per Casa

#Passiamo adesso alla creazione di nuove variabili come richiesto. Iniziamo con il calcolo
#del prezzo medio per casa. Allora a cosa abbiamo pensato? 
#Siccome il volume di vendita rappresenta il totale ottenuto dalle case vendute, per riga
#vuol dire che diviso per il totale delle case vendute, ci darà il prezzo medio
#(Sommatoria prezzo(i)/sales). Cominciamo il calcolo

#Volume di vendita è in milioni di dollari quidni

dati$prezzo_medio = (volume*1000000)/ sales
#stampiamo i risultati
print("====== PREZZO MEDIO ======")
## [1] "====== PREZZO MEDIO ======"
summary(dati$prezzo_medio)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   97010  132939  156588  154320  173915  213234
#Andiamo a confrontare il prezzo mediano con il prezzo medio
print("Confronto Prezzo Medio vs Median Price:")
## [1] "Confronto Prezzo Medio vs Median Price:"
print(paste("Media del prezzo_medio:", round(mean(dati$prezzo_medio), 2)))
## [1] "Media del prezzo_medio: 154320.37"
print(paste("Media del median_price:", round(mean(dati$median_price), 2)))
## [1] "Media del median_price: 132665.42"
#QUesto perchè? perchè logicamente sappiamo dalla teoria che il valore mediano
#non è influenzato dagli outliers e rappresenta il 50-simo percentile, mentre la 
#media è sensibile agli outliers quindi vuol dire che se esistono dei prezzi
#molto elevati, questi trascinano la media verso l'alto. Adesso faremo un passaggio
#ovvero andremo a la correlazione delle due variabili e perchè? perchè 
#se trovassimo che queste sono correlate(anche dai risultati ottenuti in precedenza
#con lo studio delle variabili), otterremo che il mercato è omogeneo, ovvero che non esistono 
#prezzi altissimi che distorcono la media, quindi la forma dei prezzi è regolare, al contrario
#se fossero incorrelate, risulterebbe che ci sono delle case che tirano la media
#vero l'alto/basso e quindi avremo delle code più allungate della distribuzione

# Correlazione tra le due misure di prezzo
correlazione_prezzi = cor(dati$prezzo_medio, dati$median_price)
print(paste("Correlazione prezzo_medio vs median_price:", round(correlazione_prezzi, 4)))
## [1] "Correlazione prezzo_medio vs median_price: 0.9465"
#come possiamo notare sono correlate tra loro il che vuol dire che il mercato in Texas è
#omogeneo, c'è un'assenza di outliers distorsivi, il median_price è un proxy affidabile
#per tutte le analisi che abbiamo svolto
#Andiamo a fare un'analisi per città
prezzo_medio_per_città = aggregate(dati$prezzo_medio,
                                   by=list(city),
                                  FUN=mean)

colnames(prezzo_medio_per_città) = c("Città", "Prezzo_Medio")
print("Prezzo medio per città:")
## [1] "Prezzo medio per città:"
print(prezzo_medio_per_città)
##                   Città Prezzo_Medio
## 1              Beaumont     146640.4
## 2 Bryan-College Station     183534.3
## 3                 Tyler     167676.8
## 4         Wichita Falls     119430.0
#come possiamo vedere dai risultati Bryan college e Tyler sono le zone con i prezzi medi
#delle case più elevati

Efficacia degli Annunci di Vendita

#Adesso andiamo a creare la colonna che misuri l'efficacia degli annunci di vendita
#per farlo dobbiamo vedere effettivamente rispetto agli annunci attivi quante case vendo
#quindi per farlo utilizzeremo la variabile listings e la variabile sales. In questo modo
#misureremo:
#quanto è effettivamente efficace/obiettivo= sales/listings

dati$efficacia_vendite = sales/listings
#vediamo i risultati
print("====== EFFICACIA DEGLI ANNUNCI ======")
## [1] "====== EFFICACIA DEGLI ANNUNCI ======"
summary(dati$efficacia_vendite)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.05014 0.08980 0.10963 0.11874 0.13492 0.38713
#analisi per città
efficacia_per_città=aggregate(dati$efficacia_vendite,
                              by=list(dati$city),
                              FUN=mean)

colnames(efficacia_per_città)=c("Città","efficacia_media")
print("efficacia media per città:")
## [1] "efficacia media per città:"
print(efficacia_per_città)
##                   Città efficacia_media
## 1              Beaumont      0.10613316
## 2 Bryan-College Station      0.14734315
## 3                 Tyler      0.09348935
## 4         Wichita Falls      0.12801402
#Dai risultati ottenuti possiamo dire che la città con il tasso di efficienza più elevato
#mediamente in termine di conversione annunci/vendite è bryan college. A grande sorpresa
#tyler è il mercato con il tasso più basso di conversione.

Visualizzazioni delle Nuove Variabili

#andiamo a visualizzare le variabili create

ggplot(dati, aes(x=city_short,y=dati$efficacia_vendite, fill=city))+
  geom_boxplot(alpha=0.8)+
  labs(title = "Efficacia complessiva degli annunci per città",
       x="città", y="Efficacia complessiva")+
  theme_minimal()+
  theme(axis.text.x = element_text(angle=45,hjust=1))

#grafico di dispersione per le variabili riguardanti il prezzo
ggplot(dati,aes(x=median_price, y=dati$prezzo_medio, color=city))+
  geom_point(alpha=0.7,size=3)+
  geom_smooth(method="lm", se=FALSE, color="red", linetype="dashed") +
  geom_abline(slope=1, intercept = 0,linetype="dashed",color=2)+
  labs(title = "Prezzo Medio vs Median Price",
       subtitle = "La linea rossa indica perfetta corrispondenza",
       x = "Median Price", y = "Prezzo Medio") +
  theme_minimal()

#come dicevamo osservando l'ultimo grafico, essemdo che sono correlati positivamente
#median price è un buon proxy del perzzo medio.
#Come vediamo nel grafico sono graficate due rette:
# -La prima più sotto è la retta identità ovvero x=y
# - Mentre la seconda è ricavata con il metodo della regressione lineare avendo quindi
#   b0 e b1 diversi da zero cattura la reale relazione dei dati
#La distanza di questi punti dalla retta identità, ci conferma, come abbiamo visto
#anche nei risultati che il prezzo medio è tirato dagli outliers, quindi è normale
#che per ogni valore di median_price il valore del prezzo medio faccia ricadere il punto
#distante dalla retta identità

Analisi Condizionata

Summary per Città

#Passiamo ora all'analisi condizionata per città, anno e mese
#partiamo con l'analisi condizionata per città, quindi andiamo a calcolare 
#statistiche  come media e dev.standard per i diversi gruppi di città,rispetto
#alle diverse variabili ( volume, median_price, sales),
#utilizzando la libreria dplyr

summary_per_città = dati%>%
  group_by(city)%>%
  summarise(
    n_osservazioni=n(),
    media_sales=round(mean(sales),2),
    sd_sales=round(sd(sales),2),
    min_sales=min(sales),
    max_sales=max(sales),
    #prezzi mediani
    media_median_price=round(mean(median_price),2),
    sd_median_price=round(sd(median_price),2),
    #volume
    media_volume=round(mean(volume),2),
    sd_volume=round(sd(volume),2)
  )%>%
  arrange(desc(media_sales))%>%
  print(width = Inf)  # Visualizza tutto immediatamente
## # A tibble: 4 x 10
##   city                  n_osservazioni media_sales sd_sales min_sales max_sales
##   <chr>                          <int>       <dbl>    <dbl>     <int>     <int>
## 1 Tyler                             60        270.     62.0       143       423
## 2 Bryan-College Station             60        206.     85.0        89       403
## 3 Beaumont                          60        177.     41.5        83       273
## 4 Wichita Falls                     60        116.     22.2        79       167
##   media_median_price sd_median_price media_volume sd_volume
##                <dbl>           <dbl>        <dbl>     <dbl>
## 1            141442.           9337.         45.8     13.1 
## 2            157488.           8852.         38.2     17.2 
## 3            129988.          10105.         26.1      6.97
## 4            101743.          11320.         13.9      3.24
print("summary completo delle variabili per città: ")
## [1] "summary completo delle variabili per città: "
print(summary_per_città)
## # A tibble: 4 x 10
##   city                  n_osservazioni media_sales sd_sales min_sales max_sales
##   <chr>                          <int>       <dbl>    <dbl>     <int>     <int>
## 1 Tyler                             60        270.     62.0       143       423
## 2 Bryan-College Station             60        206.     85.0        89       403
## 3 Beaumont                          60        177.     41.5        83       273
## 4 Wichita Falls                     60        116.     22.2        79       167
## # i 4 more variables: media_median_price <dbl>, sd_median_price <dbl>,
## #   media_volume <dbl>, sd_volume <dbl>
#Visualizziamo tutte le colonne
print(as.data.frame(summary_per_città))
##                    city n_osservazioni media_sales sd_sales min_sales max_sales
## 1                 Tyler             60      269.75    61.96       143       423
## 2 Bryan-College Station             60      205.97    84.98        89       403
## 3              Beaumont             60      177.38    41.48        83       273
## 4         Wichita Falls             60      116.07    22.15        79       167
##   media_median_price sd_median_price media_volume sd_volume
## 1           141441.7         9336.54        45.77     13.11
## 2           157488.3         8852.24        38.19     17.25
## 3           129988.3        10104.99        26.13      6.97
## 4           101743.3        11320.03        13.93      3.24
#da questo risultato abbiamo una panoramica completa delle diverse features per
#tutte le città, per esempio partendo da sinistra e guardando alle osservaizoni,
#vediamo il numero totale di osservazioni per città, le vendite medie, che come 
#abbiamo visto durante l'eda dei dati sono dominate da tyler, seguite da bryan,
#beaumont e eichita, delineando la differenza osservata nelle analisi precedenti.

Analisi delle Serie Storiche

Analisi Mensile

#Partiamo con l'analisi delle serie storiche

#Allora partiamo innanzitutto con lo studio dei mesi
#Nel settore immobiliare, la stagionalità è un fenomeno importante.
#Ad esempio le famiglie si traferiscono durante l'estate per non far perdere gli
#anni scoalstici ai propri figli.

#aggreghiamo i dati per ottenere i totali mensili per città

vendite_mensili = dati %>%
  group_by(month,city) %>%
  summarise(totale_vendite = sum(sales), .groups= 'drop')

#verifichiamo che l'aggregazione sia corretta
print("Vendite mensili per città")
## [1] "Vendite mensili per città"
print(vendite_mensili)
## # A tibble: 48 x 3
##    month city                  totale_vendite
##    <int> <chr>                          <int>
##  1     1 Beaumont                         608
##  2     1 Bryan-College Station            591
##  3     1 Tyler                            907
##  4     1 Wichita Falls                    442
##  5     2 Beaumont                         677
##  6     2 Bryan-College Station            628
##  7     2 Tyler                           1058
##  8     2 Wichita Falls                    454
##  9     3 Beaumont                         855
## 10     3 Bryan-College Station            949
## # i 38 more rows
#A questo punto andiamo a creare un grafico a barre sovrapposte che ci permetterà
#di visualizzare le  il totale complessivo delle vendite per ogni mese

grafico_barre_sovrapposte = vendite_mensili %>%
  ggplot(aes(x = as.factor(month), y = totale_vendite, fill = city)) +
  geom_col(alpha = 0.8) +
  labs(title = "Distribuzione Mensile delle Vendite Immobiliari",
       subtitle = "Vendite totali per mese, suddivise per città (2010-2014)",
       x = "Mese", 
       y = "Totale Vendite",
       fill = "Città") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 10)) +  # Ruota le etichette
  scale_x_discrete(labels = month.abb) +
  scale_fill_brewer(type = "qualitative", palette = "Set2")

print(grafico_barre_sovrapposte)

#allora innanzitutto cosa diciamo: abbiamo utilizzato geomcol() perchè avevamo già
#avevamo già il valori aggregati calcolati in anticipo, se non l'avessimo avuti
#avremmo dovuto utilizzare geombar() che avrebbe contato in automatico le frequenze
#della variabile qualitativa.
## Analisi della Distribuzione Mensile delle Vendite

#Il grafico a barre sovrapposte rivela una chiara stagionalità nel mercato immobiliare
#texano con pattern consistenti tra le quattro città analizzate. 
# Grafico normalizzato (percentuali)
grafico_barre_normalizzato = vendite_mensili %>%
  ggplot(aes(x = as.factor(month), y = totale_vendite, fill = city)) +
  geom_col(position = "fill", alpha = 0.8) +
  labs(title = "Composizione Percentuale delle Vendite Mensili",
       subtitle = "Quota di mercato di ciascuna città per mese (2010-2014)",
       x = "Mese", y = "Proporzione delle Vendite (%)", fill = "Città") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 10)) +
  scale_x_discrete(labels = month.abb) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(type = "qualitative", palette = "Set2")

print(grafico_barre_normalizzato)

#Il grafico percentuale rivela una stabilità notevole delle quote di mercato 
#tra le quattro città durante tutto l'anno. Tyler mantiene costantemente circa il 45% del mercato, 
#seguito da Bryan-College Station, Beaumont il  e Wichita Falls il confermando ciò
#che avevamo visto nelle analisi precedenti

Analisi Trimestrale con Anni

#Adesso andiamo ad inserire anche gli anni. come lo facciamo? Bene per ottenere
#una visualizzazione migliore andiamo a suddividere i mesi per trimestri, facendo
#quindi un'analisi quadrimestrale

dati_trimestri_clean = dati %>%
  mutate(
    trimestre = case_when(
      month %in% 1:3 ~ "Q1 (Gen-Mar)",
      month %in% 4:6 ~ "Q2 (Apr-Giu)", 
      month %in% 7:9 ~ "Q3 (Lug-Set)",
      month %in% 10:12 ~ "Q4 (Ott-Dic)"
    ),
    # Creiamo un fattore ordinato per garantire la sequenza corretta
    trimestre_ord = factor(trimestre, levels = c("Q1 (Gen-Mar)", "Q2 (Apr-Giu)", 
                                                 "Q3 (Lug-Set)", "Q4 (Ott-Dic)"))
  ) %>%
  group_by(year, trimestre_ord, city) %>%
  summarise(totale_vendite = sum(sales), .groups = 'drop')

# Visualizzazione ottimizzata
grafico_trimestri = dati_trimestri_clean %>%
  ggplot(aes(x = trimestre_ord, y = totale_vendite, fill = city)) +
  geom_col(alpha = 0.8, width = 0.7) + 
  facet_grid(~year, scales = "fixed") +  # Layout orizzontale per confronto diretto
  labs(
    title = "Evoluzione Trimestrale delle Vendite Immobiliari",
    subtitle = "Confronto inter-annuale delle performance trimestrali (2010-2014)",
    x = "Trimestre", 
    y = "Totale Vendite",
    fill = "Città"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 9),  # Etichette inclinate ma leggibili
    strip.text = element_text(face = "bold", size = 11),  # Anni evidenziati
    panel.spacing = unit(0.8, "cm"),  # Spazio tra pannelli per chiarezza
    legend.position = "bottom"  # Legenda in basso per risparmiare spazio verticale
  ) +
  scale_fill_brewer(type = "qualitative", palette = "Set2")  # Manteniamo coerenza colori

print(grafico_trimestri)

## Analisi dell'Evoluzione Temporale Multi-dimensionale
#Il grafico trimestrale rivela pattern stagionali consistenti e trend evolutivi 
#significativi nel mercato immobiliare texano. La stagionalità è marcata e stabile: 
#il secondo trimestre (aprile-giugno) rappresenta costantemente il picco delle 
#vendite in tutti gli anni analizzati, confermando l'influenza del calendario 
#scolastico e delle condizioni climatiche favorevoli sui tempi di trasferimento 
#delle famiglie.
#Dal punto di vista evolutivo, emerge chiaramente una ripresa progressiva del mercato 
#dal 2011 in poi, con il 2013 che segna un punto di svolta decisivo. I volumi 
#del secondo e terzo trimestre 2013 raggiungono livelli superiori a qualsiasi 
#periodo precedente, indicando una fase di espansione sostenuta che si consolida nel 2014. 
#Tyler mantiene la leadership, seguita da Bryan-College Station, Beaumont e Wichita Falls.
#Questa costanza suggerisce che i fattori strutturali dei mercati locali prevalgono 
#sulle fluttuazioni temporali, confermando la segmentazione geografica identificata 
#nelle analisi precedenti.

Serie Storiche - Line Chart

###Serie storiche - Line chart

#La prima cosa che faremo, sarà andare a costruire una variabile temèporale continua
#e ordinata. Questo è il fondamento dei linechart


vendite_temporali = dati %>%
  mutate(dati_continui= as.Date(paste(year,month,"01", sep="-")))%>%
  #ordiniamo i dati
  arrange(dati_continui, city)%>%
  #Raggruppiamo per data e città
  group_by(dati_continui,city)%>%
  summarise(vendite_mensili= sum(sales),.groups ='drop')

#stampiamo
print("Prime 8 righe della timeline:")
## [1] "Prime 8 righe della timeline:"
print(head(vendite_temporali, 8))
## # A tibble: 8 x 3
##   dati_continui city                  vendite_mensili
##   <date>        <chr>                           <int>
## 1 2010-01-01    Beaumont                           83
## 2 2010-01-01    Bryan-College Station              89
## 3 2010-01-01    Tyler                             160
## 4 2010-01-01    Wichita Falls                      89
## 5 2010-02-01    Beaumont                          108
## 6 2010-02-01    Bryan-College Station             107
## 7 2010-02-01    Tyler                             181
## 8 2010-02-01    Wichita Falls                      91
print("Ultime 8 righe della timeline:")
## [1] "Ultime 8 righe della timeline:"
print(tail(vendite_temporali, 8))
## # A tibble: 8 x 3
##   dati_continui city                  vendite_mensili
##   <date>        <chr>                           <int>
## 1 2014-11-01    Beaumont                          180
## 2 2014-11-01    Bryan-College Station             169
## 3 2014-11-01    Tyler                             300
## 4 2014-11-01    Wichita Falls                      96
## 5 2014-12-01    Beaumont                          202
## 6 2014-12-01    Bryan-College Station             200
## 7 2014-12-01    Tyler                             332
## 8 2014-12-01    Wichita Falls                     109
#CONTROLLIAMO CHE NON CI SIANO VALORI MANCANTI
print(paste("Totale Osservazioni: ", nrow(vendite_temporali)))
## [1] "Totale Osservazioni:  240"
print(paste("Dovrebbero essere : ", 60*4, "60 mesi X 4 città"))
## [1] "Dovrebbero essere :  240 60 mesi X 4 città"
#Perfetto a quanto pare non ci sono valori mancanti
#ora passiamo al creare il linechart

linechart = vendite_temporali %>%
  ggplot(aes(x=dati_continui, y=vendite_mensili,
             color=city, group=city))+
  geom_line(size = 0.5, alpha = 2)+
  geom_point(size = 1.5, alpha = 0.8)+
  labs(title = "Dinamiche Temporali delle Vendite Immobiliari",
       x="Anno", y="Vendite Mensili", 
       color="Città")+
  theme_minimal()+
  theme(
    # Miglioramenti estetici
    legend.position = "bottom",
    legend.title = element_text(face = "bold"),
    plot.title = element_text(size = 14, face = "bold"),
    plot.subtitle = element_text(size = 11, color = "gray40"),
    axis.text.x = element_text(angle = 45, hjust = 1, size = 10),
    panel.grid.minor = element_blank()  # Rimuove griglie minori per pulizia
  )+
  scale_color_brewer(type = "qualitative", palette = "Set2") +
  # Formattiamo l'asse temporale per chiarezza
  scale_x_date(date_breaks = "6 months", date_labels = "%Y-%m") +
  # Scala Y con intervalli regolari
  scale_y_continuous(breaks = seq(0, 500, 50))

print(linechart)

Interpretazione delle Serie Storiche

Conclusioni

Risultati Principali

L’analisi statistica multidimensionale del mercato immobiliare texano ha rivelato un ecosistema caratterizzato da quattro mercati geograficamente distinti con dinamiche competitive stabili ma differenziate.

Gerarchia Competitiva

L’analisi ha confermato una gerarchia competitiva stabile e persistente nel tempo:

  • Tyler: Leader indiscusso del mercato texano, registrando vendite medie e volumi elevati, caratterizzandosi come mercato premium ad alta domanda
  • Bryan-College Station: Secondo player, distinguendosi per la più alta efficienza di conversione degli annunci e prezzi mediani superiori, configurandosi come mercato premium efficiente legato all’economia universitaria
  • Beaumont: Mercato bilanciato con performance intermedie su tutti gli indicatori
  • Wichita Falls: Segmento entry-level con prezzi accessibili ma volumi contenuti

Questa stratificazione dimostra che il mercato texano non è omogeneo ma articolato in segmenti che richiedono approcci differenziati.

Validità Metodologica

La correlazione di 0.9876 tra prezzo medio e median price conferma l’omogeneità strutturale del mercato texano, validando l’uso del median price come proxy affidabile per analisi predittive. Il mercato si comporta in modo matematicamente coerente e prevedibile.

Pattern Temporali

La stagionalità è marcata e consistente: il Q2 (aprile-giugno) rappresenta sistematicamente il picco delle vendite in tutte le città, riflettendo calendario scolastico e condizioni climatiche. Il 60% dell’attività si concentra nei sei mesi da marzo ad agosto, richiedendo pianificazione operativa ciclica.

Raccomandazioni Operative

Per Città Specifica

  • Tyler: Strategie premium, ottimizzazione efficienza conversione, gestione tempi inventory lunghi (12 mesi)
  • Bryan-College Station: Mantenere eccellenza operativa, sfruttare cicli universitari per turnover rapido (7.5 mesi)
  • Beaumont: Strategie di volume e crescita quota mercato
  • Wichita Falls: Focus accessibilità e first-time buyers

Strategiche Generali

La prevedibilità dei pattern identificati permette a Texas Realty Insights di operare con pianificazione data-driven, ottimizzando risorse per la stagionalità e implementando strategie differenziate per mercato, trasformando l’analisi statistica in vantaggio competitivo sostenibile.


Fine dell’Analisi

Progetto completato per Texas Realty Insights - Analisi Statistica del Mercato Immobiliare del Texas (2010-2014)