Introducción al análisis de datos ecológicos en R (1)

Seminario 1, Ecología I

Grado en Biología

Profesores

José Francisco Calvo Sendín

José Antonio Palazón Ferrando

Departamento

Ecología e Hidrología, Facultad de Biología

Fecha de publicación

8 de noviembre de 2023

Fecha de modificación

20 de febrero de 2024

Introducción

R es un software gratuito, y un lenguaje de programación, que constituye un entorno integrado de análisis de datos y elaboración de gráficos. A las ventajas que proporciona su carácter de proyecto de dominio público y multiplataforma, se añade la existencia de una enorme comunidad de usuarios y colaboradores que de forma constante crean bibliotecas o paquetes de funciones para todo tipo de análisis de datos. Todo ello ha convertido a R en una de las herramienta de análisis más utilizadas en el ámbito científico y académico.

En este seminario nos introduciremos en el manejo de R, con el objetivo de aprender las herramientas básicas para la introducción, manejo, visualización y análisis de datos ecológicos, que irán siendo utilizadas en otras sesiones de prácticas y seminarios de la asignatura Ecología I, Ecología II y Gestión y Conservación de Ecosistemas.

R puede descargarse desde la página https://cran.r-project.org/. A través de la web de la red CRAN (The Comprehensive R Archive Network) puede encontrarse también la documentación necesaria para iniciarse y profundizar en el uso de R, así como de sus bibliotecas o paquetes de funciones, creadas por una amplísima comunidad de programadores e investigadores de todos los ámbitos de las ciencias. El documento de Tors y Brauer (2014) y el libro de Paradis (2002) son muy recomendables para principiantes.

Primeros pasos en R

R está disponible en los ordenadores de la Aulas informáticas de la Universidad de Murcia, desde donde ejecutaremos la aplicación. Una vez iniciada, obtendremos la información básica sobre R y quedará a la espera de recibir una orden:

El signo (prompt) > en la última línea indica que podemos escribir una expresión. R la evaluará y actuará en consecuencia.

  • La expresión más sencilla es un número entero:

    2 
    [1] 2

R evalúa la expresión y nos devuelve el valor. La notación [1] indica la primera línea de valores de respuesta, en este caso con un único valor.

Las líneas de código de los recuadros sombreados de este documento pueden copiarse clicando en el icono que aparece en la parte superior derecha.

Los valores pueden relacionarse mediante operadores (algebráicos y lógicos) y funciones. Entre los operadores tenemos los siguientes:

+ - * / ^: suma, resta, producto, cociente, potencia

== != !: igual, distinto, no

> >= < <=: mayor que, mayor o igual que, menor que, menor o igual que

& |: y, o

<- -> :: asignar a la izquierda, asignar a la derecha, generar una serie

Cada operador implica a los dos elementos que se sitúan a izquierda y derecha en la expresión. El uso de espacios es opcional. Existe una jerarquía de operadores que determina cuál de ellos se evalúa primero. El orden puede alterarse mediante el uso de paréntesis. Por ejemplo:

9 * 5 / 2
9 * 5 / 2 * 3
9 * 5 / ( 2 * 3 )
9 * 5 / 2 / 3

Las expresiones anteriores efectúan las siguientes operaciones:

\[\frac{9 \times 5}{2} ,\quad \frac{9 \times 5 \times 3}{2}, \quad \frac{9 \times 5}{2 \times 3}\quad y \quad \frac{9 \times 5}{2 \times 3} \] Las expresiones se escriben normalmente en líneas distintas, pero pueden escribirse en la misma línea separadas por ;.

1 : 10; 10 : 1

También es posible escribir una expresión en más de una línea; así, cuando R evalúa que la expresión es incompleta devulve un prompt + en lugar del habitual >. En cualquier caso, podemos cancelar la escritura con la tecla ESC.

El uso de las flechas del teclado nos permite repetir o modificar expresiones ejecutadas previamente.

Los operadores lógicos proporcionan como resulatdo el valor TRUE (verdadero, que puede abreviarse como T) o FALSE (falso, que puede abreviarse como F):

3 != 2
5 < 3

Los datos lógicos pueden incluirse en operaciones, en las que adoptan los valores de 1 (TRUE) y 0 (FALSE):

TRUE + TRUE
1 : 10 > 4
( 1 : 10 > 4 ) * 1

Determinadas operaciones nos devuelven valores especiales, como indeterminaciones matemáticas (NaN, not a number), infinito (Inf) y menos infinito (-Inf):

0 / 0
1 / 0
-1 / 0

R utiliza la notación científica para números muy grandes o muy pequeños, y también trabaja con números complejos:

0.00001
10 ^ 6
( 2+3i ) * 2

Las funciones disponibles en R son numerosas, y permiten realizar diversos tipos de cálculos y análisis. Por ejemplo:

sqrt( 4 )
cos( pi )
log( 2 )
exp( 3 )
rnorm( 10 )
sum( 1 : 10 > 4 )

Podemos pedir información o ayuda sobre cualquier función usando ? pegado al nombre, o la función help:

?rnorm
help( sin )

R es un lenguaje “orientado a objetos”, lo que significa que podemos guardar en memoria datos, funciones y resultados en forma de objetos con un nombre específico (Paradis 2002). Para ello usaremos los operadores de asignación (<- y ->). Por ejemplo:

x <- 3.2
log10( x ) -> y
a <- "cadena de texto"
1 : 10 -> v
x; y; a; v

El símbolo = puede funcionar también como operador de asignación, pero solo en un sentido:

i = 1
i

Los nombres de los objetos deben comenzar obligatoriamente por una letra, y a continuación, opcionalmente, una combinación de letras y números, entre los que puede incorporarse el punto (.) y el guion bajo (_).

Para ver los objetos disponibles en memoria podemos usaremos ls(). Para eliminarlos usaremos la función rm:

ls()
rm( x, y, a, v, i)

Podemos borrar el contenido de la pantalla (no de la memoria) si tecleamos Ctrl-L.

Vectores

Los vectores son conjuntos ordenados de datos. Podemos crearlos utilizando el operador :, o diversas funciones, como seq o c (concatenar). Por ejemplo:

-5 : 4 -> x
seq( 1, 0.1 , by = -0.1 ) -> y
c( 12, 23, 32, 9, 15, NA, 18, 10, 15, 9 ) -> z
c( "h", "h", "m", "h", "m", "h", "h", "m", "m", "h" ) -> sexo
x; y; z; sexo

Observa que en la creación del vector z hemos introducido un NA, que es el valor específico que R utiliza para los valores no disponibles (Not Avalaible) o faltantes (missing). Observa también que podemos crear vectores de caracteres.

Podemos crear vectores con cualquier longitud. Por ejemplo:

rep( 1 : 10, 5) -> v1
rep( 1 : 10, each = 5 ) -> v2
v1
v2
rnorm( 50 ) -> v3
v3
round( v3, 3 )

Observa que cuando el resultado no cabe en una única línea, cada línea comienza por una notación entre corchetes que indica el número de orden en el vector correspondiente al primer valor de la línea (que varía dependiendo del tamaño de la ventana).

Con los vectores numéricos podemos realizar operaciones y aplicarles funciones:

x * y 
sqrt( x * 2 + log( z ) )
length( v3 )
abs( x )
sort( z )
table( sexo )

Cuando existen valores NA, muchas funciones requieren incluir el argumento na.rm = TRUE. De lo contrario, el resultado sería NA:

max( z )
mean( z )
max( z, na.rm = TRUE )
mean( z, na.rm = TRUE )

Podemos referirnos a un elemento concreto de un vector, o a un conjunto de ellos, indicando el valor del índice (su posición dentro del vector) entre corchetes:

z
z[ 3 ]
z[ -3 ]
z[ 1 : 3 ]
z[ -( 1 : 3 ) ]
z[ c( 1, 3, 6 ) ]
z[ -c( 1, 3, 6 ) ]

Utilizando operadores lógicos y diversas funciones podemos conocer qué elementos de un vector cumplen una determinada condición:

x > 0
is.na( z )
which( v3 == min( v3 ) )
which( sexo == "h" )

Matrices

Las matrices son conjuntos de valores organizados en filas y columnas. Podemos generarlas uniendo vectores por columnas (usando la función cbind), por filas (usando la función rbind) o con funciones como `matrix´. Por ejemplo:

cbind( x, y, z )
rbind( z, y, x )
matrix( c( x, y, z ), 10, 3 ) -> mat
mat

Para trasponer una matriz utilizaremos la función t, y para conocer sus dimensiones podemos usar nrow, ncol y dim:

t( mat )
nrow( mat )
ncol( mat )
dim( mat )

La selección de elementos de las matrices se realiza utilizando los corchetes, de manera similar que con los vectores, pero considerando dos índices (el primero para las filas y el segundo para las columnas) separados por una coma. Si no se incluye el primer índice nos referiremos a una columna; si no se incluye el segundo, nos referiremos a una fila.

mat[ 2, 3]
mat[ , 3 ]
mat[ 2, ]
mat[ , 2 : 3 ]
mat[ c( 2, 4, 7 ), ]

Para realizar operaciones con matrices y vectores podemos emplear diversos operadores, incluido el producto matricial (%*%). Así, para realizar en R la operación

\[\mathbf{n}(t + 1) = \mathbf{A}(t) \mspace{6mu}\mathbf{n}(t) = \begin{bmatrix} a_{11}(t) & a_{12}(t) & a_{13}(t) \\ a_{21}(t) & a_{22}(t) & a_{23}(t) \\ a_{31}(t) & a_{32}(t) & a_{33}(t) \end{bmatrix}\left\lbrack \begin{array}{r} n_{1}(t) \\ n_{2}(t) \\ n_{3}(t) \end{array} \right\rbrack\]

que corresponde a un modelo de crecimiento de poblaciones estructuradas (Ecología I, tema 9), y cuyo resultado es

\[\left\lbrack \begin{array}{r} n_{1}(t + 1) \\ n_{2}(t + 1) \\ n_{3}(t + 1) \end{array} \right\rbrack = \begin{bmatrix} a_{11}(t)\mspace{6mu} n_{1}(t) + a_{12}(t)\mspace{6mu} n_{2}(t) + a_{13}(t)\mspace{6mu} n_{3}(t) \\ a_{21}(t)\mspace{6mu} n_{1}(t) + a_{22}(t)\mspace{6mu} n_{2}(t) + a_{23}(t)\mspace{6mu} n_{3}(t) \\ a_{31}(t)\mspace{6mu} n_{1}(t) + a_{32}(t)\mspace{6mu} n_{2}(t) + a_{33}(t)\mspace{6mu} n_{3}(t) \end{bmatrix}\]

ejecutaremos, por ejemplo:

n <- c( 23.5, 14.2, 7.3 )
A <- matrix( c ( 0.02115, 0.0740, 0.0846,
                 0.56300, 0.0000, 0.0000,
                 0.00000, 0.5630, 0.5630 ), 3, 3, byrow = TRUE )
A %*% n

Tablas de datos

Las tablas de datos en R (data frames) son similares a las matrices, pero permiten almacenar variables con datos de diferente naturaleza. Podemos generarlas con cbind o, preferiblemente, con la función data.frame.

data.frame( x, y, sexo ) -> datos
datos

En general, en una tabla de datos, las columnas corresponden a las variables, y las filas a las unidades de muestreo u observaciones. Para referirnos a una variable dentro de una tabla usaremos el símbolo $. Los nombres de las columnas y filas se pueden modificar o añadir, en su caso, con las funciones colnames (o simplemente names) y rownames:

datos$y
colnames( datos )
colnames( datos )[ 3 ] <- "sex"
rownames( datos ) <- ( 2011 : 2020 )
datos

Con tablas complejas, con numerosas variables, podemos obtener información sobre su estructura interna aplicando la función str:

str( datos )

Para realizar muchos tipos de análisis es conveniente convertir las variables de texto, o determinadas variables numéricas en variables de tipo “factor”. Los factores son variables categóricas con diferentes niveles. Podemos hacer la conversión usando la función factor:

datos$sex <- factor( datos$sex )
datos$sex

Listas

Las listas son objetos que contienen cualquier tipo de objeto, incluso otras listas. Los objetos de una lista pueden ser de diferentes dimensiones o tipos. Los resultados de muchas funciones suelen ser listas. Las listas se crean con la función list, pudiendo asignar de inicio un nombre a cada objeto:

lista <- list( tabla = datos, matriz = mat, texto = sexo )
lista
str( lista )

Para referirnos a un objeto en particular dentro de una lista podemos usar su nombre (con $) o dobles corchetes [[]]:

lista$tabla
lista$tabla$sex
lista[[ 2 ]]
lista[[ 2 ]][ , 1 ]

Archivos de datos (área de trabajo)

Los objetos generados en una sesión (el “área de trabajo”) pueden guardarse en un archivo con extensión .RData. También puede guardarse el historial de código ejecutado durante la sesión en un archivo con extensión .Rhistory. Ambos tipos de archivos pueden cargarse posteriormente en una nueva sesión.

Para los seminarios y prácticas de la asignatura Ecología I disponemos de un archivo que contiene los datos y funciones que pueden ser utilizados en las distintas sesiones. Este archivo (eco1.RData) está disponible en un servidor de la Universidad de Murcia. Puede descargarse directamente en R ejecutando:

load( url( "http://webs.um.es/jfcalvo/eco1.RData" ) )

La función load no borra los objetos creados durante la sesión (aunque sí los sobreescribe en caso de coincidencia de nombres), por lo que usando ls() podemos verlos junto a los objetos cargados. El archivo eco1.RData contiene una función (info) que permite obtener la descripción de sus objetos. Por ejemplo:

ls()
info( "ardilla" )
ardilla

Teclea info() para más información.

Paquetes de funciones y datos

Además de las funciones básicas disponibles cuando se inicia R, existen más de 20000 paquetes o bibliotecas de funciones (más de 20000, descargables en su mayoría desde los servidores del proyecto R) que permiten realizar infinidad de análisis de datos de cualquier tipo en el ámbito de disciplinas muy diversas. Algunos de estos paquetes vienen instalados por defecto, pero otros deben instalarse con la función install.packages. Los paquetes instalados deben cargarse en memoria con la función library. Como ejemplo instalaremos y cargaremos el paquete vegan, que permite realizar diversos tipos análisis con datos ecológicos.

install.packages( "vegan" )
library( vegan )

Muchos paquetes disponen además de datos con los que ejemplificar el uso de sus funciones. En el caso de vegan, están disponibles, entre otros, los datos de abundancia de 225 especies de árboles de la isla Barro Colorado en Panamá (objeto BCI, que hay que cargar con la función data):

data( BCI )
str( BCI )

Cálculos, análisis y gráficos

Utilizaremos el objeto ardilla para realizar otro ejercicio elaborando la tabla de vida de la cohorte de ardilla gris. En concreto calcularemos las siguientes variables: \(l_x\) (probabilidad de sobrevivir al inicio de la clase \(x\)), \(s_x\) (tasa de supervivencia específica de cada clase) y \(d_x\) (tasa de mortalidad).

Para ello realizaremos unas sencillas operaciones entre las variables disponibles:

ardilla$l <- ardilla$n / ardilla$n[ 1 ]
ardilla$s <- c( ardilla$n[ 2 : 8 ] / ardilla$n[ 1 : 7 ], 0 )
ardilla$d <- 1 - ardilla$s
ardilla

Existen muchas más posibilidades de analizar la información contenida en las tablas de datos, así como de realizar representaciones gráficas. Utilizaremos ahora los datos del objeto BCI para realizar diversos cálculos. Por ejemplo, para cada especie de árbol, podemos calcular el número total de ejemplares registrados en el muestreo sumando las columnas de la tabla:

colSums( BCI )

Una operación similar, ahora por filas, proporcionaría información sobre cada inventario. En este caso interesaría, más que la suma del número de ejemplares, la suma del número de especies (la riqueza). Para ello tenemos que usar la función rowSums aplicada a una operación lógica (BCI > 0):

rowSums( BCI > 0 )

R dispone de otras funciones para realizar diversos tipos de cálculos sobre los datos de las tablas. La función apply permite aplicar varias funciones sobre filas y columnas. Con esta función hay que indicar con un 1 si queremos trabajar con las filas, o con un 2 si queremos trabajar con las columnas:

apply( BCI > 0, 1, sum )
apply( BCI, 2, mean )

No olvidemos que el principal uso de R es el de análisis estadístico, para lo cual dispone de un gran número de funciones y paquetes. Como ejemplo, realizaremos un par de pruebas estadísticas sencillas:

shapiro.test( v3 )
t.test( z ~ sex, data = datos )

Por otra parte, las funciones de representación gráfica son diversas. Por ejemplo:

plot( log( l ) ~ x, data = ardilla )
pie( table( sexo ) )
hist( v3 )

Como último ejemplo utilizaremos la función prestondistr, incluida en el paquete vegan, que calcula, y permiter representar, el modelo de distribución de abundancia de especies (o modelo especies-abundancia) de Preston (Ecología I, tema 5):

prestonfit( colSums( BCI ) )
plot( prestonfit( colSums( BCI ) ) )

Ejercicios

1. Operaciones
  • Calcula con R la siguiente expresión matemática:

    \[ \frac{\left(\sqrt{5}\right)^{\ln(3)}}{3 \times e^4} \]

  • En R:

    ( ( sqrt( 5 ) ) ^ log( 3 ) ) / ( 3 * exp( 4 ) ) 
    [1] 0.01477915
  • Calcula la suma de las raíces cuadradas de los 5 primeros números.
  • En R:

    sum( sqrt( 1 : 5 ) )
    [1] 8.382332
2. Vectores, matrices y tablas
  • ¿Qué especie de árbol es la más abundante en los inventarios de Barro Colorado? ¿Con cúantos individuos?
  • En R:

    which( colSums( BCI ) == max(colSums( BCI ) ) )
    Faramea.occidentalis 
                      71 
    max(colSums( BCI ) )
    [1] 1717
3. Cálculos y análisis
  • Elabora la tabla de vida de Poa annua (objeto poa)
  • En R:

    poa$l <- poa$n / poa$n[ 1 ]
    poa$s <- c( poa$n[ 2 : 9 ] / poa$n[ 1 : 8 ], 0 )
    poa$d <- 1 - poa$s
    poa
      x   n   m           l         s         d
    1 0 843   0 1.000000000 0.8564650 0.1435350
    2 1 722 300 0.856465006 0.7299169 0.2700831
    3 2 527 620 0.625148280 0.5996205 0.4003795
    4 3 316 430 0.374851720 0.4556962 0.5443038
    5 4 144 210 0.170818505 0.3750000 0.6250000
    6 5  54  60 0.064056940 0.2777778 0.7222222
    7 6  15  30 0.017793594 0.2000000 0.8000000
    8 7   3  10 0.003558719 0.0000000 1.0000000
    9 8   0   0 0.000000000 0.0000000 1.0000000

Bibliografía

  • Paradis E (2002) R para principiantes. (PDF)

  • Tors P, Brauer C (2014) A (very) short introduction to R. (PDF)