Progetto “Analisi esplorativa del mercato Immobiliare del Texsas” per conto della TEXAS REALTY INSIGHTS

# impostare la cartella contenente il file "Real Estate Texas.csv con "setwd(*percorso*)"
setwd("C:/Users/ClaudioCavaleri/OneDrive - OVER SpA/Desktop/CODICE/StatisticaR")
dati <- read.csv("Real Estate Texas.csv", sep=",")

# carico le librerie necessarie (le inserisco tutte qui per praticità)

library(dplyr) 
## 
## Caricamento pacchetto: 'dplyr'
## I seguenti oggetti sono mascherati da 'package:stats':
## 
##     filter, lag
## I seguenti oggetti sono mascherati da 'package:base':
## 
##     intersect, setdiff, setequal, union
library(moments) 
library(ggplot2) 
library(tidyr)
library(zoo)
## 
## Caricamento pacchetto: 'zoo'
## I seguenti oggetti sono mascherati da 'package:base':
## 
##     as.Date, as.Date.numeric

1. ANALISI DELLE VARIABILI

summary(dati$city)
##    Length     Class      Mode 
##       240 character character
# variabile qualitativa nominale - 4 valori caratteriali
attach(dati) 
summary(year) 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    2010    2011    2012    2012    2013    2014
# variabile qualitativa ordinale - 5 anni dal 2010 al 2014 
summary(month) 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1.00    3.75    6.50    6.50    9.25   12.00
# variabile qualitativa codifcata in numeri - i 12 mesi del'anno 
summary(sales) 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    79.0   127.0   175.5   192.3   247.0   423.0
# variabile quantitativa discreta - le vendite hanno una media più alta della mediana, segno che ci saranno più mesi con vendite alte rispetto alla mediana 
summary(volume) 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   8.166  17.660  27.062  31.005  40.893  83.547
# variabile quantitativa continua - da 8M a 83M con range IQR tra 17M e 40M 
summary(median_price) 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   73800  117300  134500  132665  150050  180000
# variabile quantitativa continua - da 73K a 180K con IQR da 117K a 150K, qui la mediana sorpassa la media 
summary(listings) 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     743    1026    1618    1738    2056    3296
# variabile quantitativa discreta - gli annunci attivi presentano un ampio range, quasi 5 volte il minimo 
summary(months_inventory)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   3.400   7.800   8.950   9.193  10.950  14.900
# variabile quantitativa continua - il tempo massimo di vendita degli immobili è di 14,9 mesi
n <- dim(dati)[1]

GESTIONE DEL TEMPO

dati$year_factor <- as.factor(dati$year)
dati$month_factor <- as.factor(dati$month)

2 CALCOLO DEGLI INDICI (POSIZIONE, VARIABILITA’ E FORMA)

# Funzione per calcolare indici di posizione, variabilità e forma

calcola_statistiche <- function(x) { 
  if (is.numeric(x)) { return(list(
    Media = mean(x, na.rm = TRUE), 
    Mediana = median(x, na.rm = TRUE),
    Deviazione_Standard = sd(x, na.rm = TRUE), 
    Varianza = var(x, na.rm = TRUE), 
    Minimo = min(x, na.rm = TRUE), 
    Massimo = max(x, na.rm = TRUE), 
    Range = max(x, na.rm = TRUE) - min(x, na.rm = TRUE), 
    Skewness = skewness(x, na.rm = TRUE), 
    Kurtosis = kurtosis(x, na.rm = TRUE)-3 )) }
  else {return(NULL) } }

# Funzione per creare una distribuzione di frequenza

crea_distribuzione_frequenza <- function(x) { 
  if (is.factor(x) || is.character(x)) { 
    return(table(x)) } 
  else { return(NULL) } }

# Applica la funzione per le statistiche a tutte le colonne

statistiche_df <- dati %>% summarise_all(calcola_statistiche)
## Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in
## dplyr 1.1.0.
## ℹ Please use `reframe()` instead.
## ℹ When switching from `summarise()` to `reframe()`, remember that `reframe()`
##   always returns an ungrouped data frame and adjust accordingly.
## ℹ The deprecated feature was likely used in the dplyr package.
##   Please report the issue at <https://github.com/tidyverse/dplyr/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
# Seleziona la colonna categorica (city) e applica la funzione per la distribuzione di frequenza

distribuzioni_freq <- dati %>% select(city) %>%
summarise_all(crea_distribuzione_frequenza)

# Trasponi il data frame delle statistiche per una migliore visualizzazione

statistiche_df_tidy <- as.data.frame(t(statistiche_df)) 
if (!is.null(statistiche_df_tidy) && ncol(statistiche_df_tidy) > 0) {
colnames(statistiche_df_tidy) <- names(statistiche_df[[1]])
print("Indici di Posizione, Variabilità e Forma:")
print(statistiche_df_tidy) } else { print("Nessuna variabile numerica
trovata per il calcolo delle statistiche.") }
## [1] "Indici di Posizione, Variabilità e Forma:"
##                     Media Mediana Deviazione_Standard  Varianza Minimo Massimo
## year                 2012    2012            1.417169  2.008368   2010    2014
## month                 6.5     6.5            3.459267  11.96653      1      12
## sales            192.2917   175.5            79.65111    6344.3     79     423
## volume           31.00519 27.0625            16.65145  277.2707  8.166  83.547
## median_price     132665.4  134500            22662.15 513572983  73800  180000
## listings         1738.021  1618.5            752.7078    566569    743    3296
## months_inventory   9.1925    8.95            2.303669  5.306889    3.4    14.9
##                   Range   Skewness   Kurtosis
## year                  4          0       -1.3
## month                11          0  -1.216783
## sales               344   0.718104 -0.3131764
## volume           75.381   0.884742   0.176987
## median_price     106200 -0.3645529 -0.6229618
## listings           2553  0.6494982   -0.79179
## months_inventory   11.5 0.04097527 -0.1744475
# Visualizza le distribuzioni di frequenza

print("\nDistribuzioni di Frequenza:") 
## [1] "\nDistribuzioni di Frequenza:"
print(distribuzioni_freq)
##   city
## 1   60
## 2   60
## 3   60
## 4   60

3 VARIABILI CON MAGGIOR VARIABILITA’ E ASIMMETRIA

if (!is.null(statistiche_df_tidy) && nrow(statistiche_df_tidy) > 0) {
  statistiche_cv <- statistiche_df_tidy %>%
    mutate(
      Media = as.numeric(Media),
      Deviazione_Standard = as.numeric(Deviazione_Standard),
      CV = (Deviazione_Standard / abs(Media)) * 100
    ) %>%
    select(CV) %>%
    arrange(desc(CV))
  
  print("Coefficienti di Variazione (CV):")
  print(statistiche_cv)
  
  variabile_piu_variabile <- rownames(statistiche_cv)[1]
  cat(sprintf("\nLa variabile con la più alta variabilità (in termini di CV) è: %s\n", variabile_piu_variabile))
} else {
  cat("Non sono state trovate variabili numeriche per calcolare la variabilità o 'statistiche_df_tidy' non è stato creato correttamente.\n")
}
## [1] "Coefficienti di Variazione (CV):"
##                           CV
## volume           53.70535868
## month            53.21949013
## listings         43.30832759
## sales            41.42202965
## months_inventory 25.06030593
## median_price     17.08218257
## year              0.07043584
## 
## La variabile con la più alta variabilità (in termini di CV) è: volume
if (!is.null(statistiche_df_tidy) && nrow(statistiche_df_tidy) > 0) {
  statistiche_skewness <- statistiche_df_tidy %>%
    select(Skewness) %>%
    mutate(
      Skewness = as.numeric(Skewness),
      abs_skewness = abs(Skewness)
    ) %>%
    arrange(desc(abs_skewness))
  
  print("\nValori Assoluti di Skewness:")
  print(statistiche_skewness)
  
  variabile_piu_asimmetrica <- rownames(statistiche_skewness)[1]
  valore_skewness_piu_asimmetrica <- statistiche_skewness$Skewness[1]
  cat(sprintf("\nLa variabile con la distribuzione più asimmetrica (in base al valore assoluto della skewness) è: %s (Skewness = %f)\n", variabile_piu_asimmetrica, valore_skewness_piu_asimmetrica))
} else {
  cat("Non sono state trovate variabili numeriche per valutare l'asimmetria o 'statistiche_df_tidy' non è stato creato correttamente.\n")
}
## [1] "\nValori Assoluti di Skewness:"
##                     Skewness abs_skewness
## volume            0.88474203   0.88474203
## sales             0.71810402   0.71810402
## listings          0.64949823   0.64949823
## median_price     -0.36455288   0.36455288
## months_inventory  0.04097527   0.04097527
## year              0.00000000   0.00000000
## month             0.00000000   0.00000000
## 
## La variabile con la distribuzione più asimmetrica (in base al valore assoluto della skewness) è: volume (Skewness = 0.884742)

4 CREAZIONI DI CLASSI PER UNA VARIBILE QUANTITATIVA

sales_cl <- c(cut(sales, seq(75,425,25)))

distr_freq_sales <- as.data.frame(  cbind(
  ni = table(sales_cl),
  fi = table(sales_cl)/n,
  Ni = cumsum(table(sales_cl)),
  Fi = cumsum(table(sales_cl)/n)))

print(distr_freq_sales)
##           ni          fi  Ni        Fi
## (75,100]  21 0.087500000  21 0.0875000
## (100,125] 38 0.158333333  59 0.2458333
## (125,150] 34 0.141666667  93 0.3875000
## (150,175] 27 0.112500000 120 0.5000000
## (175,200] 29 0.120833333 149 0.6208333
## (200,225] 17 0.070833333 166 0.6916667
## (225,250] 15 0.062500000 181 0.7541667
## (250,275] 15 0.062500000 196 0.8166667
## (275,300] 19 0.079166667 215 0.8958333
## (300,325]  7 0.029166667 222 0.9250000
## (325,350]  6 0.025000000 228 0.9500000
## (350,375]  7 0.029166667 235 0.9791667
## (375,400]  2 0.008333333 237 0.9875000
## (400,425]  3 0.012500000 240 1.0000000
ggplot(data=dati)+ geom_bar(aes(x=sales_cl), stat="count",
col="lightblue", fill="blue")+ labs(title="Distribuzione di Frequenze
delle Classi di Vendita", x="Classi di Vendita", y="Frequenza")+
theme_light()+ theme(axis.text.x = element_text(angle = 90, hjust = 1))

proporzioni <- distr_freq_sales$fi
somma_quadrati_proporzioni <- sum(proporzioni^2)
gini_index <- 1 - somma_quadrati_proporzioni
cat(sprintf("L'indice di eterogeneità di Gini è: %f\n", gini_index))
## L'indice di eterogeneità di Gini è: 0.898299

5 CALCOLO DELLE PROBABILILTA’

n_totale <- nrow(dati)

n_beaumont <- nrow(dati[dati$city == "Beaumont", ])

prob_beaumont <- n_beaumont / n_totale
cat(sprintf("La probabilità che una riga a caso riporti la città 'Beaumont' è: %f\n", prob_beaumont))
## La probabilità che una riga a caso riporti la città 'Beaumont' è: 0.250000
n_luglio <- nrow(dati[dati$month == 7, ])

prob_luglio <- n_luglio / n_totale
cat(sprintf("La probabilità che una riga a caso riporti il mese di Luglio è: %f\n", prob_luglio))
## La probabilità che una riga a caso riporti il mese di Luglio è: 0.083333
n_dicembre_2012 <- nrow(dati[(dati$month == 12 & dati$year == 2012), ])

prob_dicembre_2012 <- n_dicembre_2012 / n_totale
cat(sprintf("La probabilità che una riga a caso riporti il mese di Dicembre 2012 è: %f\n", prob_dicembre_2012))
## La probabilità che una riga a caso riporti il mese di Dicembre 2012 è: 0.016667

6 CREAZIONE DI NUOVE VARIABILI

dati <- dati %>%
  mutate(prezzo_medio_stimato = (volume * 1000000) / sales)

ggplot(dati, aes(x = city, y = prezzo_medio_stimato)) +
  geom_boxplot(fill = "maroon2", color = "black", outlier.shape = 1, outlier.size = 2) +
  labs(
    title = "Distribuzione Prezzo Medio in dollari per Città",
    x = "Città",
    y = "Prezzo Medio Stimato"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

dati <- dati %>%
  mutate(efficacia_annunci = sales / listings)

ggplot(dati, aes(x = city, y = efficacia_annunci)) +
  geom_boxplot(fill = "lawngreen", color = "snow4", outlier.shape = 1, outlier.size = 2) +
  labs(
    title = "Distribuzione dell'Efficacia degli Annunci per Città",
    x = "Città",
    y = "Efficacia Annunci (Vendite / Annunci)"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

7 ANALISI CONDIZIONATA

summary_city_sales <- dati %>%
  group_by(city) %>%
  summarise(
    media_sales = mean(sales, na.rm = TRUE),
    sd_sales = sd(sales, na.rm = TRUE),
    n_obs = n()
  )

print("Summary di 'sales' per città:")
## [1] "Summary di 'sales' per città:"
print(summary_city_sales)
## # A tibble: 4 × 4
##   city                  media_sales sd_sales n_obs
##   <chr>                       <dbl>    <dbl> <int>
## 1 Beaumont                     177.     41.5    60
## 2 Bryan-College Station        206.     85.0    60
## 3 Tyler                        270.     62.0    60
## 4 Wichita Falls                116.     22.2    60

8 CREAZIONE DI VISUALIZZAZIONE CON GGPLOT2 (e grafici personalizzati)

ggplot(dati, aes(x = month, y = sales, fill = city)) +
  geom_boxplot() +
  facet_wrap(~ as.factor(year)) +
  labs(title = "Vendite per Media Mesile, per Anno (suddiviso per Città)",
       x = "Mese",
       y = "Vendite",
       fill = "Città") +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))

media_mensile_citta_anno <- dati %>%
  group_by(city, year = as.factor(year), month) %>%
  summarise(media_vendite = mean(sales, na.rm = TRUE)) %>%
  ungroup()
## `summarise()` has grouped output by 'city', 'year'. You can override using the
## `.groups` argument.
media_mensile_citta_anno$month <- factor(media_mensile_citta_anno$month, levels = month.name)

media_mensile_totale <- media_mensile_citta_anno %>%
  group_by(city, month) %>%
  summarise(media_vendite_mensile = mean(media_vendite, na.rm = TRUE))
## `summarise()` has grouped output by 'city'. You can override using the
## `.groups` argument.
ggplot(media_mensile_citta_anno, aes(x = year, y = media_vendite, fill = year)) +
  geom_bar(stat = "identity", position = position_dodge(width = 0.9)) +
  geom_text(
    stat = "summary",
    fun = "mean",
    aes(label = format(round(..y.., 0), nsmall = 0), group = month), # Usa ..y.. per la media e raggruppa per mese
    position = position_nudge(x = 0, y = 0.5), # Regola la posizione verticale
    vjust = 0,
    hjust = 0.5,
    size = 3
  ) +
  facet_wrap(~ city) +
  labs(title = "Media Mensile su Anno delle Vendite per Città",
       x = "",
       y = "Media Mensile Vendite",
       fill = "Anno") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        strip.background = element_rect(fill = "lightgray"),
        strip.text = element_text(face = "bold"))
## Warning: The dot-dot notation (`..y..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(y)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

dati_tyler <- dati %>%
  filter(city == "Tyler")

dati_tyler <- dati_tyler %>%
  mutate(month_year = interaction(month, year_factor))

all_levels_tyler <- levels(dati_tyler$month_year)

selected_levels_tyler <- all_levels_tyler[seq(1, length(all_levels_tyler), by = 3)]

ggplot(dati_tyler, aes(x = month_year, group = 1)) +
  geom_line(aes(y = listings, color = "Disponibilità Immobili"), linewidth = 0.8) +
  geom_point(aes(y = listings, color = "Disponibilità Immobili", shape = "Disponibilità Immobili"), size = 2) +
  geom_line(aes(y = sales, color = "Vendite Mensili"), linewidth = 0.8, alpha = 0.7) +
  geom_point(aes(y = sales, color = "Vendite Mensili", shape = "Vendite Mensili"), size = 2, alpha = 0.7) +
  scale_x_discrete(labels = function(x) gsub("\\.(.*)", "-\\1", x),
                   breaks = selected_levels_tyler) +
  scale_y_continuous(
    name = "Disponibilità Immobili",
    sec.axis = sec_axis(~ ., name = "Vendite Mensili")
  ) +
  scale_color_manual(name = "",
                     values = c("Disponibilità Immobili" = "black", "Vendite Mensili" = "blue")) +
  scale_shape_manual(name = "",
                     values = c("Disponibilità Immobili" = 16, "Vendite Mensili" = 1)) +
  labs(
    title = "Disponibilità Immobili e Vendite nel Tempo (Città di Tyler)",
    x = "Mese - Anno"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 8),
        axis.title.y.right = element_text(color = "blue"),
        axis.text.y.right = element_text(color = "blue"),
        legend.position = "right",
        legend.title = element_blank())

dati_bryan <- dati %>%
  filter(city == "Bryan-College Station")

dati_bryan <- dati_bryan %>%
  mutate(month_year = interaction(month, year_factor))

all_levels_bryan <- levels(dati_bryan$month_year)
selected_levels_bryan <- all_levels_bryan[seq(1, length(all_levels_bryan), by = 3)]

ggplot(dati_bryan, aes(x = month_year, group = 1)) +
  geom_line(aes(y = listings, color = "Disponibilità Immobili"), linewidth = 0.8) +
  geom_point(aes(y = listings, color = "Disponibilità Immobili", shape = "Disponibilità Immobili"), size = 2) +
  geom_line(aes(y = sales, color = "Vendite Mensili"), linewidth = 0.8, alpha = 0.7) +
  geom_point(aes(y = sales, color = "Vendite Mensili", shape = "Vendite Mensili"), size = 2, alpha = 0.7) +
  scale_x_discrete(labels = function(x) gsub("\\.(.*)", "-\\1", x),
                   breaks = selected_levels_tyler) +
  scale_y_continuous(
    name = "Disponibilità Immobili",
    sec.axis = sec_axis(~ ., name = "Vendite Mensili")
  ) +
  scale_color_manual(name = "",
                     values = c("Disponibilità Immobili" = "black", "Vendite Mensili" = "blue")) +
  scale_shape_manual(name = "",
                     values = c("Disponibilità Immobili" = 16, "Vendite Mensili" = 1)) +
  labs(
    title = "Disponibilità Immobili e Vendite nel Tempo (Città di Bryan)",
    x = "Mese - Anno"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 8),
        axis.title.y.right = element_text(color = "blue"),
        axis.text.y.right = element_text(color = "blue"),
        legend.position = "right",
        legend.title = element_blank())

ggplot(dati, aes(x = city, y = median_price)) +
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(
    title = "Distribuzione del Prezzo Mediano delle Case per Città",
    x = "Città",
    y = "Prezzo Mediano"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# distribuzione valore Totale vendite per città
ggplot(dati, aes(x = city, y = volume)) +
  geom_boxplot(fill = "lightgreen", color = "black") +
  facet_wrap(~ year_factor) +
  labs(
    title = "Distribuzione del Valore Totale delle Vendite per Città, per Anno",
    x = "Città",
    y = "Valore Totale delle Vendite (Milioni $)"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Confronto totale delle vendite per mese per Città
totale_vendite_mensile_citta <- dati %>%
  group_by(city, month) %>%
  summarise(totale_sales = sum(sales, na.rm = TRUE))
## `summarise()` has grouped output by 'city'. You can override using the
## `.groups` argument.
ggplot(totale_vendite_mensile_citta, aes(x = month, y = totale_sales, fill = city)) +
  geom_bar(stat = "identity") +
  labs(
    title = "Totale delle Vendite per Mese, per Città",
    x = "Mese",
    y = "Totale Vendite",
    fill = "Città"
  ) +
  scale_x_continuous(breaks= seq(1,12,1))+
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Confronto totale delle vendite per mese per Città normalizzato
  totale_vendite_mensile_citta_percentuale <- dati %>%
    group_by(city, month) %>%
    summarise(totale_sales = sum(sales, na.rm = TRUE)) %>%
    group_by(month) %>%
    mutate(percentuale_citta = totale_sales / sum(totale_sales) * 100)
## `summarise()` has grouped output by 'city'. You can override using the
## `.groups` argument.
  ggplot(totale_vendite_mensile_citta_percentuale, aes(x = month, y = percentuale_citta, fill = city)) +
    geom_bar(stat = "identity", position = "fill") +
    labs(
      title = "Percentuale del Totale delle Vendite per Mese, per Città",
      x = "Mese",
      y = "Percentuale del Totale Vendite",
      fill = "Città"
    ) +
    scale_x_continuous(breaks= seq(1,12,1))+
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

  totale_vendite_mensile_citta_anno_percentuale <- dati %>%
    group_by(city, month, year_factor) %>%
    summarise(totale_sales = sum(sales, na.rm = TRUE)) %>%
    group_by(month, year_factor) %>%
    mutate(percentuale_citta = totale_sales / sum(totale_sales) * 100)
## `summarise()` has grouped output by 'city', 'month'. You can override using the
## `.groups` argument.
  ggplot(totale_vendite_mensile_citta_anno_percentuale, aes(x = month, y = percentuale_citta, fill = city)) +
    geom_bar(stat = "identity", position = "fill") +
    facet_wrap(~ year_factor) +
    labs(
      title = "Percentuale del Totale delle Vendite per Mese, per Città (vs Anno)",
      x = "Mese",
      y = "Percentuale del Totale Vendite",
      fill = "Città",
      caption = "Pannelli divisi per Anno"
    ) +
    scale_x_continuous(breaks = seq(1,12,1))+
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1),
          strip.background = element_rect(fill = "lightgray"),
          strip.text = element_text(face = "bold"))

# Confronto tra città e periodi storici (mese - anno - cronologico) 
    dati <- dati %>%
  mutate(year_month = interaction(month_factor, year_factor, sep = "-"))

media_mensile_citta <- dati %>%
  group_by(city, year_month) %>%
  summarise(media_vendite = mean(sales, na.rm = TRUE), .groups = 'drop')

# Ottieni i livelli unici di year_month (già nel formato desiderato)
all_levels <- levels(media_mensile_citta$year_month)

# Seleziona 1 etichetta ogni 3
selected_levels <- all_levels[seq(1, length(all_levels), by = 3)]

ggplot(media_mensile_citta, aes(x = year_month, y = media_vendite, color = city, group = city)) +
  geom_line() +
  geom_point() +
  scale_x_discrete(breaks = selected_levels) +
  labs(
    title = "Media Mensile delle Vendite per Città nel Tempo",
    x = "Mese-Anno",
    y = "Media Vendite",
    color = "Città"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 8))

# inserimento media mobile su tre mesi (armonizzato)
media_mensile_citta_smoothed <- dati %>%
  group_by(city, year_month) %>%
  summarise(media_vendite = mean(sales, na.rm = TRUE)) %>%
  group_by(city) %>%
  mutate(media_vendite_smoothed = rollmean(media_vendite, k = 3, align = "center", fill = NA))
## `summarise()` has grouped output by 'city'. You can override using the
## `.groups` argument.
ggplot(media_mensile_citta_smoothed, aes(x = year_month, y = media_vendite_smoothed, color = city, group = city)) +
  geom_line() +
  geom_point() +
  scale_x_discrete(breaks = selected_levels) +
  labs(
    title = "Media Mensile delle Vendite (Armonizzata su 3 mesi) per Città nel Tempo",
    x = "Anno-Mese",
    y = "Media Vendite (Media Mobile su 3 Mesi)",
    color = "Città"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
## Warning: Removed 8 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 8 rows containing missing values or values outside the scale range
## (`geom_point()`).

9 CONCLUSIONI