-
Notifications
You must be signed in to change notification settings - Fork 1
/
Batimetria_Arroyo_Valizas_v3.Rmd
2921 lines (1998 loc) · 103 KB
/
Batimetria_Arroyo_Valizas_v3.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: 'Metodología para modelar la batimetría de ríos y arroyos: caso de estudio
del Arroyo Valizas.'
author: "Guzmán López"
date: "3 de octubre de 2017"
output:
github_document:
html_document:
highlight: zenburn
number_sections: yes
theme: cosmo
toc: yes
html_notebook:
fig_caption: yes
highlight: zenburn
number_sections: yes
theme: cosmo
toc: yes
pdf_document:
fig_caption: yes
highlight: zenburn
keep_tex: yes
number_sections: yes
toc: yes
fontsize: 11pt
---
# Ambiente de trabajo en el programa R
En esta sección se describen las características del ambiente de trabajo en el programa `R`, las librerías requeridas y los programas y versiones que fueron necesarios para la realización de este trabajo.
## Información de la sesión
Se utilizó la versión de `R` 3.3.3 y el Ambiente de Desarrollo Integrado (*IDE*) de RStudio versión 1.0.153 sobre un sistema operativo Debian GNU/Linux buster/sid.
```{r tabla_infosesión, echo = FALSE}
class(print(sessionInfo(), locale = FALSE))
```
El directorio de trabajo de `R` se estableció donde se encuentra el archivo fuente para ejecutar el código y elaborar el documento.
```{r setwd_ambiente_trabajo, eval=FALSE, include=TRUE}
setwd("~/Documents/GitLab/Valizas-River-Bathymetry-Model/")
```
## Librerias utilizadas
Las librerías cargadas y necesarias para la realización de este trabajo fueron:
```{r cargar_librerias, echo=TRUE, message=FALSE, warning=FALSE}
# Manipulación de datos
library("data.table")
library("dplyr")
# Reestructurar datos
library("reshape2")
# Conexión a Bases de Datos
library("RPostgreSQL")
library("postGIStools")
# Manipulación de objetos espaciales
library("sf")
library("sp")
# Trigonometría espacial
library("geosphere")
# Interfaz a GEOS
library("rgeos")
# Geoestadística
library("gstat")
library("geoR")
library("geoRglm")
library("automap")
library("gdalUtils")
library("SpatialPosition")
library("rgdal")
# Algunos estadísticos
library("moments")
# Transformaciones Box-Cox
library("forecast")
# Autocorrelaciones - Indices de Moran y Geary
library("ncf")
# Dependencia espacial
library("spdep")
# Selección de modelos por el método de Akaike
library("MASS")
# Importancia relativa predictores
library("relaimpo")
# Correlogramas
library("corrgram")
# Procesamiento en paralelo y en clusters
library("parallel")
# Gráficos
library("ggplot2")
library("gridExtra")
library("plotrix")
library("RColorBrewer")
```
```{r cargar_RData, eval=TRUE, include=FALSE}
# Load data objects
load("data3.RData")
```
Se definió una paleta de colores para los gráficos y mapas basada en el esquema de colores Monokai.
```{r colores_monokai, eval=TRUE, include=TRUE}
# Esquema de colores Monokai
darkgray <- "#272822"
gray <- "#4D4D4D"
lightgray <- "#75715E"
green <- "#81B023"
orange <- "#C97C16"
purple <- "#8F66CC"
red <- "#C72259"
blue <- "#53A8BD"
```
# Metadatos de la batimetría del Arroyo Valizas
## Características de la campaña hidroacústica
El 19 de febrero de 2016 se realizó una campaña hidroacústica a lo largo del Arroyo Valizas que abarcó desde la naciente hasta su desembocadura. Se navegó realizando transectas en zigzag registrando la posición y rumbo mediante GPS y la profundidad del fondo mediante una ecosonda científica portátil modelo BioSonics DT-X con un transductor circular *split-beam* de 123 kHz (7.4◦ de apertura angular). El transductor fue montado verticalmente sobre una banda de una lancha abierta construida en fibra de vidrio de 5.0 m de eslora y 1.7 m de manga con un motor fuera de borda que fue proporcionada por la Unidad de Gestión de Pesca Atlántica (UGEPA) de la Dirección Nacional de Recursos Acuáticos (DINARA) con sede en La Paloma.
## Características de los datos
La ecosonda fue operada mediante una computadora portátil con el software de adquisición de datos Visual Acquisition de BioSonics. Los archivos digitales obtenidos fueron procesados con el software EchoView v.4.20. El procesamiento consistió en la identificación y trazado de una línea virtual del fondo del Arroyo Valizas en dos pasos: 1) detección del fondo mediante un algoritmo de detección provisto por el software y 2) corrección de errores mediante supervisación.
# Crear base de datos en PostgreSQL
Crear una base de datos en PostgreSQL para manejar los ejemplos directamente desde `R`.
```{bash ingresar_postgres, eval=FALSE, engine.path="/bin/zsh", include=TRUE}
# Desde la terminal de Linux, ingresar a postgres
psql -U postgres
```
```{sql crear_bd, eval=FALSE, connection=conn, engine.opts="psql -d batiValizasDB", engine.path="/bin/postgres", include=TRUE}
-- Crear base de datos
CREATE DATABASE batiValizasDB;
-- Conectar la base de datos
\connect batiValizasDB;
-- Create postgis extension
CREATE EXTENSION postgis;
```
```{r conexión_postgresql, eval=FALSE, include=TRUE}
# Establecer una conexión ODBC
# Info de la Base de datos
dbName <- "batiValizasDB"
dbHost <- "localhost"
dbPort <- 5432
dbUser <- ""
dbPassword <- ""
dbString <- paste("PG:dbname='", dbName, "' host='", dbHost, "' port='", dbPort,
"' user='", dbUser, "' password='", dbPassword, "'", sep = "")
# Cargar datos desde el servidor PostGIS
conn <- dbConnect(dbDriver("PostgreSQL"), dbname = dbName, host = dbHost, port = dbPort,
user = dbUser, password = dbPassword)
# Ver tablas en la base de datos
dbListTables(conn)
```
# Cargar datos de batimetría y capas vectoriales espaciales
Se cargaron los datos de batimetría exportados desde el EchoView
```{r cargar_datos_bati, eval=TRUE, include=TRUE}
riverBati <- data.table::fread(input = "tablas/LineaFondoTodo.csv", sep = ",",
header = TRUE, showProgress = TRUE, data.table = FALSE, stringsAsFactors = FALSE)
```
```{r tabla_datos_bati, eval=TRUE, include=TRUE, echo=FALSE, results = 'asis'}
knitr::kable(riverBati[1:5, 1:7], caption = "Datos de batimetría")
knitr::kable(riverBati[1:5, 8:11], caption = "Datos de batimetría")
```
## Cargar capas espaciales
Definir los Sistemas de Referencia de Coordenadas utilizados: WGS84 y UTM zona 21 S.
```{r crs_definición, eval=FALSE, include=TRUE}
# Sistemas de referencias de coordenadas
epsg.32721 <- "+proj=utm +zone=21 +south +datum=WGS84 +units=m +no_defs"
wgs.84 <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
```
```{r cargar_capa_valizaspoly, eval=FALSE, include=TRUE}
# Cargar capa espacial del Arroyo Valizas (polígono)
arroyoValizasPoly <- read_sf("capasVectoriales/ArroyoValizasPoly-UTM21.shp")
```
```{r cargar_capa_lineareferencia, eval=TRUE, include=TRUE}
# Cargar capa espacial de la Línea de Referencia (línea)
refLineSmooth <- read_sf("capasVectoriales/ArroyoValizas-RefLine-Smooth.shp")
# Agregar ID
refLineSmooth$spatial_id <- 1:nrow(refLineSmooth)
# Cambiar el nombre de las columnas a minúsculas
names(refLineSmooth) <- tolower(names(refLineSmooth))
```
```{r mapa_arroyovalizaslinearef, eval=TRUE, include=TRUE, message=TRUE, warning=FALSE}
# Plot
plot(st_transform(arroyoValizasPoly, 4326), bgc = darkgray, col = blue,
border = blue, lwd = 1, xlab = "Longitud", ylab = "Latitud", graticule = TRUE,
col_graticule = lightgray, axes = TRUE, main = "Arroyo Valizas y línea de referencia",
cex.axis = 0.75, lat = seq(-34.2, -34.4, by = -0.01))
plot(st_transform(refLineSmooth, 4326), col = red, lwd = 2, add = TRUE)
legend("bottomright", legend = c("Arroyo Valizas", "Línea de referencia"),
pch = c(15, NA), lty = c(NA, 1), col = c(blue, red), lwd = c(NA, 3),
pt.cex = c(2, 1), bg = "white")
```
## Filtrar datos de batimetría
```{r filtrar_datosbati, eval=FALSE, include=TRUE}
# Remover estados de línea con errores (Line_status = 0)
riverBatiF <- subset(x = riverBati, subset = riverBati$Line_status == 1)
# Crear objeto sf
riverBatiF <- st_as_sf(riverBatiF, coords = c("Longitude", "Latitude"))
st_crs(riverBatiF) <- wgs.84 # assign CRS to points
# Transformar coordenadas
riverBatiF <- st_transform(riverBatiF, crs = epsg.32721)
# Eliminar puntos afuera del polígono del río
batiRiverIntersect <- st_intersects(riverBatiF, arroyoValizasPoly)
riverBatiF2 <- riverBatiF[which(!is.na(batiRiverIntersect)), ]
# Eliminar puntos duplicados
riverBatiF3 <- sp::remove.duplicates(obj = as(riverBatiF2, "Spatial"),
remove.second = TRUE)
riverBatiF3 <- st_as_sf(riverBatiF3)
# Add temporary unique ID to spatial DF
riverBatiF3$spatial_id <- 1:nrow(riverBatiF3)
# Set column names to lower case
names(riverBatiF3) <- tolower(names(riverBatiF3))
```
```{r crear_regulargrid5m, eval=FALSE, include=TRUE}
# Create Regular grid
mygrid5m <- st_make_grid(x = arroyoValizasPoly, cellsize = 5, what = "centers")
# Grid points adentro de polígono de Arroyo
gridRiverIntersect <- st_intersects(mygrid5m, arroyoValizasPoly)
mygrid5m <- mygrid5m[which(!is.na(gridRiverIntersect) & !(gridRiverIntersect ==
0))]
# Add temporary unique ID to spatial DF
dfAux <- data.frame(spatial_id = 1:length(mygrid5m))
dfAux$geom <- st_geometry(mygrid5m)
mygrid5m <- st_as_sf(dfAux)
```
```{r mapa_todos, eval=TRUE, message=TRUE, warning=FALSE, include=TRUE}
# Plot
plot(st_transform(arroyoValizasPoly, 4326), bgc = darkgray, col = blue,
border = blue, lwd = 1, xlab = "Longitud", ylab = "Latitud", graticule = TRUE,
col_graticule = lightgray, axes = TRUE, main = "Mapa conceptual", cex.axis = 0.75,
lat = seq(-34.2, -34.4, by = -5e-04), xlim = c(-53.852, -53.8494),
ylim = c(-34.359, -34.358))
plot(st_transform(riverBatiF3, 4326), col = orange, cex = 0.5, add = TRUE)
plot(st_transform(refLineSmooth, 4326), col = red, lwd = 3, add = TRUE)
plot(st_transform(mygrid5m, 4326), col = darkgray, cex = 0.5, pch = 19,
add = TRUE)
legend("bottomright", legend = c("Arroyo Valizas", "Batimetría", "Línea de referencia",
"Grilla de 5 metros"), pch = c(15, 19, NA, 19), lty = c(NA, NA, 1, NA),
col = c(blue, orange, red, darkgray), lwd = c(NA, 3, 3, NA), pt.cex = c(2,
0.5, 1, 0.5), bg = "white")
```
## Escribir objetos espaciales a PostgreSQL
```{r escribir_capas_bd, eval=FALSE, include=TRUE}
st_write(obj = riverBatiF3, layer = "riverdepthb", driver = "PostgreSQL",
dsn = dbString, layer_options = c("geometry_name=geom, OVERWRITE=YES"))
st_write(obj = mygrid5m, layer = "mygrid5mb", driver = "PostgreSQL", dsn = dbString,
layer_options = c("geometry_name=geom, OVERWRITE=YES"))
st_write(obj = refLineSmooth, layer = "reflinesmoothb", driver = "PostgreSQL",
dsn = dbString, layer_options = c("geometry_name=geom, OVERWRITE=YES"))
# Ver tablas en la base de datos
dbListTables(conn)
```
## Transformar coordenadas
Transformar coordenadas de los puntos de batimetría.
```{sql, connection=conn, engine.opts="psql -d batiValizasDB", engine.path="/bin/postgres", eval=FALSE, include=TRUE}
-- Crear tabla riverdepthsn a partir de la transformación de coordendas
-- de los puntos de batimetría con respecto a la línea de referencia
CREATE TABLE riverdepthsn AS
SELECT points.spatial_id, points.depth AS depth,
st_distance(line.geom, points.geom) AS N,
ST_LineLocatePoint(st_linemerge(line.geom), (ST_Dump(points.geom)).geom) *
st_length(st_linemerge(line.geom)) AS S,
st_makepoint(st_distance(line.geom, points.geom),
ST_LineLocatePoint(st_linemerge(line.geom), (ST_Dump(points.geom)).geom) *
st_length(st_linemerge(line.geom))) AS geom
FROM reflinesmooth AS line, riverdepth AS points;
-- Ver los primeros 10 registros de la tabla creada
SELECT *
FROM riverdepthsn
LIMIT 10;
```
```{sql, connection=conn, engine.opts="psql -d batiValizasDB", engine.path="/bin/postgres", eval=FALSE, include=TRUE}
-- Crear tabla rivergridsn a partir de la transformación de coordendas
-- de los puntos de la grilla con respecto a la línea de referencia
CREATE TABLE rivergridsn AS
SELECT points.spatial_id,
st_distance(line.geom, points.geom) AS N,
ST_LineLocatePoint(st_linemerge(line.geom), (ST_Dump(points.geom)).geom) *
st_length(st_linemerge(line.geom)) AS S,
st_makepoint(st_distance(line.geom, points.geom),
ST_LineLocatePoint(st_linemerge(line.geom), (ST_Dump(points.geom)).geom) *
st_length(st_linemerge(line.geom))) AS geom
FROM reflinesmooth AS line, mygrid5m AS points;
-- Ver los primeros 10 registros de la tabla creada
SELECT *
FROM rivergridsn
LIMIT 10;
```
## Cargar capas espaciales transformadas desde la Base de Datos PostGIS
```{r, eval=FALSE, include=TRUE, message=FALSE, warning=FALSE}
# Points Transformed Bati
riverdepthsn <- st_read(dsn = dbString, layer = "riverdepthsn")
# Points Transformed River Grid 5m
rivergridsn <- st_read(dsn = dbString, layer = "rivergridsn")
```
# Análisis exploratorio de los datos
## Distribución de frecuencias
Para ilustrar como la distribución de los datos de batimetría se ubican con respecto a su mediana o para identificar valores extremos se realizó un Histograma y un Diagrama de cajas.
```{r ggplot_hist_boxplot, message=FALSE, warning=FALSE}
ggDatosBati <- ggplot(data = st_set_geometry(riverdepthsn, NULL))
# Histograma Profundidad
ggHistBati <- ggDatosBati + geom_histogram(aes(x = depth), binwidth = 0.25,
fill = blue, col = darkgray, alpha = 1) + labs(title = "", x = "Profundidad (m)",
y = "Frecuencia") + scale_x_continuous(limits = c(1, 7.25), breaks = seq(1,
7.25, 0.5)) + scale_y_continuous(limits = c(0, 6000), breaks = seq(0,
6000, 500)) + theme(plot.margin = unit(c(-1, 1, 1, 1), "mm"))
# Boxplot profundidad
ggBoxPlotBati <- ggDatosBati + geom_boxplot(aes(y = depth, x = rep("Prof",
length(depth))), fill = blue, col = darkgray, alpha = 1) + labs(title = "",
x = "", y = "") + scale_y_continuous(limits = c(1, 7.25), breaks = seq(1,
7.25, 0.5), position = "top") + coord_flip() + theme(plot.margin = unit(c(1,
1, -1, 1), "mm"))
# Ver plot
grid.arrange(ggBoxPlotBati, ggHistBati, ncol = 1, nrow = 2, heights = c(1,
3))
```
Se observó que la *profundidad* posee dispersión de valores entorno a la mediana. Además, la frecuencia de valores mayores a la mediana fue mayor que la frecuencia para los valores menores. Se observaron valores extremos positivos a partir de 5.75 metros de profundidad.
## Tendencia central y dispersión
Para analizar cuantitativamente el rango, la tendencia central y la dispersión de los datos de la *profundidad* se creó una función personalizada llamada `ResumenEstadisticas`. Además se incluyó que dicha función retorne el tipo de clase de la variable en `R` y la cantidad de celdas vacías (`NA`).
```{r func_resumenestadisticas, eval=TRUE, include=TRUE}
ResumenEstadisticas <- function(df) {
if (class(df) == "data.frame") {
# Número de columnas del data.frame
ncol = ncol(df)
} else {
# Coerce vector to data.frame
df = data.frame(variable = df)
ncol = ncol(df)
}
# Estadísticas
maximo = numeric()
minimo = numeric()
media = numeric()
mediana = numeric()
moda = vector()
varianza = numeric()
desvioEstandar = numeric()
cv = numeric()
asimetria = numeric()
kurtosis = numeric()
NAs = numeric()
clases = character()
# Función para calcular la moda
Moda <- function(x) {
ux = unique(x)
ux[which.max(tabulate(match(x, ux)))]
}
# Iteración que recorre todas las columnas del data.frame
for (i in 1:ncol) {
# Condición de que la columna para las estadísticas tenga que ser
# numérica
if (is.numeric(df[, i])) {
mediana[i] = median(df[, i], na.rm = TRUE)
media[i] = mean(df[, i], na.rm = TRUE)
moda[i] = Moda(x = df[, i])
varianza[i] = var(df[, i], na.rm = TRUE)
desvioEstandar[i] = sd(df[, i], na.rm = TRUE)
cv[i] = 100 * (sd(df[, i], na.rm = TRUE)/mean(df[, i], na.rm = TRUE))
asimetria[i] = moments::skewness(df[, i], na.rm = TRUE)
kurtosis[i] = moments::kurtosis(df[, i], na.rm = TRUE)
minimo[i] = min(df[, i], na.rm = TRUE)
maximo[i] = max(df[, i], na.rm = TRUE)
NAs[i] = length(which(is.na(df[, i]) == TRUE))
clases[i] = class(df[, i])
} else {
# En caso de que no sea de tipo numérica asignar NAs a las
# estadísticas pero calcular el número de NAs y tipo de datos
mediana[i] = NA
media[i] = NA
moda[i] = Moda(x = df[, i])
varianza[i] = NA
desvioEstandar[i] = NA
cv[i] = 100 * NA
asimetria[i] = NA
kurtosis[i] = NA
minimo[i] = NA
maximo[i] = NA
NAs[i] = length(which(is.na(df[, i]) == TRUE))
clases[i] = class(df[, i])
}
}
# Generar data.frame con todas las estadísticas
summary = data.frame(mínimo = minimo, máximo = maximo, media = media,
mediana = mediana, moda = moda, varianza = varianza, ds = desvioEstandar,
cv = cv, asimetría = asimetria, kurtosis = kurtosis, NAs = NAs,
clase = clases)
# Asignar el nombre de las variables (columnas) como nombre de las
# filas para el objeto de salida
rownames(summary) <- colnames(df)
# Retorno de la función
return(summary)
}
```
Se llamó a la función `ResumenEstadisticas` pasando como parámetro el `data.frame` llamado `data` contenido en el objeto espacial `riverdepthsn` y se asignó el retorno de la función a un nuevo objeto llamado `resumenriverdepthsn`. Además, se imprimió en consola el resultado de la ejecución del comando.
```{r, eval=TRUE, include=TRUE}
# Crear objeto con las principales estadísticas y mostrarlo en consola
(resumenriverdepthsn <- ResumenEstadisticas(df = riverdepthsn$depth))
```
## Estructura y resumen de los datos
```{r, eval=TRUE, include=TRUE}
head(riverdepthsn)
```
```{r, eval=TRUE, include=TRUE}
str(riverdepthsn)
```
## Normalidad
Para analizar la normalidad de la *profundidad* se realizó la prueba de normalidad de *Shapiro-Wilk*. La hipótesis nula de la prueba de *Shapiro-Wilk* es que los datos son normales, por lo cual un *p-valor* significativo indicó que se rechazó la hipótesis nula, es decir que la variable analizada fuese normal.
```{r, eval=TRUE, include=TRUE}
# Profundidad
shapiro.test(riverdepthsn$depth[sample(x = 1:nrow(riverdepthsn), size = 5000, replace = FALSE)])
```
Se rechazó la hipótesis nula de la prueba de normalidad de *Shapiro-Wilk* para la *profundidad*.
## Transformaciones a normalidad
Se transformó los datos originales a nuevas escalas para acercarlos a una distribución normal. Se probaron las transformaciones *logarítmica*, *raíz cuadrada* y *Box-Cox*.
```{r, eval=FALSE, include=TRUE}
# Transformar profundidad
# Logaritmo
ProfLog <- log(riverdepthsn$depth)
shapiro.test(ProfLog[sample(x = 1:nrow(riverdepthsn), size = 5000, replace = FALSE)]) # Probar normalidad de la transformación
# Raíz cuadrada
ProfSqrt <- sqrt(riverdepthsn$depth)
shapiro.test(ProfSqrt[sample(x = 1:nrow(riverdepthsn), size = 5000, replace = FALSE)]) # Probar normalidad de la transformación
# Box-Cox
lambdaProf <- BoxCox.lambda(x = riverdepthsn$depth) # Hallar Lambda
ProfBC <- BoxCox(x = riverdepthsn$depth, lambda = lambdaProf) # Transf.vector
shapiro.test(ProfBC[sample(x = 1:nrow(riverdepthsn), size = 5000, replace = FALSE)]) # Probar normalidad de la transformación
```
Ninguna de las transformaciones de los datos permitió que se pudiera fallar en rechazar la hipótesis nula de normalidad del test de *Shapiro-Wilk*.
## Q-Q Plots
```{r, fig.width=12, message=FALSE, warning=FALSE}
# Q-Q plot profundidad
ggQQprof <- ggDatosBati +
geom_qq(aes(sample = depth)) +
geom_abline(intercept = mean(riverdepthsn$depth, na.rm = TRUE),
slope = sd(riverdepthsn$depth, na.rm = TRUE), col = "red") +
labs(title = "Profundidad (m)", x = "Cuantiles teóricos",
y = "Cuantiles de la muestra")
ggQQprofLog <- ggDatosBati +
geom_qq(aes(sample = log(depth))) +
geom_abline(intercept = mean(log(riverdepthsn$depth), na.rm = TRUE),
slope = sd(log(riverdepthsn$depth), na.rm = TRUE), col = "red") +
labs(title = "Log Prof.", x = "Cuantiles teóricos",
y = "Cuantiles de la muestra")
ggQQprofSqrt <- ggDatosBati +
geom_qq(aes(sample = sqrt(depth))) +
geom_abline(intercept = mean(sqrt(riverdepthsn$depth), na.rm = TRUE),
slope = sd(sqrt(riverdepthsn$depth), na.rm = TRUE), col = "red") +
labs(title = "Raíz cuadrada Prof.", x = "Cuantiles teóricos",
y = "Cuantiles de la muestra")
ggQQprofBC <- ggDatosBati +
geom_qq(aes(sample = ProfBC)) +
geom_abline(intercept = mean(ProfBC, na.rm = TRUE),
slope = sd(ProfBC, na.rm = TRUE), col = "red") +
labs(title = "Box-Cox Prof", x = "Cuantiles teóricos",
y = "Cuantiles de la muestra")
# Ver plots
grid.arrange(ggQQprof, ggQQprofLog, ggQQprofSqrt, ggQQprofBC,
ncol = 2, nrow = 2)
```
A partir del análisis de los Q-Q plots (cuantiles - cuantiles) se observó que todas las transforamciones probadas no acercaron sustantivamente los datos originales a distribuciones normales. Incluso, los Q-Q plots para los datos originales confirman el desvío de los datos de una distribución normal.
## Análisis de tendencias
Para analizar si existen tendencias entre la *profundidad* y la latitud y longitud se realizaron gráficos de dispersión de puntos junto con lineas basadas en suavizados de la medias locales de los valores.
```{r, fig.width=12, message=FALSE, warning=FALSE}
# Profundidad vs transformación Longitud (N)
ggTend_ProfVsLong <- ggDatosBati +
geom_point(aes(y = depth, x = riverdepthsn$n)) +
geom_smooth(aes(y = depth, x = riverdepthsn$n)) +
labs(title = "", x = "n", y = "Profundidad (m)")
# Profundidad vs transformación Latitud (S)
ggTend_ProfVsLat <- ggDatosBati +
geom_point(aes(y = depth, x = riverdepthsn$s)) +
geom_smooth(aes(y = depth, x = riverdepthsn$s)) +
labs(title = "", x = "s", y = "Profundidad (m)")
# Ver plots
grid.arrange(ggTend_ProfVsLong, ggTend_ProfVsLat,
ncol = 1, nrow = 2)
```
A partir de los gráficos de dispersión y suavizado de medias, no se observó una tendencia entre la *profundidad* y la *latitud* o *longitud*.
## Correlación
Se calculó el coeficiente de correlación de Pearson ($r$) para cuantificar la relación entre la *profundidad* y la *latitud* y *longitud*. Para complementar la interpretación, se realizaron correlogramas para visualizar la matriz de correlaciones.
```{r, eval=TRUE, include=TRUE}
# Profundidad vs transformación Longitud (N)
cor.test(x = riverdepthsn$n,
y = riverdepthsn$depth,
method = "pearson")
# Profundidad vs transformación Latitud (S)
cor.test(x = riverdepthsn$s,
y = riverdepthsn$depth,
method = "pearson")
```
Se observó que la correlación entre la *profundidad* con la *latitud* y la *longitud* fueron bajas ($-0.04 < r < 0.10$), confirmando una tendencia despreciable.
## Índice de Moran (ver acá)
```{r, eval=FALSE, include=TRUE}
corr <- data.frame(no = 1:20)
corr$gls <- correlog(x = temp.data$x, y = temp.data$y, z = model.gls$residuals, increment = 2, resamp = 100, quiet = T)$correlation
corr$gls.spat <- correlog(x = temp.data$x, y = temp.data$y, z = model.gls.spat$residuals, increment = 2, resamp = 100, quiet = T)$correlation
```
```{r, eval=FALSE, include=TRUE, fig.width=12, message=FALSE, warning=FALSE}
plot(corr$gls ~ corr$no, pch = 1, xlab = 'Distance', ylab = 'Moran I')
points(corr$gls.spat ~ corr$no, pch = 16)
legend('bottomleft', c('GLS', 'spatial GLS'), pch = c(1,16), cex = 0.7)
```
# Variograma empírico
A partir del análisis de los variogramas empíricos puede decirse que existe estructura espacial para las dos campañas ya que:
- la semivarianza ($\gamma$) aumenta con la distancia hasta llegar a una meseta, que implica que la dependencia espacial va disminuyendo con la distancia hasta alcanzar la independencia espacial.
**Nota:** dado que para estimar los parámetros de ajuste de los modelos teóricos a los variogramas empíricos mediante métodos cuantitativos se utilizará la librería `geoR` y para realizar los modelos de predicción-interpolación, validación cruzada y simulaciones se utilizará la librería `gstat`, se incluyen los variogramas empíricos y direccionales utilizando las dos librerías (requisitos necesarios de creación de objetos para poder utilizar una y otra librería).
## Con librería `geoR`
```{r, eval=FALSE, include=TRUE}
# Con librería geoR:
# Objetos geodata
geodataZ <- as.geodata(obj = st_set_geometry(riverdepthsn, NULL), coords.col = 3:4, data.col = 2)
```
```{r, eval=TRUE, include=TRUE, fig.width=12, message=FALSE, warning=FALSE}
plot(geodataZ)
```
```{r, eval=FALSE, include=TRUE}
# Tomar submuestra aleatoria
geodataZ.sample <- sample.geodata(geodataZ, size = 40000, replace = FALSE)
# Crear variograma empírico
varZ <- variog(geodataZ.sample, max.dist = 500, breaks = seq(from = 0, to = 500, by = 5))
gc()
```
```{r, eval=TRUE, include=TRUE, fig.width=12, message=FALSE, warning=FALSE}
# Plot variogramas empíricos
plot(varZ, pch = 19, col = blue, ylab = "semivarianza", xlab = "distancia", main = "Variograma empírico de Z")
```
## Con librería `gstat`
```{r, eval=FALSE, include=TRUE}
# gstat data
gstatZ.sample <- gstat(id = "depth", formula = depth ~ 1, data = as(riverdepthsn, "Spatial"))
# Crear variograma empírico omnidireccional
varOmniZ <- variogram(gstatZ.sample, width = 5, cutoff = 500)
```
```{r, eval=TRUE, include=TRUE, fig.width=12, message=FALSE, warning=FALSE}
# Plotear variograma
plot(varOmniZ, xlab = "distancia", ylab = "semivarianza",
main = "Variograma empírico - Z", pch = 19, col = blue)
```
# Análisis del proceso espacial (isotropía y anisotropía)
```{r, eval=FALSE, include=TRUE}
# Compute the 10 degree variogram for the following directions:
var1 <- variogram(gstatZ.sample, alpha = 0, tol.hor = 11.25, cutoff = 300, width = 5)
var2 <- variogram(gstatZ.sample, alpha = 22.5, tol.hor = 11.25, cutoff = 90, width = 2)
var3 <- variogram(gstatZ.sample, alpha = 45, tol.hor = 11.25, cutoff = 45, width = 3)
var4 <- variogram(gstatZ.sample, alpha = 67.5, tol.hor = 11.25, cutoff = 25, width = 2)
var5 <- variogram(gstatZ.sample, alpha = 90, tol.hor = 11.25, cutoff = 22, width = 2)
var6 <- variogram(gstatZ.sample, alpha = 112.5, tol.hor = 11.25, cutoff = 39, width = 3)
var7 <- variogram(gstatZ.sample, alpha = 135, tol.hor = 11.25, cutoff = 35, width = 3)
var8 <- variogram(gstatZ.sample, alpha = 157.5, tol.hor = 11.25, cutoff = 90, width = 2)
```
```{r, eval=TRUE, include=TRUE, fig.width=12, message=FALSE, warning=FALSE}
# Plotear variograma
par(mfrow = c(2,4))
plot(x = var1$dist, y = var1$gamma, xlab = "distancia", ylab = "semivarianza",
main = "Variograma emp. 0 grados", pch = 19, col = blue)
lines(x = variogramLine(fit.variogram(var1, model = vgm("Cir")), maxdist = 400)$dist,
y = variogramLine(fit.variogram(var1, model = vgm("Cir")), maxdist = 400)$gamma, col = red)
plot(x = var2$dist, y = var2$gamma, xlab = "distancia", ylab = "semivarianza",
main = "Variograma emp. 22.5 grados", pch = 19, col = blue)
lines(x = variogramLine(fit.variogram(var2, model = vgm("Cir")), maxdist = 400)$dist,
y = variogramLine(fit.variogram(var2, model = vgm("Cir")), maxdist = 400)$gamma, col = red)
plot(x = var3$dist, y = var3$gamma, xlab = "distancia", ylab = "semivarianza",
main = "Variograma emp. 45 grados", pch = 19, col = blue)
lines(x = variogramLine(fit.variogram(var3, model = vgm("Cir")), maxdist = 400)$dist,
y = variogramLine(fit.variogram(var3, model = vgm("Cir")), maxdist = 400)$gamma, col = red)
plot(x = var4$dist, y = var4$gamma, xlab = "distancia", ylab = "semivarianza",
main = "Variograma emp. 67.5 grados", pch = 19, col = blue)
lines(x = variogramLine(fit.variogram(var4, model = vgm("Cir")), maxdist = 400)$dist,
y = variogramLine(fit.variogram(var4, model = vgm("Cir")), maxdist = 400)$gamma, col = red)
plot(x = var5$dist, y = var5$gamma, xlab = "distancia", ylab = "semivarianza",
main = "Variograma emp. 90 grados", pch = 19, col = blue)
lines(x = variogramLine(fit.variogram(var5, model = vgm("Cir")), maxdist = 400)$dist,
y = variogramLine(fit.variogram(var5, model = vgm("Cir")), maxdist = 400)$gamma, col = red)
plot(x = var6$dist, y = var6$gamma, xlab = "distancia", ylab = "semivarianza",
main = "Variograma emp. 112.5 grados", pch = 19, col = blue)
lines(x = variogramLine(fit.variogram(var6, model = vgm("Cir")), maxdist = 400)$dist,
y = variogramLine(fit.variogram(var6, model = vgm("Cir")), maxdist = 400)$gamma, col = red)
plot(x = var7$dist, y = var7$gamma, xlab = "distancia", ylab = "semivarianza",
main = "Variograma emp. 135 grados", pch = 19, col = blue)
lines(x = variogramLine(fit.variogram(var7, model = vgm("Cir")), maxdist = 400)$dist,
y = variogramLine(fit.variogram(var7, model = vgm("Cir")), maxdist = 400)$gamma, col = red)
plot(x = var8$dist, y = var8$gamma, xlab = "distancia", ylab = "semivarianza",
main = "Variograma emp. 157.5 grados", pch = 19, col = blue)
lines(x = variogramLine(fit.variogram(var8, model = vgm("Cir")), maxdist = 400)$dist,
y = variogramLine(fit.variogram(var8, model = vgm("Cir")), maxdist = 400)$gamma, col = red)
par(mfrow = c(1,1))
```
A partir del análisis de los variogramas direccionales se concluyó que el proceso espacial es anisotrópico. Se observaron diferencias en la meseta ($\gamma_{Z}$) y también en la distancia a la cual se llega a $\gamma$ ($h_{z}$) para las distintas direcciones en el espacio ($0^{\circ}, 45^{\circ}, 90^{\circ} y 135^{\circ}$).
# Ajustar modelos de variogramas teóricos a variograma empírico
Ajuste al menos tres tipos de modelos permisibles para cada uno de los variogramas muestrales obtenidos en el punto anterior y elija el mejor en cada caso justificando su elección a partir de un criterio cuantitativo objetivo. Utilice procedimientos de estimación estadísticos para ajustar el modelo del variograma.
Se ajustaron cuatro modelos permisibles (*Esférico*, *Exponencial*, *Circular* y *Matern*) a los variogramas empíricos obtenidos para cada una de las campañas mediante estimación de parámetros por el método de *Máxima versoimilitud restringida (REML)*. Se utilizó para ello la librería `geoR` debido a que presenta la función `likfit` que permite estimar los parámetros necesarios (*rango*, *meseta* y *pepita*) para ajustar un modelo de variograma teórico al variograma empírico y seguir un criterio cuantitativo para seleccionar el mejor modelo. La librería `gstat` posee la función `fit.variogram.reml` que cumple con lo anterior pero solo estima el *rango*. También se probó la función `fit.variogram.gls` pero no es eficaz para muchos datos y requería de un muestreo aleatorio (trabajar con una submuestra) sobre los datos originales.
(Para el ajuste de los modelos se asumió que el efecto pepita o nugget fue cero y no se estimó este parámetro.)
```{r, eval=FALSE, include=TRUE}
# submuestrear submuestra
geodataZ.sample2 <- sample.geodata(geodataZ.sample, 1000, replace = FALSE)
```
```{r, eval=TRUE, include=TRUE}
# Matriz de posibles parámetros iniciales de rango y meseta para C1
iniCovParsZ <- cbind("sigma" = seq(0.5, 1.5, length.out = 20),
"phi" = seq(10, 200, length.out = 20)
)
iniCovParsZ <- as.matrix(iniCovParsZ) # convertir a matriz
```
```{r, eval=FALSE, include=TRUE}
# Ajuste modelo esférico
likfitVarZ.sph <- likfit(geodataZ.sample2,
ini.cov.pars = iniCovParsZ,
limits = pars.limits(phi = c(10, 200), sigmasq = c(0.5, 1.5)),
fix.nugget = FALSE,
fix.psiA = FALSE,
fix.psiR = FALSE,
cov.model = "spherical",
lik.method = "REML")
# Ajuste modelo exponencial
likfitVarZ.exp <- likfit(geodataZ.sample2,
ini.cov.pars = iniCovParsZ,
limits = pars.limits(phi = c(10, 200), sigmasq = c(0.5, 1.5)),
fix.nugget = FALSE,
fix.psiA = FALSE,
fix.psiR = FALSE,
cov.model = "exponential",
lik.method = "REML")
# Ajuste modelo circular
likfitVarZ.cir <- likfit(geodataZ.sample2,
ini.cov.pars = iniCovParsZ,
limits = pars.limits(phi = c(10, 200), sigmasq = c(0.5, 1.5)),
fix.nugget = FALSE,
fix.psiA = FALSE,
fix.psiR = FALSE,
cov.model = "circular",
lik.method = "REML")
# Ajuste modelo Matern
likfitVarZ.mat <- likfit(geodataZ.sample2,
ini.cov.pars = iniCovParsZ,
limits = pars.limits(phi = c(10, 200), sigmasq = c(0.5, 1.5)),
fix.kappa = FALSE,
fix.nugget = FALSE,
fix.psiA = FALSE,
fix.psiR = FALSE,
cov.model = "matern",
lik.method = "REML")
```
Resumen de los ajustes a los modelos teóricos
```{r, eval=FALSE, include=TRUE}
summary(likfitVarZ.sph)
summary(likfitVarZ.exp)
summary(likfitVarZ.cir)
summary(likfitVarZ.mat)
```
```{r, , eval=TRUE, include=TRUE, fig.width=12, message=TRUE, warning=FALSE}
# Plot variograma empírico + modelos
# Crear variograma empírico
varZ.sample2 <- variog(geodataZ.sample2, max.dist = 200, breaks = seq(from = 0, to = 200, by = 10))
plot(varZ.sample2, main = "Z", ylab = "semivarianza",
xlab = "distancia", pch = 19, col = blue, ylim = c(0,1.5))
lines.variomodel(likfitVarZ.sph, col = "red", lty = 2, max.dist = 200)
lines.variomodel(likfitVarZ.exp, col = "red", lty = 3, max.dist = 200)
lines.variomodel(likfitVarZ.cir, col = "red", lty = 4, max.dist = 200)
lines.variomodel(likfitVarZ.mat, col = "red", lty = 5, max.dist = 200)
grid()
legend('bottomright', lty = c(2,3,4,5), legend = c('Esf','Exp','Cir','Mat'), col = rep("red", 3))
```
```{r, eval=FALSE, include=TRUE}
# Selección de modelo por criterio de información de Akaike
AICmodelosZ <- data.frame("Modelo" = c('Esférico', 'Exponencial', 'Circular', 'Matern'),
"AIC" = c(likfitVarZ.sph$AIC, likfitVarZ.exp$AIC, likfitVarZ.cir$AIC, likfitVarZ.mat$AIC))
print(AICmodelosZ)
```
El mejor ajuste del modelo de variograma teórico a los datos fue para el modelo *Circular* ($AICesf_{Z} = 2049.224$, $AICexp_{Z} = 2058.332$, $AICcir_{Z} = 2049.224$ y $AICmat_{Z} = 2060.332$).
```{r, eval=FALSE, include=TRUE, fig.width=12, message=TRUE, warning=FALSE}
# gstat: anis = c("ángulo eje mayor - 0 grados norte", "eje menor / eje mayor = valor entre 0 y 1"), ámgulo en grados
# geoR: anis = c("ángulo eje mayor - 0 grados norte", "eje mayor / eje menor = mayor o igual a 1"), ángulo en radianes, parece devolver el rango del eje menor y no del mayor(ojo!)
# Radians to degrees function
rad2deg <- function(rad) {(rad * 180) / (pi)}
anisoAng <- rad2deg(likfitVarZ.cir$aniso.pars[1])
anisoRel <- 1/likfitVarZ.cir$aniso.pars[2]
ejeMenor <- likfitVarZ.cir$phi
ejeMayor <- 1/anisoRel * ejeMenor
varMejorTeoZ <- vgm(psill = likfitVarZ.cir$sigmasq,
model = "Cir",
range = ejeMayor,
nugget = likfitVarZ.cir$nugget,
anis = c(anisoAng, anisoRel)
)
# Plotear variograma experimental y ajuste modelo teórico
plot(x = varOmniZ$dist, y = varOmniZ$gamma, main = "Mejor ajuste de modelo - Z",
col = blue, ylab = "semivarianza", xlab = "distancia",
ylim = c(0, 1.5), xlim = c(0, 200), pch = 19)
lines(variogramLine(object = varMejorTeoZ, maxdist = 200), col = "red", lwd = 1, lty = 1)
legend("bottomright", c("Modelo Circular"), lty = 1, col = "red")
```
# Interpolación mediante Kriging Ordinario Local
## Cortar el objeto espacial en partes
Para gestionar la memoria de RAM se tuvo que cortar el objeto espacial en partes para su posterior interpolación
```{r, eval=TRUE, include=TRUE}
# Clip Spatial Objects
ClipSpObj <- function(xmin, xmax, ymin, ymax, spatialObject) {
vectorClip = which(st_coordinates(spatialObject)[,1] >= xmin & st_coordinates(spatialObject)[,1] < xmax & st_coordinates(spatialObject)[,2] >= ymin & st_coordinates(spatialObject)[,2] < ymax)
spatialObjectClipped = spatialObject[vectorClip,]
return(spatialObjectClipped)