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
● 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
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
I dati sono distribuiti tra 79 (minimo) e 423 (massimo).
Il 25% dei dati si trova al di sotto di 127, mentre il 75% è al di sotto di 247.
La mediana indica che la metà dei dati ha un valore inferiore a 175.5.
L’IQR di 120 mostra che c’è una certa dispersione tra i quartili, e può anche essere utile per identificare eventuali outliers nel dataset.
Il CV di circa 41% indica che la variabilità delle vendite è significativa rispetto alla media.
Questo suggerisce che, anche se la media è 192.29, le vendite possono variare in modo considerevole, il che può essere utile da sapere quando si prendono decisioni basate su queste vendite.
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"
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.
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.
L’indice di Gini per la variabile city è 1 in quanto la frequenza assoluta di tutte le sua modalità è la stessa.
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
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
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
)
Definizione: La formula per calcolare l’efficacy è: efficacy = sales / listings
Significato:
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
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.
# 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.
# 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.
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)
# 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à.