Importa il dataset “Real Estate Texas.csv” e vediamo quante unità statistiche ci sono nel dataset

setwd("C:/Users/arist/Desktop/CORSI/PROFESSION_AI/Progetti/Progetto_2_STAT_DESCRITTIVA")

data = read.csv("realestate_texas.csv", header= TRUE, sep= ",")

n = dim(data)[1]
print(n)
## [1] 240

ci sono 240 unità statistiche

1. Indica il tipo di variabili contenute nel dataset. (Attenzione alle variabili che sottintendono il tempo e a come vengono trattate!)

● city: città —> qualitativa nominale

● year: anno di riferimento —> quantitativa continua, da trattare come qualitativa ordinabile in questo caso.

● month: mese di riferimento —> qualitativa nominale (ciclica) ma codificata in numeri

● sales: numero totale di vendite —> quantitativa discreta

● volume: valore totale delle vendite in milioni di dollari —> quantitativa continua

● median_price: prezzo mediano di vendita in dollari —> quantitativa continua

● listings: numero totale di annunci attivi —> quantitativa discreta

● months_inventory: quantità di tempo necessaria per vendere tutte le inserzioni correnti al ritmo attuale delle vendite, espresso in mesi. —> quantitativa continua

2. Calcola Indici di posizione, variabilità e forma per tutte le variabili per le quali ha senso farlo, per le altre crea una distribuzione di frequenza. Commenta tutto brevemente.

city -> questa è una variabile qualitativa nominale, per tale variabile possiamo calcolare principalmente la frequenza assoluta e relativa, la moda, l’indice di gini e analizzare la distribuzione delle frequenze.

ni = table(data$city)
fi = table(data$city)/n
freq_city = cbind(ni, fi) 

# Carica la libreria knitr per kable
library(knitr)

# Visualizza la tabella con kable
kable(freq_city)
ni fi
Beaumont 60 0.25
Bryan-College Station 60 0.25
Tyler 60 0.25
Wichita Falls 60 0.25

L’output ci mostra che sono presenti 4 città ed hanno una frequenza assoluta tutte di 60 con una relativa del 25%.

Per tale variabile non c’è una moda ed è perfettamente bilanciata nel dataset dato che i valori hanno tutte la stessa frequenza relativa.

Non abbiamo calcolato le frequenze cumulate in quanto non è una variabile ordinabile.

Ora grafichiamo quest’output ed in seguito calcoliamo l’indice di Gini.

library(ggplot2)

ggplot(data = data) +
  geom_bar(aes(x = city),
           stat = "count",
           col = "black",
           fill = "blue") +
  labs(title = "Distribution of absolute frequencies for the city variable",
       x = "City names",
       y = "Absolute frequencies") +
  scale_y_continuous(breaks = seq(0,70,10))

Calcoliamo l’indice di gini per city:

# Funzione per calcolare l'indice di Gini normalizzato

norm_gini_index <- function(x) {
  ni = table(x)
  fi = ni/length(x)
  fi2 = fi^2
  j = length(table(x))
  
  gini = 1 - sum(fi2)
  normalized_gini = gini/((j-1)/j)
  
  return(normalized_gini)
}

# utilizzo
city_gini_index = norm_gini_index(data$city)
print(city_gini_index)
## [1] 1

Come era prevedibile, l’indice di gini normalizzato è uguale ad 1, questo perché la variabile presenta massima eterogeneità in quanto la distribuzione dei dati è perfettamente bilanciata (distribuzione uniforme).

Passiamo ora alla variabile year.

year -> rappresenta l’anno di riferimento ed è una variabile quantitativa discreta ordinabile.

Essendo una variabile ordinabile possiamo calcolare anche le frequenze comulate.

ni_year = table(data$year)
fi_year = table(data$year)/n
f_cum_year = cumsum(ni_year)
fr_cum_year = cumsum(fi_year)

freq_year = cbind(ni_year, fi_year, f_cum_year, fr_cum_year)
kable(freq_year)
ni_year fi_year f_cum_year fr_cum_year
2010 48 0.2 48 0.2
2011 48 0.2 96 0.4
2012 48 0.2 144 0.6
2013 48 0.2 192 0.8
2014 48 0.2 240 1.0

L’output ci mostra che, come per la variabile city, la variabile year è perfettamente bilanciata nel dataset.

Ci sono 5 distinti anni dal 2010 al 2014 e ognuno di essi ha la stessa probabilità di esssere estratto dal dataset del 20% , non c’è una moda in quanto presentano le stesse frequenze assolute (48).

month -> rappresenta il mese di riferimento ed è una variabile qualitativa nominale.

ni_month = table(data$month)
fi_month = table(data$month)/n

freq_month = cbind(ni_month, fi_month)
month_gini_index = norm_gini_index(data$month)
print(month_gini_index)
## [1] 1
kable(freq_month)
ni_month fi_month
20 0.0833333
20 0.0833333
20 0.0833333
20 0.0833333
20 0.0833333
20 0.0833333
20 0.0833333
20 0.0833333
20 0.0833333
20 0.0833333
20 0.0833333
20 0.0833333

sales -> rappresenta il numero totale di vendite ed è una variabile quantitativa discreta.

Per prima cosa andiamo a visualizzare un istrogramma di tale variabile per farci un’idea immediata della sua distribuzione.

# Function to visualize the histogram of a variable
visualize_histogram <- function(data, variable, breaks = 10) {
  # Calculate the mean and median
  mean_value <- mean(data[[variable]], na.rm = TRUE)
  median_value <- median(data[[variable]], na.rm = TRUE)
  
  # Visualize the histogram
  hist(data[[variable]],
       main = paste("Histogram of", variable, "with Density Curve"),
       xlab = variable,
       ylab = "Relative Frequencies",
       col = "lightblue",
       border = "black",
       breaks = breaks,
       freq = FALSE)  # Set freq = FALSE to normalize the histogram
  
  # Add the density curve
  lines(density(data[[variable]], na.rm = TRUE), col = "red", lwd = 2)  # Red line with thickness 2
  
  # Add vertical lines for the mean and median
  abline(v = mean_value, col = "green", lwd = 2, lty = 2)  # Green dashed line for the mean
  abline(v = median_value, col = "blue", lwd = 2, lty = 2)  # Blue dashed line for the median
  
  # Add a legend for the lines
  legend("topright", legend = c(paste("Mean =", round(mean_value, 2)), 
                                paste("Median =", round(median_value, 2))),
         col = c("green", "blue"), lwd = 2, lty = 2)
}

# variabile sales

mean_sales = mean(data$sales)
median_sales = median(data$sales)
s_min = min(data$sales)
s_max = max(data$sales)
range = s_max - s_min

sd_sales <- sd(data$sales)

# Call the function to visualize the histogram of the variable "sales"
visualize_histogram(data, "sales", breaks = 10)

Il grafico ci mostra che sono più frequenti valori o modalità basse; quindi, la distribuzione di “sales” è assimetrica positiva.

sales varia da un minimo di 79 vendite ad un massimo di 423 vendite con un range di 344.

La media delle vendite totali nel dataset è 192.29 con una mediana di 176.

Ora calcoliamo i sui indici di forma e di variabilità.

# indici di forma

library(e1071)    # for skewness and kurtosis functions

print(paste("La asimmetria è:", round(skewness(data$sales), 3)))
## [1] "La asimmetria è: 0.714"
print(paste("La curtosi è:", round(kurtosis(data$sales), 3)))
## [1] "La curtosi è: -0.336"

Come ci potevamo immaginare dal grafico, l’indice di fisher è maggiore di 0, la distribuzione risulta essere assimetrica positiva.

L’indice di curtosi risulta essere minore di 3 quindi la distribuzione risulta essere platicurtica con code meno pronuncite ed un picco più basso rispetto alla distribuzione normale.

# Function to visualize the boxplot of a variable
visualize_boxplot <- function(data, variable) {
  # Calculate quartiles
  sales_quartile <- quantile(data[[variable]], probs = c(0.25, 0.5, 0.75))  # Q1, Median (Q2), Q3
  s_min <- min(data[[variable]], na.rm = TRUE)  # Minimum value
  s_max <- max(data[[variable]], na.rm = TRUE)  # Maximum value
  
  # Create the boxplot
  boxplot(data[[variable]],
          main = paste("Horizontal Boxplot of", variable, "with Quartiles, Min, and Max"),
          xlab = variable,  # Label for x-axis
          col = "lightblue",
          border = "black",
          horizontal = TRUE)  # Set the boxplot to horizontal
  
  # Add labels for quartiles
  text(y = 0.75, x = sales_quartile[1] - 30, labels = paste("Q1 =", round(sales_quartile[1], 2)), 
       pos = 4, col = "#006400")   # Q1 in green
  text(y = 1.25, x = sales_quartile[2] - 30, labels = paste("Median =", round(sales_quartile[2], 2)), 
       pos = 4, col = "red")  # Median in red
  text(y = 0.75, x = sales_quartile[3] - 30, labels = paste("Q3 =", round(sales_quartile[3], 2)), 
       pos = 4, col = "blue")   # Q3 in blue
  
  # Add labels for minimum and maximum
  text(y = 1.15, x = s_min - 18, labels = paste("Min =", round(s_min, 2)), 
       pos = 4, col = "black")  # Minimum in black
  text(y = 1.15, x = s_max - 45, labels = paste("Max =", round(s_max, 2)), 
       pos = 4, col = "black")  # Maximum in black
  
  # Add colored lines for quartiles
  segments(sales_quartile[1], 0.8, sales_quartile[1], 1.2, col = "#006400", lwd = 3)  # Q1 in green
  segments(sales_quartile[2], 0.8, sales_quartile[2], 1.2, col = "red", lwd = 3)    # Median in red
  segments(sales_quartile[3], 0.8, sales_quartile[3], 1.2, col = "blue", lwd = 3)   # Q3 in blue
  }

# Call the function to visualize the boxplot of the variable "sales"
visualize_boxplot(data, "sales")

sales_iqr = IQR(data$sales)
coeff_var <- (sd_sales / mean_sales) * 100

Interpretazione

Passiamo ora alla variabile volume:

visualize_histogram(data, 'volume')

visualize_boxplot <- function(data, variable) {
  # Calculate quartiles
  quartile <- quantile(data[[variable]], probs = c(0.25, 0.5, 0.75))  # Q1, Median (Q2), Q3
  min <- min(data[[variable]], na.rm = TRUE)  # Minimum value
  max <- max(data[[variable]], na.rm = TRUE)  # Maximum value
  
  # Create the boxplot
  boxplot(data[[variable]],
          main = paste("Horizontal Boxplot of", variable, "with Quartiles, Min, and Max"),
          xlab = variable,  # Label for x-axis
          col = "lightblue",
          border = "black",
          horizontal = TRUE)  # Set the boxplot to horizontal
  
  # Add labels for quartiles
  text(y = 0.75, x = quartile[1] - 5 , labels = paste("Q1 =", round(quartile[1], 2)), 
       pos = 4, col = "#006400")   # Q1 in green
  text(y = 1.25, x = quartile[2] - 5, labels = paste("Median =", round(quartile[2], 2)), 
       pos = 4, col = "red")  # Median in red
  text(y = 0.75, x = quartile[3] - 5, labels = paste("Q3 =", round(quartile[3], 2)), 
       pos = 4, col = "blue")   # Q3 in blue
  
  # Add labels for minimum and maximum
  text(y = 1.15, x = min - 4, labels = paste("Min =", round(min, 2)), 
       pos = 4, col = "black")  # Minimum in black
  text(y = 1.15, x = max - 10, labels = paste("Max =", round(max, 2)), 
       pos = 4, col = "black")  # Maximum in black
  
  # Add colored lines for quartiles
  segments(quartile[1], 0.8, quartile[1], 1.2, col = "#006400", lwd = 3)  # Q1 in green
  segments(quartile[2], 0.8, quartile[2], 1.2, col = "red", lwd = 3)    # Median in red
  segments(quartile[3], 0.8, quartile[3], 1.2, col = "blue", lwd = 3)   # Q3 in blue
}

visualize_boxplot(data, 'volume')

Il boxplot ci mostra che sono presenti alcuni outlier.

Ora visualizziamo in tabella gli indici di posizione variabilità e forma:

position_index <- function(variable) {
  
  min = round(min(variable), 3)
  max = round(max(variable), 3)
  mean = round(mean(variable), 3)
  median = round(median(variable), 3)
  q1 = round(quantile(variable, probs = c(0.25)), 3)
  q3 = round(quantile(variable, probs = c(0.75)), 3)

  df <- data.frame(min=min, q1=q1, median=median, q3=q3, max=max, mean=mean)
  rownames(df) <- 1:nrow(df)
  return(df)
}

volume_position_index = position_index(data$volume)
kable(volume_position_index)
min q1 median q3 max mean
8.166 17.66 27.062 40.893 83.547 31.005
variable_index <- function(variable) {
  
  sd = round(sd(variable), 3)
  range = round(max(variable) - min(variable) , 3)
  mean = round(mean(variable), 3)
  cv = round((sd / mean) * 100, 3)
  IQR = round(IQR(variable), 3)

  df <- data.frame(sd=sd, range=range, cv=cv, iqr=IQR)
  
  return(df)
}

volume_var_index = variable_index(data$volume)
kable(volume_var_index)
sd range cv iqr
16.651 75.381 53.704 23.233
print(paste("La asimmetria è:", round(skewness(data$volume), 3)))
## [1] "La asimmetria è: 0.879"
print(paste("La curtosi è:", round(kurtosis(data$volume), 3)))
## [1] "La curtosi è: 0.151"

L’indice di asimmetria di fisher è positivo e ci conferma che la distribuzione è asimmetrica positiva con coda allungata verso destra.

L’indice di kurtosi è maggiore di 3, questo ci indica che la distribuzione è leptocurtica con una coda più allungata/appuntita rispetto ad una distribuzione normale.

median_price: prezzo mediano di vendita in dollari – > quantitativa continua

Utilizziamo le stesse funzioni create precedentemente per visualizzare i vari indici e i grafici.

# median_price

median_price_position_index = position_index(data$median_price)
kable(median_price_position_index)
min q1 median q3 max mean
73800 117300 134500 150050 180000 132665.4
median_price_var_index = variable_index(data$median_price)
kable(median_price_var_index)
sd range cv iqr
22662.15 106200 17.082 32750
median_price_skewness = round(skewness(data$median_price),3)
median_price_kurtosi = round(kurtosis(data$median_price), 3)

print(paste("La asimmetria è:", round(skewness(data$median_price), 3)))
## [1] "La asimmetria è: -0.362"
print(paste("La curtosi è:", round(kurtosis(data$median_price), 3)))
## [1] "La curtosi è: -0.643"

Kurtosis < 3: Distribuzione platicurtica (distribuzione più piatta rispetto ad una normale).

Skewness < 0: La distribuzione è asimmetrica a sinistra (coda lunga a sinistra).

visualize_histogram(data, "median_price")

visualize_boxplot(data, 'median_price')

listings: numero totale di annunci attivi —> quantitativa discreta

# listings

listings_var_index = variable_index(data$listings)
kable(listings_var_index)
sd range cv iqr
752.708 2553 43.308 1029.5
listings_position_index = position_index(data$listings)
kable(listings_position_index)
min q1 median q3 max mean
743 1026.5 1618.5 2056 3296 1738.021
listings_skewness = round(skewness(data$listings),3)
listings_kurtosi = round(kurtosis(data$listings), 3)

print(paste("La asimmetria è:", listings_skewness, 3))
## [1] "La asimmetria è: 0.645 3"
print(paste("La curtosi è:", listings_kurtosi))
## [1] "La curtosi è: -0.81"

months_inventory: quantità di tempo necessaria per vendere tutte le inserzioni correnti al ritmo attuale delle vendite, espresso in mesi. —> quantitativa continua

months_var_index = variable_index(data$months_inventory)
kable(months_var_index)
sd range cv iqr
2.304 11.5 25.063 3.15
months_position_index = position_index( data$months_inventory)
kable(months_position_index)
min q1 median q3 max mean
3.4 7.8 8.95 10.95 14.9 9.193
months_skewness = round(skewness(data$months_inventory),3)
months_kurtosi = round(kurtosis(data$months_inventory), 3)

print(paste("La asimmetria è:", months_skewness))
## [1] "La asimmetria è: 0.041"
print(paste("La curtosi è:", months_kurtosi))
## [1] "La curtosi è: -0.198"

3. Qual è la variabile con variabilità più elevata? Come ci sei arrivato? E quale quella più asimmetrica?

Per confrontare la variabilità tra le variabili utilizziamo il coefficiente di variazione (cv).

Il CV è particolarmente utile quando si devono confrontare variabili o dataset con unità di misura o ordini di grandezza differenti poiché, essendo un numero senza dimensioni, ti permette di confrontare direttamente la variabilità relativa indipendentemente dalla scala.

Indica quanto la deviazione standard è grande rispetto alla media.

Se il valore del CV è inferiore a 1, la variabilità è bassa rispetto alla media.

Un CV superiore a 1 indica una variabilità più alta rispetto alla media.

La variabile con variabilità più elevata in base ai cv che abbiamo calcolato precedentemente è volume che rappresenta il valore totale delle vendite espresso in milioni di dollari.

Volume rappresenta anche la variabile più asimmetrica in quanto ha un indice di fisher più elevato rispetto agli altri.

1. Dividi una delle variabili quantitative in classi, scegli tu quale e come, costruisci la distribuzione di frequenze, il grafico a barre corrispondente e infine calcola l’indice di Gini.

Scelgo la variabile quantitativa discreta listings che rappresenta il numero di annunci attivi.

Dividiamo questa variabile in 3 categorie: numero di annunci bassi, medi ed alti.

min_listings = min(data$listings)
max_listings = max(data$listings)

# Suddividi la variabile in 3 etichette usando cut() ed i quartili

labels <- c("Basso", "Medio", "Alto")
breaks <- quantile(data$listings, probs = seq(0, 1, by = 1/3), na.rm = TRUE)  

data$listings_labels <- cut(data$listings,
                            breaks = c(743.0, 1405.667, 1759.333, 3296.0),include.lowest = TRUE,labels = labels)
frequency_distribution <- function(data) {

  # Crea una tabella delle frequenze
  freq_table <- table(data)
  
  # Calcola le frequenze relative e percentuali
  freq_relative <- prop.table(freq_table)
  freq_percentuale <- freq_relative * 100
  
  # Calcola le frequenze cumulate e percentuali cumulate
  freq_cumulata <- cumsum(freq_table)
  freq_cumulata_percentuale <- cumsum(freq_percentuale)
  
  # Crea un dataframe con i risultati
  frequency_distribution <- data.frame(
    Modalità = names(freq_table),
    Frequenze_Assolute = as.vector(freq_table),
    Frequenze_Relative = round(freq_relative, 4),
    Frequenze_Percentuali = round(freq_percentuale, 2),
    Frequenze_Cumulate = freq_cumulata,
    Frequenze_Cumulate_Percentuali = round(freq_cumulata_percentuale, 2)
  )
  
  return(frequency_distribution)
}

frq_diss_listings_labels = frequency_distribution(data$listings_labels)

kable(frq_diss_listings_labels)
Modalità Frequenze_Assolute Frequenze_Relative.data Frequenze_Relative.Freq Frequenze_Percentuali.data Frequenze_Percentuali.Freq Frequenze_Cumulate Frequenze_Cumulate_Percentuali
Basso Basso 80 Basso 0.3333 Basso 33.33 80 33.33
Medio Medio 80 Medio 0.3333 Medio 33.33 160 66.67
Alto Alto 80 Alto 0.3333 Alto 33.33 240 100.00
ggplot(data = data) +
  geom_bar(aes(x = listings_labels),
           stat = "count",
           col = "black",
           fill = "blue") +
  labs(title = "Distribution of absolute frequencies for listings_labels",
       x = "listings_labels",
       y = "Absolute frequencies") +
   scale_y_continuous(breaks = seq(0,90,10))

print(norm_gini_index(data$listings_labels))
## [1] 1

Come possiamo notare anche dal grafico, l’indice di gini risulta essere 1.

5. “Indovina” l’indice di gini per la variabile city.

L’indice di Gini per la variabile city è 1 in quanto la frequenza assoluta di tutte le sua modalità è la stessa.

6. Qual è la probabilità che presa una riga a caso di questo dataset essa riporti la città “Beaumont”? E la probabilità che riporti il mese di Luglio? E la probabilità che riporti il mese di dicembre 2012?

Per rispondere a questa domanda possiamo vedere le distribuzione di frequenza relativa calcolate precedentemente.

P di Beaumont = 25%

P di Luglio = 8.3%

Mentre, per rispondere alla domanda che una riga riporti il mese di dicembre 2012, possiamo costruire una tabella di frequenza doppia prendendo in considerazione il mese e l’anno.

# Crea una tabella delle frequenze
freq_table <- table(data$month, data$year)
  
# Calcola le frequenze relative e percentuali
freq_relative <- round(prop.table(freq_table),3)
freq_percentuale <- freq_relative * 100

print(freq_percentuale[12, "2012"])
## [1] 1.7

7. Esiste una colonna col prezzo mediano, creane una che indica invece il prezzo medio, utilizzando le altre variabili che hai a disposizione.

Per realizzare questo punto utilizziamo le variabili sales e volume.

Volume è il totale delle vendite in milioni di dollari e per prima cosa lo convertiamo in dollari.

In seguito, dividiamo il risultato per sales che rappresenta il numero totale di vendite.

data$volume_in_dollar = data$volume * 1000000
data$mean_price = data$volume_in_dollar / data$sales

8. Prova a creare un’altra colonna che dia un’idea di “efficacia” degli annunci di vendita. Riesci a fare qualche considerazione?

Per avere un’idea dell’efficacia degli annunci sulle vendite possiamo fare il rapporto tra le vendite effettive di case e il numero di annunci, prendere i quartili di questa nuova variabile e fare una suddivisione in classi.

data$ad_efficacy <- data$sales / data$listings

# Suddividere l'efficacia in categorie basate sui quartili
quartili <- quantile(data$ad_efficacy, probs = c(0.25, 0.5, 0.75), na.rm = TRUE)

data$efficacia_cat <- cut(
  data$ad_efficacy,
  breaks = c(-Inf, quartili[1], quartili[2], quartili[3], Inf),
  labels = c("Bassa", "Media", "Alta", "Molto Alta"),
  include.lowest = TRUE
)

Valori Alti: Un valore elevato di efficacy indica che una percentuale significativa degli annunci viene convertita in vendite. Questo suggerisce un mercato molto efficace, in cui gli annunci sono ben allineati con la domanda del mercato.

Può significare che:

Gli immobili sono ben posizionati in termini di prezzo. Gli annunci sono di alta qualità e attirano acquirenti. Esiste una forte domanda per il tipo di proprietà in questione.

Valori Bassi: Un valore basso di efficacy indica che solo una piccola percentuale degli annunci si traduce in vendite.

Ciò può segnalare:

Problemi di prezzo, dove gli immobili sono valutati troppo alti rispetto al mercato. Problemi di qualità degli annunci o delle proprietà. Un mercato saturo con troppi annunci e non abbastanza domanda.

head(data, 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
##   listings_labels volume_in_dollar mean_price ad_efficacy efficacia_cat
## 1           Medio         14162000   170626.5  0.05414220         Bassa
## 2           Medio         17690000   163796.3  0.06809584         Bassa
## 3           Medio         28701000   157697.8  0.10775607         Media
## 4           Medio         26819000   134095.0  0.11709602          Alta
## 5            Alto         28833000   142737.6  0.11405985          Alta

Prova a creare dei summary(), o semplicemente media e deviazione standard, di alcune variabili a tua scelta, condizionatamente alla città, agli anni e ai mesi. Puoi utilizzare il linguaggio R di base oppure essere un vero Pro con il pacchetto dplyr. Ti

lascio un suggerimento in pseudocodice, oltre al cheatsheet nel materiale:

Con la funzione qui creata creiamo delle summary mettendo in relazione:

· city e sales,

· year e listings,

· month e volume.

# Carichiamo il pacchetto dplyr

library(dplyr)
library(glue)

# Definiamo la funzione

summarize_by_group <- function(data, x, y) {
  data %>%
    group_by({{ x }}) %>%
    summarise(
      "{{ y }}_sum" := sum({{ y }}, na.rm = TRUE),
      "{{ y }}_mean" := round(mean({{ y }}, na.rm = TRUE), 3),
      "{{ y }}_min" := min({{ y }}, na.rm = TRUE),
      "{{ y }}_max" := max({{ y }}, na.rm = TRUE),
      "{{ y }}_sd" := round(sd({{ y }}, na.rm = TRUE), 3)
    )
}

# Esempio di utilizzo della funzione 

df_summary_city_sales <- summarize_by_group(data, city, sales)
kable(df_summary_city_sales)
city sales_sum sales_mean sales_min sales_max sales_sd
Beaumont 10643 177.383 83 273 41.484
Bryan-College Station 12358 205.967 89 403 84.984
Tyler 16185 269.750 143 423 61.964
Wichita Falls 6964 116.067 79 167 22.152
df_summary_year_listings <- summarize_by_group(data, year, listings)
kable(df_summary_year_listings)
year listings_sum listings_mean listings_min listings_max listings_sd
2010 87648 1826.000 904 3296 785.020
2011 88783 1849.646 844 3266 780.378
2012 85287 1776.812 801 3072 738.449
2013 80525 1677.604 743 2998 743.524
2014 74882 1560.042 746 2875 706.709
df_summary_month_volume <- summarize_by_group(data, month, volume)
kable(df_summary_month_volume)
month volume_sum volume_mean volume_min volume_max volume_sd
1 380.015 19.001 8.166 36.916 8.372
2 433.030 21.651 8.747 42.553 10.094
3 587.694 29.385 13.104 50.404 12.018
4 666.089 33.304 13.524 60.581 14.523
5 794.042 39.702 12.451 71.456 19.021
6 826.063 41.303 13.031 80.814 21.081
7 782.438 39.122 12.355 83.547 21.413
8 760.283 38.014 14.003 67.244 18.048
9 591.983 29.599 11.792 68.744 15.221
10 581.572 29.079 9.507 65.316 15.134
11 496.143 24.807 10.844 52.314 11.154
12 541.893 27.095 9.400 61.032 12.568

Da qui in poi utilizza ggplot2 per creare grafici fantastici!

Ma non fermarti alla semplice soluzione del quesito, prova un po’ a personalizzare i grafici utilizzando temi, colori e annotazioni, e aggiustando i vari elementi come le etichette, gli assi e la legenda.

Consiglio: Fai attenzione quando specifichi le variabili month e year tra le estetiche, potrebbe essere necessario considerarle come fattori.

Utilizza i boxplot per confrontare la distribuzione del prezzo mediano delle case tra le varie città. Commenta il risultato

# confronta prezzo mediano tra le varie città
ggplot(data, aes(x = city, y = median_price)) +
  geom_boxplot(fill = "skyblue", color = "darkblue") +
  labs(
    title = "Distribuzione del Prezzo Mediano delle Case per Città",
    x = "Città",
    y = "Prezzo Mediano delle Case"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Dal grafico possiamo affermare che le case vendute più costose si trovano mediamente a Bryan-College Station mentre quelle meno costose a Wichita Falls.

2. Utilizza i boxplot o qualche variante per confrontare la distribuzione del valore totale delle vendite tra le varie città ma anche tra i vari anni. Qualche considerazione da fare?

# confronto volume di vendite 
ggplot(data, aes(x = city, y = volume, fill = factor(year))) +
  geom_boxplot(color = "darkblue") +
  scale_fill_manual(
    values = c(
      "2010" = "red",
      "2011" = "blue",
      "2012" = "green",
      "2013" = "purple",
      "2014" = "orange"
    )
  ) +
  labs(
    title = "Distribuzione del volume totale delle Case per Città ed anno",
    x = "Città",
    y = "Volume delle vendite espresso in milioni di dollari",
    fill = "Anno"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1)
  ) +
  facet_wrap(~ year, ncol = 5)  # Layout a 5 colonne e 1 riga

In questo caso ho utilizzato un grafico che mostra i boxplot uno accanto all’altro per ogni città e per ogni anno in ordine crescente.

Dal grafico si nota come tendenzialmente c’è stato un volume totale di vendite che è aumentato nel corso di questi 5 anni per tutte le città tranne per Wichita-Falss.

Ora vediamo se questo aumento è stato dato dall’aumento del prezzo delle case o da un aumento generale di vendita delle case confrontando la variabile sales e mean_price per ogni anno.

# Carichiamo il pacchetto necessario
library(gridExtra)

# Primo grafico: distribuzione di sales per anno
plot1 <- ggplot(data, aes(x = factor(year), y = sales)) +
  geom_boxplot(fill = "skyblue", color = "darkblue") +
  labs(
    title = "Distribuzione di sales per ogni anno",
    x = "Anno",
    y = "Sales"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Secondo grafico: distribuzione di mean_price per anno
plot2 <- ggplot(data, aes(x = factor(year), y = mean_price)) +
  geom_boxplot(fill = "orange", color = "darkred") +
  labs(
    title = "Distribuzione di mean_price per ogni anno",
    x = "Anno",
    y = "Prezzo Medio"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Disposizione dei grafici affiancati
grid.arrange(plot1, plot2, ncol = 2)

Sia il numero di vendite che il prezzo delle case tendenzialmente crescono nel corso degli anni.

3. Usa un grafico a barre sovrapposte per confrontare il totale delle vendite nei vari mesi, sempre considerando le città. Prova a commentare ciò che viene fuori. Già che ci sei prova anche il grafico a barre normalizzato.

Consiglio: Stai attento alla differenza tra geom_bar() e geom_col(). PRO LEVEL: cerca un modo intelligente per inserire ANCHE la variabile Year allo stesso blocco di codice, senza però creare accrocchi nel grafico.

# creiamo un grafico a barre sovrapposte per confrontare 
# il totale delle vendite nei vari mesi, sempre considerando le città

ggplot(data, aes(x = factor(month), y = sales, fill = city)) +
  geom_bar(stat = "identity", position = "stack") +
  labs(
    title = "Totale delle vendite per mese e città",
    x = "Mese",
    y = "Totale Vendite",
    fill = "Città"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# grafico normalizzato

ggplot(data, aes(x = factor(month), y = sales, fill = city)) +
  geom_bar(stat = "identity", position = "fill") +
  labs(
    title = "Totale delle vendite per mese e città",
    x = "Mese",
    y = "Totale Vendite",
    fill = "Città"
  ) +
  scale_y_continuous(breaks = seq(0,1,0.1)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Nei grafici notiamo che nei mesi estivi il numero di vendite aumenta rispetto agli altri mesi e che la città con il più alto numero di vendite è Tyler.

Possiamo confermare quest’ultima affermazione anche con un boxplot.

ggplot(data, aes(x = city, y = sales)) + 
  geom_boxplot(color = "darkblue", fill = "lightblue") + 
  labs(
    title = "Distribuzione di sales per ogni città",
    x = "City",
    y = "Sales"
  ) + 
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

ggplot(data, aes(x = city, y = sales, fill = factor(month))) + 
  geom_boxplot(color = "darkblue") + 
  labs(
    title = "Distribuzione di sales per ogni mese e città",
    x = "City",
    y = "Sales"
  ) + 
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

é interessante notare come anche se Tyler sia in generale la città con il più alto numero di vendite durante l’anno nei mesi estivi Bryan-Collage può arrivare a superare il numero di vendite di tyler anche se essendo i boxplot più allungati questo ci suggerisce che la sua variabilità di vendite nei mesi estivi sia più alta di tyler.

Possiamo inserire la variabile year creando un grafico a barre sovrapposto per ciascun anno con il faceting.

In questo modo, ogni anno avrà il proprio pannello, mantenendo la leggibilità senza creare confusione.

# Includiamo YEAR

ggplot(data, aes(x = factor(month), y = sales, fill = city)) +
  geom_bar(stat = "identity", position = "fill") +
  labs(
    title = "Totale delle vendite per mese e città in ogni anno",
    x = "Mese",
    y = "Totale Vendite",
    fill = "Città"
  ) +
  scale_y_continuous(breaks = seq(0,1,0.1)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  facet_wrap(~ year)

4. Prova a creare un line chart di una variabile a tua scelta per fare confronti commentati fra città e periodi storici. Ti avviso che probabilmente all’inizio ti verranno fuori linee storte e poco chiare, ma non demordere.

# ultimo punto creare linechart tra year e sales per ogni città

# Aggregazione delle vendite per anno e città
agg_data <- data %>%
  group_by(year, city) %>%
  summarise(total_sales = sum(sales, na.rm = TRUE))

ggplot(agg_data, aes(x = year, y = total_sales, color = city, group = city)) +
  geom_line(size = 1) +
  geom_point(size = 2) +  # Aggiunge punti per evidenziare ogni anno
  labs(
    title = "Andamento delle vendite totali per anno e città",
    x = "Anno",
    y = "Vendite Totali",
    color = "Città"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Il line chart ci mostra come tendenzialmente nel corso degli anni le vendite siano aumentate in ogni città tranne per Wichita Falls.

Nell’anno tra il 2010 e 2011 sembrerebbe che ci sia stata come una stagnazione delle vendite.

Sono aumentate di poco Tyler rimaste costanti per Bryan-Collage e ridotte per le utlime due città.

FINE PROGETTO