-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgetto Markdown.Rmd
2384 lines (1493 loc) · 88.1 KB
/
Progetto Markdown.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---
title: "Progetto Markdown"
runtime: shiny
output:
html_document:
theme: readable
code_folding: hide
number_sections: true
toc: yes
includes:
in_header: header.Rhtml
after_body: footer.Rhtml
bibliography: biblio.bib
link-citations: yes
---
<style>
body .main-container {
max-width: 1650px;
}
</style>
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
load(".RData")
# Librerie
#####
library(plyr)
library(tidyverse)
library(ggmap)
library(sp)
library(sf)
library(tmap)
library(tmaptools)
library(leaflet)
library(RColorBrewer)
library(shinyjs)
library(spdep)
library(dplyr)
library(shiny)
library(shinydashboard)
library(DT)
library(ggplot2)
library(plotly)
library(GGally)
library(magrittr)
```
# Introduzione
Il divario economico tra Nord e Sud Italia è fin dal 1861 un problema sociale ma soprattutto economico che si ripercuote sulla qualità della vita di milioni di persone. Secondo i dati dell'ISTAT il Mezzogiorno presenta un ampio divario di crescita rispetto al Nord. Nel corso degli anni molti studi hanno provato a identificare le cause di questo divario, che rimangono tutt'oggi difficili da individuare con precisione. Ciò che possiamo sicuramente asserire è che una delle cause di questo divario è l'assenza, al Sud, di un tessuto industriale strutturato e di conseguenza il mercato del lavoro è profondamente diverso da quello del resto d'Italia, condannando i giovani, in particolare i meridionali, ad un futuro incerto e precario dal punto di vista lavorativo.
Questo lavoro si pone l’obiettivo di studiare la distribuzione spaziale delle varie tipologie di reddito sul territorio italiano; in particolare verranno utilizzati metodi propri dell’analisi spaziale al fine di valutare se ci sono zone dello stivale in cui le variabili osservate presentano autocorrelazione spaziale o meno.
Lo studio procederà per gradi. In primis verranno analizzati i dati dal punto di vista descrittivo per identificare le proprietà statistiche delle variabili considerate e quindi procedere ad una trattazione efficace. Successivamente verranno trattate le basi teoriche dell'analisi spaziale descrivendo minuziosamente il framework utilizzato per l'analisi.
# Data Exploration
## Data Wrangling
I dati sui redditi per comune sono quelli forniti dall’ISTAT relativi all’anno 2016. Il problema principale da affrontare nella prima fase del lavoro è stato quello di valutare la qualità e la coerenza dei dati forniti dall’ Istituto. In particolare nel dataset oggetto di studio erano presenti comuni conteggiati più volte. Una volta individuati questi comuni è stato possibile rimuovere i doppioni e procedere alla fase seguente.
Per ogni tipologia di reddito rilevata erano presenti due variabili, cioè la frequenza delle osservazioni e l’ammontare totale rilevato; al fine di rendere più semplice la trattazione è stata calcolata una media per ogni comune dividendo l’ammontare totale per la rispettiva frequenza per ogni tipologia di reddito. Dopo queste operazioni preliminari il dataset si presenta come segue:
<br><br>
```{r}
shinyApp(
ui <- fluidPage(
#sidebar panel serve a inserire le scelte dell'utente
DTOutput("table", width = "100%"),
fluidRow(
column(6,
selectInput(inputId = "red7",
label = "Choose a variable to display",
choices = etichette,
selected = "Red. pens.") ),
column(6,
selectInput(inputId = "red8",
label = "Choose a variable to display",
choices = etichette,
selected = "")),
mainPanel ( column(6,
plotlyOutput("scatter",width = "100%")),
column(5,
plotlyOutput("barplot", width = "100%"),offset = 1), width= 12)
)),
server <- function(input,output) {
output$table <- DT::renderDataTable({
a <- red.fin %>% mutate_if(is.numeric, ~round(.,3))
datatable(a[,-4], filter = "top", options = list(scrollX = TRUE, target = "column") )
})
output$scatter <- renderPlotly({
a <- red.fin %>% mutate_if(is.numeric, ~round(.,3))
s1 = input$table_rows_current
s2 = input$table_rows_all
xx <- c("Denominazione.Comune",input$red7,input$red8)
aa <- as.data.frame(a[s2,xx])
# par(mar = c(4, 4, 1, .1))
b <- ggplot(aa, aes_string(x = aa[,2] ,y=aa[,3], comune = aa[,1] )) +
geom_point()+labs(x=input$red7,y=input$red8)
ggplotly(b, tooltip = c("x","y","comune"))
})
output$barplot <- renderPlotly({
a <- red.fin %>% mutate_if(is.numeric, ~round(.,3))
s1 = input$table_rows_current
s2 = input$table_rows_all
##
##
x <- c("Denominazione.Comune",input$red8,"macro")
a <- as.data.frame(a[s2,x])
#par(mar = c(4, 4, 1, .1))
c<- ggplot(a, aes_string(x=a[,input$red8], fill = "macro" )) +
geom_histogram(binwidth = 190)+ ylab("count") +
xlab(input$red8) + xlim(c(min(a[,2], na.rm = TRUE),quantile(a[,2],na.rm=TRUE)[4]))
ggplotly(c, tooltip = c("x","count","fill"))
#ggplotly(c, tooltip = c(x,"macro"))
})
} ,
options = list(height = 1100)
)
```
<br><br>
## Descriptive statistics
Una volta che il dataset è stato corretto e sintetizzato nel modo sopra descritto diventa possibile calcolare tutte le statistiche descrittive necessarie per analizzare quantitativamente le variabili di interesse.
La prima tipologia di grafico presente nell'app è un circle plot. Quest' ultimo è molto simile ad un bar plot con la differenza che la visualizzazione non è orizzontale o verticale, bensì circolare. Ogni barra rappresenta il valor medio del reddito selezionato per ogni regione italiana. E' possibile poi notare come le barre siano raggruppate secondo macro aree (nord,sud,centro).
Il grafico presenta anche dei livelli contrassegnati da archi di circonferenza che permettono, per grandi linee, un confronto tra le aree anche di natura quantitativa.
E' evidente come le regioni del nord Italia siano di frequente quelle che presentano valori medi più elevati rispetto a quelli delle altre macro regioni.
La seconda tipologia di grafico è un violin plot. Questo serve ad evidenziare in particolare la densità delle osservazioni. A differenza del box-plot, il violin plot non riporta esplicitamente le classiche statistiche quali quantili e media, ma mostra la densità di osservazioni per ogni livello della variabile osservata.
Abbiamo scelto questa tipologia di rappresentazione poichè ci permette di confrontare la densità di osservazioni tra macro aree per ogni tipologia di reddito.
E' possibile notare come, ad esempio, per i redditi da fabbricati la densità nelle regioni del sud è più elevata per valori minori rispetto alla densità delle altre macro aree. Data la presenza di numerosi outlier, l'app shiny permette di escludere i valori estremi cliccando ripetutamente sul pulsante "Run Code".
La terza tipologia di grafico è un correlogramma. E' possibile anche in questo caso scegliere quali tipologie di reddito includere nell'analisi.
Passando ad analizzare i risultati ottenuti notiamo subito che sulla diagonale dell'output vengono rappresentate le densità per i vari redditi, divise secondo l'appartenenza alla rispettiva macro regione, come visto in precedenza per le altre tipologie di grafici.
Nella parte inferiore rispetto alla diagonale, invece, sono presenti vari scatterplot. Ogni scatterplot si riferisce alla coppia di redditi indicata nelle corrispondenti etichette presenti sulle righe e sulle colonne.
Infine nella parte superiore troviamo le correlazioni (Pearson) tra le coppie di redditi considerati. La prima correlazione indicata è quella che non tiene conto delle differenze tra macro aree, bensì le considera congiuntamente. Gli asterischi indicano il livello di significatività del risultato ottenuto, calcolato secondo il classico test per la correlazione, cioè quello che utilizza la distribuzione t di Student con (n-2) gradi di libertà.
Inoltre la correlazione viene calcolata anche dividendo le osservazioni in macro aree.
<br><br>
```{r}
shinyApp(
ui <- fluidPage(
sidebarLayout(
# Sidebar panel per input ----
sidebarPanel(
selectInput(inputId = "red2",
label = "Choose a variable for cir/viol plot",
choices = etichette[1:8],
selected = ""),
selectInput(inputId = "red33",
label = "Choose a variable for corr.",
choices = etichette[1:8],
selected = "Red. pens."),
selectInput(inputId = "red34",
label = "Choose a variable for corr.",
choices = etichette[1:8],
selected = "Red. lav. aut."),
selectInput(inputId = "red35",
label = "Choose a variable for corr.",
choices = etichette[1:8],
selected = "Red. imponibile"),
selectInput(inputId = "palette3",
label = "Choose color palette",
choices = list("Blues","BuGn",
"Greens","Greys",
"PuBuGn","Dark2"),
selected = "Greys"),
br(),
actionButton("Run2", "Run code")
),
mainPanel(
# Output: Tabset w/ plot, summary, and table ----
tabsetPanel(type = "tabs",
tabPanel("Circ. plot", plotOutput("cirplot", height = 600)),
tabPanel("Viol. plot", plotlyOutput("violinplot", height = 600)),
tabPanel("Corr.plot", plotOutput("corr", height= 600))
)
)
)
),
server = function(input,output) {
output$violinplot <- renderPlotly({
if(input$Run2 == 0)
return()
isolate({
xx <- input$red2
mean <- mean(red.fin[[xx]], na.rm = TRUE)
sd <- sd(red.fin[[xx]], na.rm = TRUE)
yy <- red.fin[etichette]
library(data.table)
outlierReplace = function(dataframe, cols, rows, newValue = NA) {
if (any(rows)) {
set(dataframe, rows, cols, newValue)
}
}
outlierReplace(yy, xx, which(yy[[xx]] > max(yy[[xx]], na.rm = TRUE)-3000))
yy$macro <- red.fin$macro
yy <- yy[-1,]
#yy[sapply(yy, is.null)] <- NA
y <- cbind(yy$macro,yy[xx])
names(y)[1] <- "macro"
p <- ggplot(y, aes(y=y[[xx]], x=y$macro, fill = y$macro)) +
geom_violin() +
theme(legend.title=element_text(face="bold")) + ylab(xx) +
xlab("Aree geografiche") + theme(legend.text = element_text( face = "bold")) +
scale_fill_brewer(palette=input$palette3)
p
# p <- ggplot(red.fin, aes(y=red.fin[[xx]], x=red.fin$macro, fill=red.fin$macro)) +
# geom_violin(trim = TRUE) +
# theme(legend.title=element_text(face="bold")) + xlab("Aree geografiche") +
# labs(fill="Aree geografiche") + theme(legend.text = element_text( face = "bold")) +
# scale_fill_brewer(palette=input$palette3)
p #+ scale_y_continuous(name = xx, limits = c(mean-3*sd,mean+3*sd))
})
})
output$cirplot <- renderPlot({
if(input$Run2 == 0)
return()
isolate({
data <- mean.reg[,c(2,24,3:9)]
et <- input$red2
# Matrice che raccoglie i dati in base al reddito scelto dall'utente
dat. <- data.frame(
individual = data$Regione,
group = data$macro,
value = data[et]
)
names(dat.) <- c("individual","group","value")
dat. = dat. %>% arrange(group,value)
# empty bar e' una barra vuota che aggiunge spazio tra ogni gruppo
#Creo dataframe vuoto con stessi nomi colonne di .dat
empty_bar <- 7
to_add <- data.frame( matrix(NA, empty_bar*nlevels(dat.$group), ncol(dat.)) )
colnames(to_add) <- colnames(dat.)
#Assegno valori a colonna
to_add$group <- rep(levels(dat.$group), each=empty_bar)
dat. <- rbind(dat., to_add)
dat. <- dat. %>% arrange(group)
dat.$id <- seq(1, nrow(dat.)) # Aggiungo altra colonna a .dat
# Ottieni nome e la posizione y di ogni etichetta
label_data <- dat.
number_of_bar <- nrow(label_data)
angle <- 90 - 360 * (label_data$id-0.5) /number_of_bar # I substract 0.5 because the letter must have the angle of the center of the bars. Not extreme right(1) or extreme left (0)
label_data$hjust <- ifelse(angle < -90, 1, 0)
label_data$angle <- ifelse(angle < -90, angle+180, angle)
# prepare a data frame for base lines
base_data <- dat. %>%
group_by(group) %>%
summarize(start=min(id), end=max(id) - empty_bar) %>%
rowwise() %>%
mutate(title=mean(c(start, end)))
# prepare a data frame for grid (scales)
grid_data <- base_data
grid_data$end <- grid_data$end[ c( nrow(grid_data), 1:nrow(grid_data)-1)] + 1
grid_data$start <- grid_data$start -1
grid_data <- grid_data[-1,]
mea <- mean(dat.$value, na.rm = TRUE)
sd <- sd(dat.$value, na.rm = TRUE)
lev <- c(mea-3*sd, mea-2.3*sd, mea-1.5*sd, mea+0.5*sd)
# Make the plot
p <- ggplot(dat., aes(x=as.factor(id), y=value, fill=group )) + # Note that id is a factor. If x is numeric, there is some space between the first bar
geom_bar(aes(x = as.factor(id), y = value, fill = group), stat = "identity", alpha = 0.7) +
geom_segment(data=grid_data, aes(x = end, y = lev[4], xend = start, yend = lev[4]), colour = "black", alpha=1, size=0.6 , inherit.aes = FALSE ) +
geom_segment(data=grid_data, aes(x = end, y = lev[3], xend = start, yend = lev[3]), colour = "black", alpha=1, size=0.6 , inherit.aes = FALSE ) +
geom_segment(data=grid_data, aes(x = end, y = lev[2], xend = start, yend = lev[2]), colour = "black", alpha=1, size=0.6 , inherit.aes = FALSE ) +
geom_segment(data=grid_data, aes(x = end, y = lev[1], xend = start, yend = lev[1]), colour = "black", alpha=1, size=0.6 , inherit.aes = FALSE ) +
annotate("text", x = rep(max(dat.$id),4), y = signif(lev,digits=6), label = as.character(signif(lev),digits=6) , color="black", size=4 , angle=0, fontface="bold", hjust=1) +
#geom_bar(aes(x=as.factor(id), y=value, fill=group), stat="identity", alpha=0.5) +
#ylim(-0.3*lev[1],lev[4]) +
theme_minimal() +
theme(
legend.position = "none",
axis.text = element_blank(),
axis.title = element_blank(),
panel.grid = element_blank(),
plot.margin = unit(rep(-1.5,4), "cm")
) +
coord_polar() +
geom_text(data=label_data, aes(x=id, y=value+10, label=individual, hjust=hjust),
color="black", fontface="bold",alpha=0.6, size=3, angle= label_data$angle, inherit.aes = FALSE ) +
geom_segment(data=base_data, aes(x = start, y = -5, xend = end, yend = -5), colour = "black", alpha=0.8, size=1.3 , inherit.aes = FALSE )
#geom_text(data=base_data, aes(x = title, y = -18, label=group), hjust=c(1,0,0), colour = "black", alpha=0.8, size=1.9, fontface="bold", inherit.aes = FALSE)
p
})
})
output$corr <- renderPlot({
if(input$Run2 == 0)
return()
isolate({
yy <- red.fin[etichette]
yy$macro<- red.fin$macro
x <- c(input$red2, input$red33, input$red34, input$red35,"macro")
xx <- yy[x]
y <- as.data.frame(xx)
d<- ggpairs(y,columns= 1:(ncol(y)-1),
ggplot2::aes(colour=macro, alpha=.3, width=.2 ),
upper = list(continuous = wrap("cor", method="spearman")))
d
})
})
} ,
options = list(height = 800)
)
```
# Spatial analysis
## Spatial Objects
Per procedere all’analisi spaziale vera e propria bisogna definire un framework per posizionare nello spazio le unità amministrative oggetto dell’analisi. Al fine di definire nel modo più accurato possibile le unità spaziali dei comuni e delle varie regioni amministrative italiane sono stati utilizzati gli shapefile presenti sul sito [ISTAT](https://www.istat.it/it/archivio/222527) con riguardo a quelli dell’anno 2016, che corrisponde all’anno di censimento del dataset.
Queste strutture dati sono in formato WGS84, facilmente caricabili in R grazie alla funzione readOGR presente nel pacchetto rgdal.
In questo modo abbiamo ottenuto i poligoni di regioni, province e comuni italiani. Qui un piccolo esempio.
<br><br>
```{r image_grobs, fig.show="hold", fig.align="default", out.width="50%"}
plot(OGR.reg, col = "gray", border = "blue") # Disegna shapefile vuoto
plot(OGR.prov, col = "gray", border = "blue") # Disegna shapefile vuoto
```
<br>
Nel caso sopra riportato i poligoni rappresentano la forma e la superficie di regioni e province italiane. Utilizzando la stessa procedura e i dati forniti dall’ISTAT sono stati importati in R anche gli shapefile per i comuni.
Una volta importati gli shapefile per comuni, province e regioni è stato possibile inserire i dati utilizzando la funzione merge di R prendendo come riferimento la denominazione delle unità amministrative. In questo modo l’oggetto SpatialPolygonsDataFrame (S4 class) conterrà sia le informazioni spaziali sia i dati sui redditi per ogni poligono considerato. E’ necessario precisare, infine, che nel caso di regioni e province i dati comunali necessitavano necessariamente di un raggruppamento. Il valore del reddito per provincia (regione) sarà quindi uguale alla media del reddito dei comuni presenti nella provincia (regione).
Nell'app seguente è possibile osservare i dati per provincia (leaflet global) e quelli per comune (leaflet local) attraverso una mappa interattiva. Per quanto riguarda la visualizzazione dei comuni, è possibile scegliere quale macro regione italiana visualizzare, questo poichè il caricamento dei comuni su tutto il territorio nazionale sarebbe stato computazionalmente oneroso e avrebbe richiesto molto tempo per il rendering. E' stata però aggiunta una casella denominata "All" da selezionare qualora si sia interessati al grafico complessivo dei comuni italiani.
<br><br>
```{r}
shinyApp(
ui <- dashboardPage(
dashboardHeader(title = "Leaflet map"),
dashboardSidebar(
sidebarMenu(
menuItem("Leaflet map", tabName = "leaflethome", icon = icon("dashboard"),
menuSubItem("Leaflet global", tabName = "leafletglobal", icon = icon("dashboard")), #4
menuSubItem("Leaflet local", tabName = "leafletlocal", icon = icon("dashboard")) #9
))),
dashboardBody(
tabItems(
tabItem(tabName = "leafletglobal",
#####
fluidPage(
#sidebar panel serve a inserire le scelte dell'utente
fluidRow(
column(3,
selectInput(inputId = "red4",
label = "Choose a variable to display",
choices = etichette,
selected = "")),
column(3,
numericInput(inputId = "g.col1",
label = ("Choose n colors"),
value = "5")),
column(3,
selectInput(inputId = "palette4",
label = "Choose color palette",
choices = list("Blues","BuGn",
"Greens","Greys",
"PuBuGn","Dark2"),
selected = "Greys")),
column(3,actionButton("Run4", "Run code")),
leafletOutput("qtm", width = "100%", height = 800),
))),
#####
tabItem(tabName = "leafletlocal",
#####
fluidPage(
#sidebar panel serve a inserire le scelte dell'utente
fluidRow(
column(2,
selectInput(inputId = "shape1",
label = "Choose a macro to display",
choices = list("Nord",
"Centro",
"Sud"),
selected = "Nord")),
column(2,
selectInput(inputId = "red9",
label = "Choose a variable to display",
choices = etichette,
selected = "")),
column(2,
numericInput(inputId = "g.col2",
label = ("Choose n colors"),
value = "5")),
column(2,
selectInput(inputId = "palette9",
label = "Choose color palette",
choices = list("Blues","BuGn",
"Greens","Greys",
"PuBuGn","Dark2"),
selected = "Greys")),
column(2,
checkboxInput("all1","All")),
column(2,
actionButton("Run9", "Run code")),
leafletOutput("qtm.local", width = "100%", height = 800),
)))))),
#####
server <- function(input,output) {
output$qtm <- renderLeaflet({
if(input$Run4 == 0)
return()
isolate({
x <- input$g.col1
y <- input$red4
tm <- tm_shape(OGR.prov) + tm_fill(input$red4, palette = input$palette4, style = "quantile",
n = x , contrast = c(0.28, 0.87),
id = "DEN_PCM") +
tm_borders(alpha=.7) + tm_legend(legend.position = c("left", "bottom")) +
tm_layout(title = paste(y,"medio per provincia"),
title.size = 1.1) +
tm_shape(OGR.reg) + tm_borders(col = "black")
tmap_mode("view")
tmap_leaflet(tm)
}) })
output$qtm.local <- renderLeaflet({
if(input$Run9 == 0)
return()
isolate({
x <- input$g.col2
y <- input$red9
if(input$shape1 == "Nord" && input$all1==FALSE){
tm <- tm_shape(OGR.com.nord) + tm_fill(input$red9, palette = input$palette9, style = "quantile",
n = input$g.col2, contrast = c(0.28, 0.87),
id = "COMUNE") +
tm_borders(alpha=.7) + tm_legend(legend.position = c("left", "bottom")) +
tm_layout(title = paste(y,"medio per comune"),
title.size = 1.1) +
tm_shape(OGR.reg) + tm_borders(col = "black")
}
if(input$shape1 == "Centro" && input$all1==FALSE){
tm <- tm_shape(OGR.com.centro) + tm_fill(input$red9, palette = input$palette9, style = "quantile",
n = input$g.col2, contrast = c(0.28, 0.87),
id = "COMUNE") +
tm_borders(alpha=.7) + tm_legend(legend.position = c("left", "bottom")) +
tm_layout(title = paste(y,"medio per comune"),
title.size = 1.1) +
tm_shape(OGR.reg) + tm_borders(col = "black")
}
if(input$shape1 == "Sud" && input$all1==FALSE){
tm <- tm_shape(OGR.com.sud) + tm_fill(input$red9, palette = input$palette9, style = "quantile",
n = input$g.col2, contrast = c(0.28, 0.87),
id = "COMUNE") +
tm_borders(alpha=.7) + tm_legend(legend.position = c("left", "bottom")) +
tm_layout(title = paste(y,"medio per comune"),
title.size = 1.1) +
tm_shape(OGR.reg) + tm_borders(col = "black")
}
if(input$all1==TRUE){
tm <- tm_shape(OGR.com) + tm_fill(input$red9, palette = input$palette9, style = "quantile",
n = input$g.col2, contrast = c(0.28, 0.87),
id = "COMUNE") +
tm_borders(alpha=.7) + tm_legend(legend.position = c("left", "bottom")) +
tm_layout(title = paste(y,"medio per comune"),
title.size = 1.1) +
tm_shape(OGR.reg) + tm_borders(col = "black")
}
tmap_mode("view")
tmap_leaflet(tm)
}) }) }
,options = list(height = 1000))
```
<br><br>
## Spatial autocorrelation
Per autocorrelazione spaziale si intende quel fenomeno per cui nell’analisi spaziale di un dataset i valori di una certa variabile osservata saranno simili in località contigue o vicine e diversi per località lontane tra loro. Questa caratteristica di una variabile che è autocorrelata viene comunemente associata alla disciplina dei processi stocastici, cioè processi che si evolvono nel tempo. In questo caso l’autocorrelazione è definita spaziale poiché ha effetto sullo “spazio” invece che sul tempo.
Oltretutto la prima legge della geografia, (Tobler 1970) dice che:
***
> "Ogni cosa è correlata a qualsiasi altra, ma le cose vicine sono più relazionate di quelle lontane"
<br>
L’autocorrelazione sarà quindi predominante quanto più la distanza si accorcia.
Un’implicazione dell’autocorrelazione è il fatto che i dati spaziali non sono indipendenti, per questo si aprono ampi margini di studio riguardo la distribuzione spaziale dei dati. Lo sviluppo di strumenti analitici ha permesso di avere basi obiettive solide per decidere se in una determinata area geografica è presente un’ autocorrelazione significativamente valida.
La domanda che ci poniamo è quindi se il pattern oggetto di studio è frutto del caso o se ci sono influenze spaziali che hanno giocato un ruolo nella distribuzione della variabile.
I test per la presenza di autocorrelazione sono la base di partenza per la costruzione di modelli spaziali complessi, poiché senza questi rischieremmo di costruire modelli per poi scoprire che le strutture su cui questi modelli si basano sono del tutto insignificanti.
E’ bene ricordare che l’autocorrelazione spaziale è stata sviluppata prendendo come riferimento dei punti collocati nello spazio. Nel caso dello shape file utilizzato in questo lavoro, le aree studiate (regioni,province,comuni) sono dei poligoni complessi ma la sostanza non cambia poiché l’analisi è estendibile ad oggetti più complessi dei punti, con le dovute accortenze.
### Struttura spaziale
Il primo passo in questo tipo di analisi è definire un metodo che ci permetta di incorporare la prossimità spaziale in una misura di autocorrelazione; a tal fine bisognerà catturare la relazione spaziale di ogni località con le altre e per fare ciò utilizzeremo una matrice di pesi spaziale $\textbf{W}$.
Nella prima riga di questa matrice troviamo l’informazione riguardante la prima località rispetto a tutte le altre. Formalmente ogni elemento della matrice $\textbf{W}$, definito come $w_{ij}$ rappresenterà la relazione tra la località $i$ e la località $j$. Pertanto avremo:
$$
\begin{bmatrix}
w_{11} & w_{12} & ... & w_{1n} \\
w_{21} & w_{22} & . & :\\
: & . & . & :\\
w_{n1} & ... & ... & w_{nn} \\
\end{bmatrix}
$$
Ogni valore della matrice è dipendente dalla relazione spaziale che lega le due località $i$ e $j$ e quest'ultima da come scegliamo di definire questa relazione.
Considerato il framework bisogna assegnare un valore alle variabili $w_{ij}$.
L’approccio più semplice è quello dell’adiacenza. Sebbene questo approccio sembri semplice ne esistono alcune varianti. Ad esempio potremmo considerare due poligoni come adiacenti se hanno un confine in comune (Rook’s case), o potremmo considerare sufficiente il fatto che i due poligoni condividano anche un solo vertice (Queen’s case).
Un altro approccio potrebbe essere quello di ignorare i confini dei poligoni e utilizzare una misura basata sulla distanza tra i poligoni. Basandoci su questo criterio, dopo aver costruito la matrice delle distanze tra i poligoni, possiamo definire una quantità arbitraria $d$ e di conseguenza considerare collegati solo i poligoni le cui distanze sono minori del valore $d$. Sarà quindi ovvio che per determinati livelli del parametro $d$, la nostra matrice assumerà valori differenti. Più sarà alto questo valore, più il poligono i-esimo avrà collegamenti anche con poligoni più distanti. E' chiaro che questo metodo differisce da quelli esposti in precedenza, poichè non si limita a considerare solo l'adiacenza quale criterio per la costruzione della matrice $\textbf{W}$.
Sulla base della matrice delle distanze tra poligoni è possibile costruire un ulteriore metodo per definire l'esistenza o meno di relazioni tra unità spaziali.
Il metodo è quello del nearest neighbour. In particolare, fissato un livello $k$, questo metodo considera collegati al generico poligono i-esimo, i primi k poligoni che hanno minor distanza dall'unità spaziale di riferimento.
E' bene precisare che tutti questi metodi per definire la struttura di relazione tra le unità spaziali vengono implementati in R attraverso il pacchetto spdep.
Le funzioni presenti in questo pacchetto danno come output una lista strutturata in modo da tener conto dell'esistenza o meno di rapporti spaziali.
Per giungere alla matrice $\textbf{W}$, cioè a quella necessaria per procedere nell'analisi, bisogna passare la suddetta lista ad un' altra funzione presente nel pacchetto spdep, cioè nb2mat().
La funzione nb2mat permette di costruire la matrice $\textbf{W}$ secondo vari criteri. Quello scelto nel corso di questa analisi è il criterio binario.
Secondo questo criterio, le unità spaziali considerate collegate, secondo i criteri esposti in precedenza, verranno contrassegnate da un 1, mentre quelle non collegate da uno 0.
Potremmo correttamente supporre, quindi, che la struttura della matrice $\textbf{W}$ descrive pienamente l'informazione sulla struttura spaziale. In letteratura molti studi sono stati proposti per descrivere le proprietà di questa matrice, in particolare [@10.2307/621721] ha analizzato autovalori e autovettori di questa matrice identificando in questi ultimi l'informazione sulla struttura spaziale dei dati. In particolelare gli autovalori della matrice forniscono una misura globale del livello di interconnessione del network, mentre gli autovettori indicano la centralità delle località rispetto all'intero sistema.
Una considerazione importante da fare prima di procedere oltre riguarda la simmetria della matrice $\textbf{W}$. Saremmo portati a pensare che la matrice debba necessariamente essere simmetrica, e in linea di principio è così. Purtroppo alcuni dei metodi sopra esposti, in particolare quello della distanza e il nearest neighbour non garantiscono la simmetria. Possiamo forzare la matrice ad essere simmetrica mediante questa trasformazione:
$$
\begin{equation}
\textbf{W}_{final} = (1/2)(\textbf{W} + \textbf{W}^{T})
\end{equation}
$$
Infine è necessario precisare che la definizione della matrice dei pesi è un passo fondamentale dell'analisi poichè le ipotesi che vengono fatte nel costruire questa matrice compongono il sistema di ipotesi del fenomeno studiato. E' infatti chiaro che qualora la matrice spaziale non rappresenti con fedeltà il sistema studiato i risultati dell'analisi potrebbero essere poco corretti.
```{r}
shinyApp(
ui <- fluidPage(
sidebarLayout(
# Sidebar panel per input ----
sidebarPanel(
selectInput(inputId = "shape10",
label = "Choose a macro to display",
choices = list("Nord",
"Centro",
"Sud"),
selected = "Nord"),
numericInput(inputId = "k",
label = "N. of neighbour",
value = 2,
min=2,
max=6),
selectInput(inputId = "method",
label = "Choose a method",
choices = list("Queen", "Distance","Nearest"),
selected = "Queen"),
sliderInput(inputId = "distance",
label = "Choose distance",
value = 1,
min = 1.5,
max = 5,
step = 0.5),
br(),
actionButton("Run22", "Run code")
),
mainPanel(
# Output: Tabset w/ plot, summary, and table ----
plotOutput("adj", width = "100%", height = 600)
)
)
),
server = function(input,output) {
output$adj <- renderPlot({
if(input$Run22 == 0)
return()
isolate({
OGR.prov.sub <- OGR.prov[OGR.prov@data$macro == input$shape10,]
OGR.prov.sub@data$seq <- seq(1:length(OGR.prov.sub))
xy.sub <- coordinates(OGR.prov.sub)
### Adicenze
#Metodo semplice QUEEN
if(input$method == "Queen"){
wr.sub <- poly2nb(OGR.prov.sub, row.names = OGR.prov.sub$seq, queen = TRUE )
}
if(input$method == "Nearest"){
wr.sub <- knn2nb(knearneigh(xy.sub,k=input$k, RANN=FALSE),row.names = OGR.prov.sub$seq)
}
#Metodo distance based
if (input$method == "Distance"){
#dsts.sub <- unlist(nbdists(wr.sub,xy.sub))
wr.sub <- dnearneigh(xy.sub, d1 = 0, d2 = input$distance * max(dsts.com),
row.names = OGR.prov.sub@data$seq)
}
## Plot adiacenze
plot(OGR.prov.sub, col="gray", border="blue") # Disegna shapefile vuoto
plot(wr.sub, xy.sub, col="red", lwd="0.5", add=TRUE) #Disegna su shapefile precedente sia centroidi che collegamenti
})
})
} ,
options = list(height = 650)
)
```
## Moran's Index
Una volta determinata la struttura spaziale possiamo procedere all'analisi dell'autocorrelazione spaziale. Nel corso del tempo sono stati sviluppati molteplici indici per valutare la presenza e la forza dell'autocorrelazione spaziale.
La misura più utilizzata è l’indice di Moran. @10.1093/biomet/37.1-2.17 Il modo più semplice per presentare la misura è di immergersi direttamente nella sua formulazione analitica e valutarne ogni componente.
L’I di Moran è calcolato come segue:
$$
\begin{equation}
\textbf{I} = \Bigg[
\frac{n}{\sum_{i=1}^{n} {(y_{i}-\bar{y})}^2 }
\Bigg]
\Bigg[
\frac{\sum_{i=1}^{n}\sum_{j=1}^{n}w_{ij}(y_{i}-\bar{y})(y_{j}-\bar{y})}
{\sum_{i=1}^{n}\sum_{j=1}^{n} w_{ij}}
\Bigg]
\end{equation}
$$
La parte più importante del calcolo è la seconda frazione. Il numeratore di questa frazione è
$$
\begin{equation}
\sum_{i=1}^{n}\sum_{j=1}^{n}w_{ij}(y_{i}-\bar{y})(y_{j}-\bar{y})
\end{equation}
$$
che si dovrebbe riconoscere come un termine di covarianza. I pedici $i,j$ si riferiscono a diverse unità spaziali e $y$ è il valore dei dati in ciascuna unità spaziale. Calcolando il prodotto delle differenze dalla media complessiva $\bar{y}$, determiniamo la misura in cui esse covariano. Se gli scarti i-esimi e j-esimi dalla media hanno lo stesso segno, allora questo prodotto è positivo; se hanno segno opposto allora il prodotto è negativo e il valore del totale risultante dipenderà da quanto i valori sono vicini alla media complessiva.
I termini di covarianza sono moltiplicati per $w_{ij}$, cioè il corrispondente elemento della matrice dei pesi spaziali $\textbf{W}$. In questo modo gli elementi di covarianza sono ponderati in base alla loro relazione spaziale. Quando $\textbf{W}$ è una matrice binaria, come nel nostro caso, allora:
* Se le unità $i,j$ NON sono in relazione tra loro: $\Rightarrow w_{ij} = 0$
* Se le unità $i,j$ sono in relazione tra loro: $\Rightarrow w_{ij} = 1$
In questo modo solamente i termini di covarianza relativi a due località in relazione reciproca saranno inclusi nel calcolo.
Il denominatore della frazione, cioè la doppia sommatoria dei pesi, serve a tener conto della somma totale dei pesi e a relativizzare la misura calcolata al numeratore.
Il termine
$$
\begin{equation}
\frac{n}{\sum_{i=1}^{n} {(y_{i}-\bar{y})}^2 }
\end{equation}
$$
non è altro che l'inverso della varianza dei dati, il che assicura che l’indice non sia grande semplicemente perché i valori e la variabilità in $y$ sono elevati.
La conseguenza di una tale formulazione matematica dell'indice di Moran è la seguente.
Se i dati sono autocorrelati positivamente, allora la maggior parte degli scarti dalla media considerati in precedenza avranno lo stesso segno e quindi l'indice di Moran avrà un valore positivo. D'altra parte, se i dati sono negativamente correlati, la maggior parte degli scarti dalla media avranno segno opposto e il risultato complessivo sarà negativo.
Pertanto, per quanto riguarda un coefficiente di correlazione convenzionale, sappiamo che un valore positivo indica una correlazione positiva e un valore negativo una correlazione negativa. Nel caso di autocorrelazione spaziale il valore, nella stragrande maggioranza dei casi, non è strettamente compreso nell'intervallo da 1 a -1, in quanto è impossibile che una mappa sia perfettamente autocorrelata, sia positivamente che negativamente, tranne che in situazioni molto insolite. In generale, un valore più o meno grande di [0.3;-0.3] indica autocorrelazione relativamente forte.
Per valutare la significatività statistica del valore ricavato verrà costruito un sistema di ipotesi e testato utilizzando una procedura bootstrap che verrà introdotta in seguito.
### Moran's scatterplot
Uno strumento utile nell'analisi dell' autocorrelazione spaziale è il Moran scatterplot.
Tale scatterplot mostra la relazione tra i valori degli attributi stessi (asse orizzontale) e il valore dell'attributo medio locale (ovvero il valore medio delle posizioni associate agli attributi stessi). Come si vede sotto, possiamo dividere lo scatterplot in quattro regioni: il quadrante in basso a sinistra contiene casi in cui il valore dell'attributo in ciascun poligono e il valore dell'attributo medio dei poligoni vicini sono inferiori alla media globale; il quadrante in alto a destra contiene casi in cui sia il valore dell'attributo che la media locale sono maggiori della media globale; e gli altri due quadranti contengono casi in cui il valore dell'attributo e la media locale si trovano su lati opposti della media globale. Le posizioni che si trovano nei quadranti in basso a sinistra e in alto a destra sono quelle che contribuiscono all'autocorrelazione positiva complessiva, poiché hanno un valore di attributo simile a quello dei loro vicini, mentre le posizioni negli altri due quadranti contribuiscono a un'autocorrelazione negativa. Se la maggior parte delle posizioni si trova nei quadranti in basso a sinistra e in alto a destra, allora il risultato sarà un valore positivo dell'I di Moran, cioè un'autocorrelazione positiva.
```{r}
Moran.fun <- function(shape,x,wm){
n <- length(shape)
y <- shape[[etichette[x]]]
ybar <- mean(y, na.rm = TRUE)
# Ora ci serve (yi - ybar)(yj - ybar)