Introducción al ambiente R

Esta página muestra 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.

# Direccionar un directorio-folder de trabajo
setwd("C:/Users/juvel/Dropbox/Cursos_Charlas/Iztacala_2018/Scripts/")

Subir un conjunto de datos en formato CSV (comma-separated-value). Estos archivos se pueden abrir con Excel.

mis_datos <- read.csv("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  : Factor w/ 9 levels "Cayman Islands",..: 6 8 6 6 6 6 6 6 6 6 ...
##  $ species : Factor w/ 80 levels "aeneus","ahli",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ distance: Factor w/ 10219 levels " NA","0.46","0.536",..: 6944 8975 5488 5252 5481 3649 3214 461 3201 336 ...
# 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("distancias_islas_caribe.csv", header=TRUE, row.names=1)

Ahora carguemos otro archivo con datos para unas especies

datos <- read.csv("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.

species <- read.csv("datos_especies_islas.csv")
areas <- read.csv("areas_islas.csv")
distancias <- read.csv("distancias.csv")

Concatenar dos tablas - dos dataframes-

species.areas <- merge(species, areas, by="Islands")

Concatenar esta tabla nueva con la de distancias

spp.areas.dist <- merge(species.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")

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)

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)

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

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"
intercepto <- reg.l2$coefficients[1] # intercepto en Y
pendiente <- reg.l2$coefficients[2] # pendiente

Ploteo con la línea de ajuste

plot(datos$area, datos$logNicho)
abline(a=intercepto, b=pendiente)

plot(datos$area, datos$logNicho, xlab="Area", ylab="Nicho")
abline(a=intercepto, b=pendiente)

EJERCICIO 1

Hagamos lo mismo, pero con un conjunto de datos más grandes.

datos_grandes <- spp.areas.dist
datos_grandes["log_Nichos"]<- NA

Extraigo los datos de distancias

nichos <- as.numeric(as.vector(datos_grandes$distancias))
## Warning: NAs introducidos por coerción

Transformación logarítmica

log_nichos<-log(nichos)

Ahora se los pego a mis datos

datos_grandes$log_Nichos <- log_nichos

Ahora cada uno debe hacer la regresión y gráficar con la línea de ajuste del modelo.

Ahora trabajaremos con archivos tipo ASCII (rasters) y localidades georeferenciadas.

library(raster)
## Loading required package: sp

Subo los datos de localidades de una especie

cardon <- read.csv("cardon.csv")

Cargo los archivos ASCII de la región

varclim <- list.files(path="./", pattern = "asc", full.names = TRUE)
varclim
## [1] "./bio12.asc" "./bio5.asc"  "./bio6.asc"

Hago un stack (una pila de rasters) con los tres archivos ascii

capas <- stack(varclim)

Puedo convertir las capas climáticas a puntos

puntos <- rasterToPoints(capas[[1]], fun=NULL, spatial=TRUE)

Extraigo los datos de cada capa climática de cada punto

bios_pts <- extract(capas, puntos)

Generamos un dataframe con las coordenadas geográficas

bios_pts <- data.frame(coordinates(puntos), bios_pts)
class(bios_pts)
## [1] "data.frame"

También se puede hacer de esta forma, pero hay una diferencia. ¿Cuál es?

pts <- rasterToPoints(capas[[1]], fun=NULL, spatial=TRUE)
bios_points <- extract(capas, pts)
coordinates<-coordinates(pts)
bios_points <- cbind(coordinates, bios_points)
class(bios_points)
## [1] "matrix"

Para cambiar de matriz a dataframe, ¿Cómo lo hago?

bios_points <- as.data.frame(bios_points)
class(bios_points)
## [1] "data.frame"

Veamos si son iguales los dos dataframes. Gráficamos ambas.

plot(bios_points$bio12, bios_pts$bio12)

Convertir el dataframe en un objeto espacial (tipo SIG). En este caso, convertiremos el archivo de coordenadas de una especie de cactus (Cardon) en una objeto espacial.

coordinates(cardon)=~LONGITUDE+LATITUDE
class(cardon)
## [1] "SpatialPointsDataFrame"
## attr(,"package")
## [1] "sp"

Extraer los datos climáticos para el Cardon

cardon_clima <- extract(capas, cardon)
cardon_clima <- data.frame(coordinates(cardon), cardon_clima)

Renombrar las columnas de un dataframe

library(plyr)
cardon_clima<-rename(cardon_clima, c("LONGITUDE"="x", "LATITUDE"="y"))

Adicionar una columna a un daframe con un identicador

cardon_clima["sitio"] <- "cardon"
bios_points["sitio"] <- "entorno"

Combinar los dos dataframes usando la misma columna nueva (sitio). Aunque ambos tienen diferentes filas es posible hacerlo porque tienen el mismo número de columnas.

cardon_entorno <- rbind(cardon_clima, bios_points)

Lo vuelvo objeto espacial y luego dataframe. Importante que aprendan esto para ir de un tipo de objeto en R a otro y poder hacer muchísimas cosas.

coordinates(cardon_entorno)=~x+y
cardon_entorno <- as.data.frame(cardon_entorno)

Eso es todo por ahora!

Escrito por Julián A. Velasco, 5 de Julio de 2018.

```