En esta página se muestran algunos ejercicios básicos para empezar a familiarizarse con el ambiente de trabajo R. Las funciones que veremos a continuación son las que todo principiante en R debería conocer y tratar de memorizar puesto que le servirán por siempre. A medida que el estudiante se familiarice con estas funciones podrá continuar con funciones y códigos un poco más complejos. Tengan paciencia y mucha persistencia.
Primero vamos a descargar los datos de este enlace: https://drive.google.com/drive/folders/1UOp6HdmGZuZCQAH8G8BqJmuOEW1hTWp0?usp=sharing
Vamos a instalar los paquetes que trae R y que usaremos. # install.packages(“sp”, “raster”, “rgdal”, “dismo”, “envirem”)
Direccionar un directorio-folder de trabajo
setwd("/mnt/tb/DD/Dropbox/Curso_PEMBU")
Algunas operaciones básicas
a <- 100
b <- 1:10
c <- "Curso"
d <- c("Curso", "UNAM", "Clima")
a
## [1] 100
b
## [1] 1 2 3 4 5 6 7 8 9 10
c
## [1] "Curso"
d
## [1] "Curso" "UNAM" "Clima"
# crear una matriz
e <- matrix(1:9, nrow = 3, ncol = 3)
e
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
Ahora vamos a jugar con datos. Subiremos un conjunto de datos en formato CSV (comma-separated-value). Estos archivos se pueden abrir con Excel o LibreOffice.
mis_datos <- read.csv("./Tablas/distancias_islas_caribe.csv", header = TRUE)
Funciones básicas para empezar a explorar
# head me muestra el encabezado del archivo que acabo de subir (las primeras filas)
head(mis_datos)
## ID Island species distance
## 1 11342 Not assigned aeneus 6.075
## 2 11359 Southern Lesser Antilles aeneus 8.194
## 3 11360 Not assigned aeneus 4.618
## 4 11361 Not assigned aeneus 4.382
## 5 11362 Not assigned aeneus 4.611
## 6 11363 Not assigned aeneus 2.855
# tail me muestra la parte final del archivo
tail(mis_datos)
## ID Island species distance
## 129312 919813 Southern Lesser Antilles whitemani 9.946
## 129313 919816 Southern Lesser Antilles whitemani 8.92
## 129314 919817 Southern Lesser Antilles whitemani 8.755
## 129315 919818 Southern Lesser Antilles whitemani 8.831
## 129316 919831 Southern Lesser Antilles whitemani 8.73
## 129317 919833 Not assigned whitemani 8.848
# class: indica que tipo de archivo estoy usando, e.g., un vector, una lista, un dataframe, una matriz, etc.
class(mis_datos)
## [1] "data.frame"
# str: me muestra la estructura de los datos que estoy visualizando. Es útil para ver donde esta algo que luego necesito extraer o indexar.
str(mis_datos)
## 'data.frame': 129317 obs. of 4 variables:
## $ ID : int 11342 11359 11360 11361 11362 11363 11364 11366 11375 11377 ...
## $ Island : chr "Not assigned" "Southern Lesser Antilles" "Not assigned" "Not assigned" ...
## $ species : chr "aeneus" "aeneus" "aeneus" "aeneus" ...
## $ distance: chr "6.075" "8.194" "4.618" "4.382" ...
# dim: permite ver las dimensiones de mi objeto ya sea un dataframe o una matriz.
dim(mis_datos)
## [1] 129317 4
# length: es igual que el anterior pero solo para objetos tipo lista
length(mis_datos)
## [1] 4
#names: permite ver los nombres de las columnas
names(mis_datos)
## [1] "ID" "Island" "species" "distance"
Ahora carguemos el mismo archivo pero que cada fila tenga un nombre único usando la primera columna (ID).
mis_datos <- read.csv("./Tablas/distancias_islas_caribe.csv", header=TRUE, row.names=1)
Ahora carguemos otro archivo con datos para unas especies
datos <- read.csv("./Tablas/areas_nichos.csv", header = TRUE, row.names = 1)
Hasta ahora hemos aprendido a cargar archivos en formato CSV y a visualizar sus dimensiones y estructura. Ahora pasaremos a una de las cosas más importante de trabajar con R que es la INDEXACIÓN. La indexación es clave para aprender a dominar R.
Primero, vamos a generar un vector númerico a partir del segundo archivo que subimos (datos)
var1 <- datos[,1]
head(var1)
## [1] 5.373085 4.209303 12.610739 6.441746 2.915383 9.306049
dim(var1)
## NULL
class(var1)
## [1] "numeric"
length(var1)
## [1] 131
Queremos asignarle los nombres de las especies a cada valor del vector númerico
names(var1)<-row.names(datos)
Ahora vamos a indexar cada una de las variables del primer archivo (mis_datos):
# voy a indexar la columna 2 y 3.
variables1 <- mis_datos[,c(2,3)]
# indexar la columna 1 y 3
variables2 <- mis_datos[,c(1,3)]
# indexar de la columna 2 a la 3 de forma continua.
variables3 <- mis_datos[,c(2:3)]
Voy a convertir el objeto lista en un dataframe
dataframe1 <- as.data.frame(variables1)
class(dataframe1)
## [1] "data.frame"
Ahora de dataframe a lista
data.list1 <- as.list(variables1)
class(data.list1)
## [1] "list"
De dataframe a matriz
vars.matrix <- as.matrix(variables1)
vars.matrix[1:100] # voy a visualizar los primeros 100 datos de esta matriz.
## [1] "aeneus" "aeneus" "aeneus" "aeneus" "aeneus" "aeneus"
## [7] "aeneus" "aeneus" "aeneus" "aeneus" "aeneus" "aeneus"
## [13] "aeneus" "aeneus" "aeneus" "aeneus" "aeneus" "aeneus"
## [19] "aeneus" "aeneus" "aeneus" "aeneus" "aeneus" "aeneus"
## [25] "ahli" "ahli" "ahli" "ahli" "ahli" "ahli"
## [31] "ahli" "ahli" "ahli" "ahli" "ahli" "ahli"
## [37] "ahli" "ahli" "ahli" "ahli" "ahli" "ahli"
## [43] "ahli" "ahli" "ahli" "ahli" "ahli" "ahli"
## [49] "ahli" "ahli" "ahli" "ahli" "ahli" "ahli"
## [55] "ahli" "ahli" "ahli" "ahli" "ahli" "ahli"
## [61] "ahli" "ahli" "ahli" "ahli" "ahli" "ahli"
## [67] "ahli" "ahli" "ahli" "ahli" "ahli" "ahli"
## [73] "ahli" "ahli" "ahli" "ahli" "ahli" "aliniger"
## [79] "aliniger" "aliniger" "aliniger" "aliniger" "aliniger" "aliniger"
## [85] "aliniger" "aliniger" "aliniger" "aliniger" "aliniger" "aliniger"
## [91] "aliniger" "aliniger" "aliniger" "aliniger" "aliniger" "aliniger"
## [97] "aliniger" "aliniger" "aliniger" "aliniger"
Ahora empezaremos a jugar con las tablas. Vamos a UNIR tres tablas diferentes con base en una columna en común.
especies <- read.csv("./Tablas/datos_especies_islas.csv")
areas <- read.csv("./Tablas/areas_islas.csv")
distancias <- read.csv("./Tablas/distancias.csv")
Concatenar dos tablas - dos dataframes-
especies.areas <- merge(especies, areas, by="Islands")
Concatenar esta tabla nueva con la de distancias
spp.areas.dist <- merge(especies.areas, distancias, by="species")
Ahora vamos a indexar por subconjuntos (subsets)
dactyloa <- subset(spp.areas.dist, clades=="Dactyloa")
homolechis <- subset(spp.areas.dist, species=="homolechis")
Miremos como podemos indexar una columna de dos formas diferentes
dist.homo1 <- homolechis[,7]
dist.homo2 <- homolechis$distancias
Para evitar que se convierta en factor usar lo siguiente:
dist.homo <- as.numeric(as.vector(homolechis$distancias))
Algunas estadísticas y gráficas básicas en R
# Histograma de frecuencias
hist(dist.homo)
mean(dist.homo)
## [1] 3.917335
min(dist.homo)
## [1] 1.233
max(dist.homo)
## [1] 29.516
sd(dist.homo)
## [1] 1.909522
var(dist.homo)
## [1] 3.646274
Vamos a indexar el promedio
a <- mean(dist.homo)
Guardar y cargar un objeto de R (RData)
save.image("misDatos.RData")
load("misDatos.RData")
Gráficas sencillas y transformación de datos
hist(dist.homo, main="histograma",xlab="distancias", ylab="frecuencias")
Transformación logarítmica
log.dist <- log(dist.homo)
hist(log.dist, main="histograma", xlab="distancias")
Correlaciones y regresión lineal
cor(datos$nicho, datos$area)
## [1] 0.09052859
# primero x y luego y
plot(datos$nicho, datos$area)
Modelo de regresión lineal
reg.l <- lm(datos$nicho~datos$area)
Hacer un histograma de los residuales Usaré la indexación de los residuales del objeto reg.l con el simbolo de $
hist(reg.l$residuals)
Gŕafica de las dos variables
plot(datos$area, datos$nicho)
Voy a crear una columna nueva que contenga los valores de la variable “nicho” pero transformados con log10
datos["logNicho"] <- log(datos$nicho)
plot(datos$area, datos$logNicho)
Vuelvo a hacer el modelo de regresión lineal, pero con la nueva variable
reg.l2 <- lm(datos$logNicho~datos$area)
reg.l2
##
## Call:
## lm(formula = datos$logNicho ~ datos$area)
##
## Coefficients:
## (Intercept) datos$area
## 1.75181 0.03249
Extraigo los valores de la línea de tendencia (intercepto y la pendiente). Uso str para saber donde están.
str(reg.l2)
## List of 12
## $ coefficients : Named num [1:2] 1.7518 0.0325
## ..- attr(*, "names")= chr [1:2] "(Intercept)" "datos$area"
## $ residuals : Named num [1:131] -0.2301 -0.4484 0.6436 -0.0346 -0.8426 ...
## ..- attr(*, "names")= chr [1:131] "1" "2" "3" "4" ...
## $ effects : Named num [1:131] -21.1738 -0.4626 0.6935 0.0209 -0.7738 ...
## ..- attr(*, "names")= chr [1:131] "(Intercept)" "datos$area" "" "" ...
## $ rank : int 2
## $ fitted.values: Named num [1:131] 1.91 1.89 1.89 1.9 1.91 ...
## ..- attr(*, "names")= chr [1:131] "1" "2" "3" "4" ...
## $ assign : int [1:2] 0 1
## $ qr :List of 5
## ..$ qr : num [1:131, 1:2] -11.4455 0.0874 0.0874 0.0874 0.0874 ...
## .. ..- attr(*, "dimnames")=List of 2
## .. .. ..$ : chr [1:131] "1" "2" "3" "4" ...
## .. .. ..$ : chr [1:2] "(Intercept)" "datos$area"
## .. ..- attr(*, "assign")= int [1:2] 0 1
## ..$ qraux: num [1:2] 1.09 1.07
## ..$ pivot: int [1:2] 1 2
## ..$ tol : num 1e-07
## ..$ rank : int 2
## ..- attr(*, "class")= chr "qr"
## $ df.residual : int 129
## $ xlevels : Named list()
## $ call : language lm(formula = datos$logNicho ~ datos$area)
## $ terms :Classes 'terms', 'formula' language datos$logNicho ~ datos$area
## .. ..- attr(*, "variables")= language list(datos$logNicho, datos$area)
## .. ..- attr(*, "factors")= int [1:2, 1] 0 1
## .. .. ..- attr(*, "dimnames")=List of 2
## .. .. .. ..$ : chr [1:2] "datos$logNicho" "datos$area"
## .. .. .. ..$ : chr "datos$area"
## .. ..- attr(*, "term.labels")= chr "datos$area"
## .. ..- attr(*, "order")= int 1
## .. ..- attr(*, "intercept")= int 1
## .. ..- attr(*, "response")= int 1
## .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
## .. ..- attr(*, "predvars")= language list(datos$logNicho, datos$area)
## .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
## .. .. ..- attr(*, "names")= chr [1:2] "datos$logNicho" "datos$area"
## $ model :'data.frame': 131 obs. of 2 variables:
## ..$ datos$logNicho: num [1:131] 1.68 1.44 2.53 1.86 1.07 ...
## ..$ datos$area : num [1:131] 4.92 4.12 4.28 4.48 4.95 ...
## ..- attr(*, "terms")=Classes 'terms', 'formula' language datos$logNicho ~ datos$area
## .. .. ..- attr(*, "variables")= language list(datos$logNicho, datos$area)
## .. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
## .. .. .. ..- attr(*, "dimnames")=List of 2
## .. .. .. .. ..$ : chr [1:2] "datos$logNicho" "datos$area"
## .. .. .. .. ..$ : chr "datos$area"
## .. .. ..- attr(*, "term.labels")= chr "datos$area"
## .. .. ..- attr(*, "order")= int 1
## .. .. ..- attr(*, "intercept")= int 1
## .. .. ..- attr(*, "response")= int 1
## .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
## .. .. ..- attr(*, "predvars")= language list(datos$logNicho, datos$area)
## .. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
## .. .. .. ..- attr(*, "names")= chr [1:2] "datos$logNicho" "datos$area"
## - attr(*, "class")= chr "lm"
Los voy a indexar…
intercepto <- reg.l2$coefficients[1] # intercepto en Y
pendiente <- reg.l2$coefficients[2] # pendiente
Hago la gráfica con la línea de ajuste
plot(datos$area, datos$logNicho)
abline(a=intercepto, b=pendiente)
La misma gráfica pero le pongo las etiquetas a los ejes
plot(datos$area, datos$logNicho, xlab="Area", ylab="Nicho")
abline(a=intercepto, b=pendiente)
EJERCICIO # 1 (van a usar lo aprendido)
Hagamos lo mismo, pero con un conjunto de datos más grandes.
datos_grandes <- spp.areas.dist
datos_grandes["log_Temp"]<- NA
Extraigo los datos de distancias
nichos <- as.numeric(as.vector(datos_grandes$distancias))
## Warning: NAs introduced by coercion
Transformación logarítmica
log_temp<-log(nichos)
Ahora se los pego a mis datos
datos_grandes$log_Temp <- log_temp
TAREA:
Ahora cada uno debe hacer la regresión y gráficar con la línea de ajuste del modelo.
Existen varias librerias de R para el análisis de datos meteorológicos. Vamos a usar una muy común que se llama “climate”. Este paquete permite automatizar la descarga de datos de varios repositorios disponibles públicamente.
OGIMET (ogimet.com) University of Wyoming - atmospheric vertical profiling data (http://weather.uwyo.edu/upperair/).
National Oceanic & Atmospheric Administration - Earth System Research Laboratory - Global Monitoring Division (NOAA)
# install.packages(c("climate", "dplyr", "tidyr))
library(climate)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(tidyr)
ns <- nearest_stations_ogimet(country ="Mexico",
point = c(-4, 56),
no_of_stations = 100,
add_map = TRUE)
## [1] "http://ogimet.com/cgi-bin/gsynres?lang=en&state=Mexico&osum=no&fmt=html&ord=REV&ano=2022&mes=06&day=27&hora=06&ndays=1&Send=send"
## /tmp/RtmpBpIN9C/file127c66e3cf16
# Vemos el encabezado
head(ns)
## wmo_id station_names lon lat alt distance [km]
## 43 76647 Valladolid, Yuc. -88.21667 20.70001 22 10245.31
## 56 76698 Felipe Carrillo Puerto, Q. Roo. -88.03333 19.58335 20 10275.51
## 61 76750 Chetumal, Q. Roo -88.30001 18.48334 9 10352.53
## 36 76593 Progreso, Yuc. -89.65001 21.26667 2 10369.75
## 42 76644 Merida / lic Manuel Crecencio -89.65001 20.93335 10 10383.86
## 55 76695 Campeche, Camp. -90.50001 19.83335 5 10519.17
PL = stations_ogimet(country = "Mexico", add_map = TRUE)
## [1] "http://ogimet.com/cgi-bin/gsynres?lang=en&state=Mexico&osum=no&fmt=html&ord=REV&ano=2022&mes=06&day=27&hora=06&ndays=1&Send=send"
## /tmp/RtmpBpIN9C/file127c67716d3fb
Descargar datos por hora en un año aleatorio de Ogimet para la Ciudad de México. Primero buscar el ID de la estación https://www1.ncdc.noaa.gov/pub/data/noaa/isd-history.txt
# Descarga de datos del servicio de la NOAA.
df = meteo_noaa_hourly(station = "766800-99999",
year = sample(2000:2020, 1))
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2017/766800-99999-2017.gz"
## /tmp/RtmpBpIN9C/file127c659a5ae82
head(df)
## date year month day hour lon lat alt t2m dpt2m ws wd
## 1 2017-01-01 00:00:00 2017 1 1 0 -99.183 19.4 2303 18.8 11.1 3 230
## 2 2017-01-01 03:00:00 2017 1 1 3 -99.183 19.4 2303 15.9 10.4 2 50
## 3 2017-01-01 09:00:00 2017 1 1 9 -99.183 19.4 2303 12.8 9.6 1 140
## 4 2017-01-01 12:00:00 2017 1 1 12 -99.183 19.4 2303 11.2 8.5 1 180
## 5 2017-01-01 18:00:00 2017 1 1 18 -99.183 19.4 2303 18.5 10.9 1 80
## 6 2017-01-01 21:00:00 2017 1 1 21 -99.183 19.4 2303 23.2 13.0 3 180
## slp visibility
## 1 1008.7 5000
## 2 1009.5 4000
## 3 1011.1 2000
## 4 1013.0 1000
## 5 1015.0 1000
## 6 1010.0 2000
hist(df$t2m, main="CDMX 2020", xlab="Temperatura horaria", ylab="Frecuencia")
# Exploramos cómo están los datos
sapply(df, class)
## $date
## [1] "POSIXct" "POSIXt"
##
## $year
## [1] "integer"
##
## $month
## [1] "integer"
##
## $day
## [1] "integer"
##
## $hour
## [1] "integer"
##
## $lon
## [1] "numeric"
##
## $lat
## [1] "numeric"
##
## $alt
## [1] "integer"
##
## $t2m
## [1] "numeric"
##
## $dpt2m
## [1] "numeric"
##
## $ws
## [1] "numeric"
##
## $wd
## [1] "integer"
##
## $slp
## [1] "numeric"
##
## $visibility
## [1] "integer"
# Indexamos la variable de temperatura y excluimos los datos faltantes (NAs)
temp <- na.omit(df$t2m)
hist(temp)
# Sacar la temperatura máxima horaria para el 2020
max(temp)
## [1] 32.4
# Temperatura mínima
min(temp)
## [1] 0.3
plot(temp)
# Ahora vamos a descargar 10 años de datos para la misma estación
df2 = meteo_noaa_hourly(station = "766800-99999",
year = c(2010:2020))
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2010/766800-99999-2010.gz"
## /tmp/RtmpBpIN9C/file127c63131c708
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2011/766800-99999-2011.gz"
## /tmp/RtmpBpIN9C/file127c6d2f43c5
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2012/766800-99999-2012.gz"
## /tmp/RtmpBpIN9C/file127c66763536
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2013/766800-99999-2013.gz"
## /tmp/RtmpBpIN9C/file127c668c303ee
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2014/766800-99999-2014.gz"
## /tmp/RtmpBpIN9C/file127c62d2abc74
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2015/766800-99999-2015.gz"
## /tmp/RtmpBpIN9C/file127c6156fa9ce
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2016/766800-99999-2016.gz"
## /tmp/RtmpBpIN9C/file127c644b9d09e
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2017/766800-99999-2017.gz"
## /tmp/RtmpBpIN9C/file127c695181f8
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2018/766800-99999-2018.gz"
## /tmp/RtmpBpIN9C/file127c65ae98d0a
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2019/766800-99999-2019.gz"
## /tmp/RtmpBpIN9C/file127c64a41c758
## [1] "https://www1.ncdc.noaa.gov/pub/data/noaa/2020/766800-99999-2020.gz"
## /tmp/RtmpBpIN9C/file127c6491c501
head(df2)
## date year month day hour lon lat alt t2m dpt2m ws wd
## 1 2010-01-01 00:00:00 2010 1 1 0 -99.183 19.4 2303 20.3 8.9 1 140
## 2 2010-01-01 03:00:00 2010 1 1 3 -99.183 19.4 2303 17.0 9.7 2 50
## 3 2010-01-02 06:00:00 2010 1 2 6 -99.183 19.4 2303 10.6 10.3 1 360
## 4 2010-01-02 09:00:00 2010 1 2 9 -99.183 19.4 2303 9.4 9.1 1 90
## 5 2010-01-02 12:00:00 2010 1 2 12 -99.183 19.4 2303 9.0 8.7 1 180
## 6 2010-01-04 06:00:00 2010 1 4 6 -99.183 19.4 2303 10.0 9.7 1 360
## slp visibility
## 1 1008.6 8000
## 2 1011.9 8000
## 3 1012.6 8000
## 4 1012.5 6000
## 5 1011.9 6000
## 6 1013.2 10000
temp2 <- df2$t2m
hist(temp2)
temp_mensual = df2 %>%
group_by(month) %>%
summarise(tmax = max(t2m, na.rm = TRUE),
tmin = min(t2m, na.rm = TRUE),
tavg = mean(t2m, na.rm = TRUE))
https://www.ruoa.unam.mx/pembu/index.php?page=historical_facts
datos = read.csv("./Datos_Estaciones/2018-CCA-L1/2018-01-CCA-L1.CSV", skip = 8, header = T)
datos <- datos[,c(1:2)]
colnames(datos) <- c("Fecha_hora", "Temp")
sapply(datos, class)
## Fecha_hora Temp
## "character" "character"
datos$Temp <- as.numeric(datos$Temp)
## Warning: NAs introduced by coercion
sapply(datos, class)
## Fecha_hora Temp
## "character" "numeric"
head(datos)
## Fecha_hora Temp
## 1 2018/01/01 00:00:00 NA
## 2 2018/01/01 00:30:00 12.7
## 3 2018/01/01 01:00:00 12.8
## 4 2018/01/01 01:30:00 12.3
## 5 2018/01/01 02:00:00 12.5
## 6 2018/01/01 02:30:00 12.6
# Los datos de las estaciones se toman cada media hora (48 observaciones por mes)
dim(datos)
## [1] 1488 2
t <- 1488/31
# agrupar por días
t2 <- split(seq_len(1488), rep(1:31, each=48))
# separar los días del mes de enero
datos2 <- lapply(1:31, function(x) datos[t2[[x]],])
# calcular el promedio diario
temp.mean.diaria <- lapply(1:31, function(x) mean(datos2[[x]][,2], na.rm=TRUE))
temp.mean.diaria <- unlist(temp.mean.diaria)
hist(temp.mean.diaria)
plot(temp.mean.diaria, xlab="días")
# Calcular el mínimo diario
temp.min.diaria <- lapply(1:31, function(x) min(datos2[[x]][,2], na.rm=TRUE))
temp.min.diaria <- unlist(temp.min.diaria)
hist(temp.min.diaria)
plot(temp.min.diaria, xlab="días")
# Calcular el máximo diario
temp.max.diaria <- lapply(1:31, function(x) max(datos2[[x]][,2], na.rm=TRUE))
temp.max.diaria <- unlist(temp.max.diaria)
hist(temp.max.diaria)
plot(temp.max.diaria, xlab="días")
Aquí empezaremos con algunos ejercicios para trabajar con objetos espaciales y hacer algunos mapas básicos. Vamos a generar unos datos aleatorios de coordenadas geográficas y de precipitación.
name <- LETTERS[1:10]
longitud <- c(-116.7, -120.4, -116.7, -113.5, -115.5,
-120.8, -119.5, -113.7, -113.7, -110.7)
latitud <- c(45.3, 42.6, 38.9, 42.1, 35.7, 38.9,
36.2, 39, 41.6, 36.9)
estaciones <- cbind(longitud, latitud)
# Simular datos de precipitación
set.seed(0)
# función runif: sirve para generar valores aleatorios siguiendo una distribución uniforme
precip <- (runif(length(latitud))*10)^3
Ahora vamos a gráficar estos datos y el tamaño de los puntos será proporcional a la cantidad de precipitación.
psize <- 1 + precip/500
plot(estaciones, cex=psize, pch=20, col='red', main='Precipitación')
# adicionarle los nombres a la gráfica
text(estaciones, name, pos=4)
# adicionar una leyenda
breaks <- c(100, 500, 1000, 2000)
legend("topright", legend=breaks, pch=20, pt.cex=psize, col='red', bg='gray')
Puntos espaciales:
Vamos a generar vectores con datos de longitud y latitud, y luego los combinamos.
longitude <- c(-116.7, -120.4, -116.7, -113.5, -115.5, -120.8, -119.5, -113.7, -113.7, -110.7)
latitude <- c(45.3, 42.6, 38.9, 42.1, 35.7, 38.9, 36.2, 39, 41.6, 36.9)
lonlat <- cbind(longitude, latitude)
Vamos a usar el paquete “sp”. D Debemos instalarlo usando la función install.packages(“sp”) y luego cargarlo con library(sp)
library(sp)
pts <- SpatialPoints(lonlat)
¿Qué clase de objeto es?
class(pts)
## [1] "SpatialPoints"
## attr(,"package")
## [1] "sp"
Exploramos que tiene
showDefault(pts)
## An object of class "SpatialPoints"
## Slot "coords":
## longitude latitude
## [1,] -116.7 45.3
## [2,] -120.4 42.6
## [3,] -116.7 38.9
## [4,] -113.5 42.1
## [5,] -115.5 35.7
## [6,] -120.8 38.9
## [7,] -119.5 36.2
## [8,] -113.7 39.0
## [9,] -113.7 41.6
## [10,] -110.7 36.9
##
## Slot "bbox":
## min max
## longitude -120.8 -110.7
## latitude 35.7 45.3
##
## Slot "proj4string":
## Coordinate Reference System:
## Deprecated Proj.4 representation: NA
## Warning in wkt(x): CRS object has no comment
El sistema de coordenadas de referencia de nuestro objeto espacial no está definido. Vamos a definirlo con la ayuda de la función CRS
crdref <- CRS('+proj=longlat +datum=WGS84')
pts <- SpatialPoints(lonlat, proj4string=crdref)
Cargamos el paquete raster
library(raster)
##
## Attaching package: 'raster'
## The following object is masked from 'package:dplyr':
##
## select
pts
## class : SpatialPoints
## features : 10
## extent : -120.8, -110.7, 35.7, 45.3 (xmin, xmax, ymin, ymax)
## crs : +proj=longlat +datum=WGS84 +no_defs
Vamos a generar (inventar) unos datos de precipitación asociados a esas coordenadas. Estos datos NO son reales, es solo para mostrar como podemos visualizarlos como objetos espaciales.
df <- data.frame(ID=1:nrow(lonlat), precip=(latitude-30)^3)
Combinamos los datos espaciales y los datos de precipitación
ptsdf <- SpatialPointsDataFrame(pts, data=df)
ptsdf
## class : SpatialPointsDataFrame
## features : 10
## extent : -120.8, -110.7, 35.7, 45.3 (xmin, xmax, ymin, ymax)
## crs : +proj=longlat +datum=WGS84 +no_defs
## variables : 2
## names : ID, precip
## min values : 1, 185.193
## max values : 10, 3581.577
Vemos que tiene ese objeto espacial
str(ptsdf)
## Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
## ..@ data :'data.frame': 10 obs. of 2 variables:
## .. ..$ ID : int [1:10] 1 2 3 4 5 6 7 8 9 10
## .. ..$ precip: num [1:10] 3582 2000 705 1772 185 ...
## ..@ coords.nrs : num(0)
## ..@ coords : num [1:10, 1:2] -117 -120 -117 -114 -116 ...
## .. ..- attr(*, "dimnames")=List of 2
## .. .. ..$ : NULL
## .. .. ..$ : chr [1:2] "longitude" "latitude"
## ..@ bbox : num [1:2, 1:2] -120.8 35.7 -110.7 45.3
## .. ..- attr(*, "dimnames")=List of 2
## .. .. ..$ : chr [1:2] "longitude" "latitude"
## .. .. ..$ : chr [1:2] "min" "max"
## ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
## .. .. ..@ projargs: chr "+proj=longlat +datum=WGS84 +no_defs"
## .. .. ..$ comment: chr "GEOGCRS[\"unknown\",\n DATUM[\"World Geodetic System 1984\",\n ELLIPSOID[\"WGS 84\",6378137,298.25722"| __truncated__
También podemos verlos así:
showDefault(ptsdf)
## An object of class "SpatialPointsDataFrame"
## Slot "data":
## ID precip
## 1 1 3581.577
## 2 2 2000.376
## 3 3 704.969
## 4 4 1771.561
## 5 5 185.193
## 6 6 704.969
## 7 7 238.328
## 8 8 729.000
## 9 9 1560.896
## 10 10 328.509
##
## Slot "coords.nrs":
## numeric(0)
##
## Slot "coords":
## longitude latitude
## [1,] -116.7 45.3
## [2,] -120.4 42.6
## [3,] -116.7 38.9
## [4,] -113.5 42.1
## [5,] -115.5 35.7
## [6,] -120.8 38.9
## [7,] -119.5 36.2
## [8,] -113.7 39.0
## [9,] -113.7 41.6
## [10,] -110.7 36.9
##
## Slot "bbox":
## min max
## longitude -120.8 -110.7
## latitude 35.7 45.3
##
## Slot "proj4string":
## Coordinate Reference System:
## Deprecated Proj.4 representation: +proj=longlat +datum=WGS84 +no_defs
## WKT2 2019 representation:
## GEOGCRS["unknown",
## DATUM["World Geodetic System 1984",
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]],
## ID["EPSG",6326]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433],
## ID["EPSG",8901]],
## CS[ellipsoidal,2],
## AXIS["longitude",east,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433,
## ID["EPSG",9122]]],
## AXIS["latitude",north,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433,
## ID["EPSG",9122]]]]
Líneas y polígonos espaciales. Hacer puntos espaciales es bastante fácil. Hacer líneas y polígonos es un poco más complicado pero vamos a usar las funciones SpatialLines y SpatialPolygons para esto.
lon <- c(-116.8, -114.2, -112.9, -111.9, -114.2, -115.4, -117.7)
lat <- c(41.3, 42.9, 42.4, 39.8, 37.6, 38.3, 37.6)
lonlat <- cbind(lon, lat)
lns <- spLines(lonlat, crs=crdref)
lns
## class : SpatialLines
## features : 1
## extent : -117.7, -111.9, 37.6, 42.9 (xmin, xmax, ymin, ymax)
## crs : +proj=longlat +datum=WGS84 +no_defs
Graficamos nuestro objeto de líneas
plot(lns)
Creamos un shapefile (polígono) con los puntos
pols <- spPolygons(lonlat, crs=crdref)
pols
## class : SpatialPolygons
## features : 1
## extent : -117.7, -111.9, 37.6, 42.9 (xmin, xmax, ymin, ymax)
## crs : +proj=longlat +datum=WGS84 +no_defs
Graficamos el polígono
plot(pols, axes=TRUE, las=1)
plot(pols, border='blue', col='yellow', lwd=3, add=TRUE)
points(pts, col='red', pch=20, cex=3)
El paquete sp permite trabajar con archivos de clase SpatialGridDataFrame y SpatialPixelsDataFrame. Estos archivos son archivos que usamos muy a menudo en operaciones espaciales y SIG. De aquí en adelante nos vamos a empezar a usar el paqute raster para trabajar con archivo tipo raster (celdas). Con este paquete podemos hacer operaciones matemáticas con rasters y un sinnúmero de otros procesos que se usan en programas dedicadas a SIG (e.g., ArcGIS, QGIS, etc.).
¿Qué es un capa de tipo raster? Un RasterLayer es un objeto de R que contiene datos de una sola variables. Como vimos en la clase este objeto debe tener información del número de celdas, hileras (rows) y columnas (columns), la extensión geográfica o espacial (x, y - min-, -max-) y lo más importante en SIG: el sistema de coordenadas de referencia.
library(raster)
r <- raster(ncol=10, nrow=10, xmx=-80, xmn=-150, ymn=20, ymx=60)
r
## class : RasterLayer
## dimensions : 10, 10, 100 (nrow, ncol, ncell)
## resolution : 7, 4 (x, y)
## extent : -150, -80, 20, 60 (xmin, xmax, ymin, ymax)
## crs : +proj=longlat +datum=WGS84 +no_defs
values(r) <- runif(ncell(r))
r
## class : RasterLayer
## dimensions : 10, 10, 100 (nrow, ncol, ncell)
## resolution : 7, 4 (x, y)
## extent : -150, -80, 20, 60 (xmin, xmax, ymin, ymax)
## crs : +proj=longlat +datum=WGS84 +no_defs
## source : memory
## names : layer
## values : 0.01339033, 0.9926841 (min, max)
Ahora podemos gráficar y ver como sale nuestro raster
plot(r)
Ahora vamos a subir unas capas climáticas que tenemos guardadas en nuestro computador.
capas <- list.files(path="./Bioclimaticos/", pattern=".tif", full.names = T)
capas <- stack(capas)
capas
## class : RasterStack
## dimensions : 180, 360, 64800, 19 (nrow, ncol, ncell, nlayers)
## resolution : 1, 1 (x, y)
## extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
## crs : NA
## names : bio_01, bio_02, bio_03, bio_04, bio_05, bio_06, bio_07, bio_08, bio_09, bio_10, bio_11, bio_12, bio_13, bio_14, bio_15, ...
## min values : -234.128322, 9.500000, 9.396564, 68.000000, -55.126503, -525.923628, 53.489130, -237.702800, -432.567114, -91.281594, -471.184995, 0.000000, 0.000000, 0.000000, 0.000000, ...
## max values : 313.0625, 195.2251, 95.0000, 22549.9589, 484.3726, 258.0000, 722.3212, 369.2097, 355.0000, 375.4345, 288.8571, 6995.0284, 1482.7247, 345.1818, 215.9236, ...
Ahora vamos a graficar una sola capa climática (bio1)
plot(capas[[1]])
Operaciones básicas con rasters
promedio_bio1 <- cellStats(capas[[1]], 'mean')
promedio_bio12 <- cellStats(capas[[12]], 'mean')
Vamos a jugar un poco con shapefiles y rasters
library(rgdal)
## Please note that rgdal will be retired by the end of 2023,
## plan transition to sf/stars/terra functions using GDAL and PROJ
## at your earliest convenience.
##
## rgdal: version: 1.5-32, (SVN revision 1176)
## Geospatial Data Abstraction Library extensions to R successfully loaded
## Loaded GDAL runtime: GDAL 3.4.3, released 2022/04/22
## Path to GDAL shared files: /usr/share/gdal
## GDAL binary built with GEOS: TRUE
## Loaded PROJ runtime: Rel. 8.2.0, November 1st, 2021, [PJ_VERSION: 820]
## Path to PROJ shared files: /home/juvelas/.local/share/proj:/usr/share/proj
## PROJ CDN enabled: FALSE
## Linking to sp version:1.4-7
## To mute warnings of possible GDAL/OSR exportToProj4() degradation,
## use options("rgdal_show_exportToProj4_warnings"="none") before loading sp or rgdal.
ame1 <- readOGR(dsn="./Shapefile", layer="cont_america")
## OGR data source with driver: ESRI Shapefile
## Source: "/mnt/tb/DD/Dropbox/Curso_PEMBU/Shapefile", layer: "cont_america"
## with 28 features
## It has 1 fields
ame2 <- readOGR("./Shapefile/cont_america.shp")
## OGR data source with driver: ESRI Shapefile
## Source: "/mnt/tb/DD/Dropbox/Curso_PEMBU/Shapefile/cont_america.shp", layer: "cont_america"
## with 28 features
## It has 1 fields
plot(ame1)
plot(ame2)
Vamos a indexar un país y luego cortar las capas climáticas para ese país
head(ame1)
## PAÍS
## 0 Aruba (Paises Bajos)
## 1 Argentina
## 2 Belice
## 3 Bolivia
## 4 Brasil
## 5 Canadá
mx <- subset(ame1, PAÍS=="México")
plot(mx)
Cortamos las capas usando la función mask. También podemos usar la función crop
# Usando mask
mx.clima <- raster::mask(capas, mx)
plot(mx.clima[[1]])
# Usando crop
mx.clima.v2 <- raster::crop(capas, mx)
plot(mx.clima.v2[[1]])
Lo ideal es primero crop y luego mask
mx.clima.v3 <- crop(capas, mx)
mx.clima.v3 <- mask(mx.clima.v3, mx)
plot(mx.clima.v3[[1]])
Agregarle el mapa de México como contorno
plot(mx.clima.v3[[1]])
plot(mx, add=T)
!Eso es todo por ahora!
Fuentes: Elaboración propia (Julián A. Velasco) y con rutinas adaptadas de: http://www.rspatial.org/intr/index.html (R. Hijmans, 2016) y https://cran.r-project.org/web/packages/climate/vignettes/getstarted.html (Czernecki, B.; Głogowski, A.; Nowosad, J. Climate: An R Package to Access Free In-Situ Meteorological and Hydrological Datasets for Environmental Assessment. Sustainability 2020, 12, 394. https://doi.org/10.3390/su12010394“)