3. Funciones y paquetes

3.1. Uso de funciones

Para crear, modificar, eliminar objetos, realizar análisis…en R utilizamos funciones!

R (“base-R”) tiene muchas funciones ya instaladas. De hecho, hemos utilizado algunas en los ejemplos anteriores (c(), list(), data.frame(), sum(), mean()).

3.2. Argumentos

Las funciones son instrucciones para hacer diferentes cosas y pueden tener uno o varios argumentos. Los argumentos son los parámetros que puedo o tengo que especificar (según cómo esté construida la función) para poder ejecutarla. A veces algunos de esos argumentos van a estar definidos por defecto, y la función va a funcionar sin necesidad de que yo los cambie, pero si quiero podré cambiarlo por otro.

Por ejemplo, la función sort(), sirve para ordenar los elementos de un vector, y tiene varios argumentos.

sort(c(1, 4, 2),            # argumento 1: el vector que quieres ordenar
     decreasing = TRUE)      # argumento 2: el orden en el que quieres ordenarlo
## [1] 4 2 1

Si tienes dudas sobre cómo funciona una función (qué hace) y los argumentos que puede incluir, puedes abrir la ayuda de esa función escribiendo interrogación y el nombre de la función ?sort.

Si no sabemos su nombre exacto o te devuelve una ayuda de una funcion de un paquete que no es la que buscas puedes escribir doble interrogación ??sort. Ello amplía la búsqueda a toda la documentación que tiene R y devuelve todas las páginas de la ayuda en donde aparece la palabra que buscas.

Si tienes dudas sobre alguna función de algún paquete instalado que no recuerdas cómo se llama puedes ir al panel de “la zona mágica” y pinchar en la pestaña de “packages”. Entonces aparecerán todos los paquetes que tienes instalados. Pinchando en el que te interese aparecerán todas las funciones que conforman ese paquete, y al seleccionar la función que estés buscando en cuestión se abrirá su panel de ayuda.

generos_arboles <- c("Quercus", "Fagus", "Sorbus", "Acer", "Pinus")
sort(generos_arboles)
## [1] "Acer"    "Fagus"   "Pinus"   "Quercus" "Sorbus"
generos_arboles
## [1] "Quercus" "Fagus"   "Sorbus"  "Acer"    "Pinus"

Como observarás aparecen dos líneas de resultados. El primero es el esperado: he aplicado la función y me ha devuelto el vector ordenado, pero en el segundo, la variable generos_arboles sigue estando desordenada.

Esto ocurre porque la mayoría de las funciones que utilizaremos devuelven un nuevo resultado y no modifican el objeto original. Para conservar ese resultado debemos asignarlo a un objeto, esa asignación puede ser:

  • Opción 1: creando un objeto nuevo
    generos_ordenados <- sort(generos_arboles)

  • Opción 2: sobreescribiendo el objeto original
    generos_arboles <- sort(generos_arboles)

3.3. Instalar y cargar paquetes

TipRegla número 1 de la programación: Reutiliza

No reinventes la rueda: si puedes usar alguna función que ya exista, úsala. Ahorrarás tiempo y esfuerzo.

A veces las funciones que vienen instaladas con R (“base-R”) no son suficientes para cumplir nuestros propósitos. Para ello, existen multitud de paquetes disponibles en CRAN, que podemos utilizar en R en dos pasos:

Para instalar cualquier paquete en nuestro ordenador hay que usar la función install.packages("package_name").
Para cargar un paquete en nuestro script con la función library(package_name).

Para instalar librerías el nombre del paquete debe ir entrecomillado. No así para cargar librerías.

Normalmente, un paquete se instala una vez por instalación de R y se carga en cada nueva sesión de RStudio en la que se necesite.

Una buena idea es cargar todos los paquetes que necesites al principio de cada script.

A través de un paquete puedes cargar no sólo funciones, sino también objetos (data frames, matrices, vectores…).

3.4. ¿Cómo citar los paquetes de R en un trabajo?

Las funciones que cargarmos con las librerías han sido creada por distintos desarrolladores y se debe (y merecen!) que les demos crédito por ello citándolos. Para conocer cómo debe citarse cada paquete utiliza citation("package_name"). Para poder usar esta función debes tener el paquete instalado, si no aparecerá un error del tipo: Error en citation(“package_name”): no hay paquete llamado “package_name”.

citation("spAbundance")
## To cite package 'spAbundance' in publications, please cite the Doser,
## Finley, Kéry, Zipkin (2024) paper. If using functions lfMsAbund,
## sfMsAbund, lfMsNMix, sfMsNMix, lfMsDS, or sfMsDS, please also cite the
## Doser, Finley, Banerjee (2023) paper that developed much of the code
## used for these functions.
## 
##   Doser, J. W., Finley A. O., Kéry, M., & Zipkin E. F. (2024).
##   spAbundance: An R package for single-species and multi-species
##   spatially explicit abundance models Methods in Ecology and Evolution,
##   15, 1024-1033. https://doi.org/10.1111/2041-210X.14332
## 
##   Doser, J. W., Finley A. O., & Banerjee, S. (2023). Joint species
##   distribution models with imperfect detection for high-dimensional
##   spatial data Ecology e4137. https://doi.org/10.1002/ecy.4137
## 
## To see these entries in BibTeX format, use 'print(<citation>,
## bibtex=TRUE)', 'toBibtex(.)', or set
## 'options(citation.bibtex.max=999)'.

Una buena práctica, además, es añadir en el apartado de metodología la versión del paquete que estás utilizando. A veces cambian algunas funciones entre versiones del mismo paquete y es útil saber cuál es la que has utilizado para tu análisis. La versión del paquete se puede consultar en la zona mágica apartado packages, al lado del paquete que quieras o mediante packageVersion("spAbundance").

3.5. Funciones propias

No obstante, existirán ocasiones en las que necesitarás crear tu propia función. En estas prácticas no vamos a entrar en detalle sobre la creación de funciones propias (aunque son muy útiles cuando hay que repetir tareas y permiten automatizar procesos de manera muy eficiente). Simplemente a continuación presentaré las partes clave que tienen que definirse:

nombre <- function(argumento1, argumento2, argumento3 = "estadística.") {
  paste("Hola, me llamo",
        argumento1,
        "y me encantaría aprender",
        argumento2,
        "y",
        argumento3)
}


nombre("Sonia", "diseño muestral")
## [1] "Hola, me llamo Sonia y me encantaría aprender diseño muestral y estadística."

Hay que definir:
1. nombre: ¿cómo vamos a llamar a ese objeto? (La función creada pasará a ser un objeto de nuestro environment),
2. utilizar la palabra clave function,
3. poner los argumentos clave que vamos a utilizar entre paréntesis y separados por comas. Se puede definir el valor que toma un argumento por defecto,
4. dar las instrucciones que queramos realizar entre llaves ({ instrucciones }).

Por defecto, R devuelve lo que haya en la última línea de la función. Sin embargo, a veces queremos que nuestra función devuelva otra cosa, para ello hay que usar el comando return.

funcion_ejemplo <- function(x) {
  y <- x^2 + 3
  y
}

funcion_ejemplo(3) # Devuelve 12, el valor esperado
## [1] 12
y                  # Devuelve un error.
## Error:
## ! objeto 'y' no encontrado



funcion_ejemplo2 <- function(x = 5) {
  y <- x^2 + 3
  y
}

funcion_ejemplo2(3)
## [1] 12

En ambos ejemplos x es el argumento de la función. En el primer ejemplo no tiene un valor por defecto, en el segundo ejemplo si lo tiene. ¿Qué pasaría si haces funcion_ejemplo() y si haces funcion_ejemplo2()? ¿Entiendes la diferencia?

El objeto y solo existe en el entorno local, es decir, dentro de la función. No existe en el entorno global, es decir, en mi environment.

Si quieres que un objeto creado dentro de una función se guarde dentro de tu environment global, cuando defines ese objeto dentro de la función en vez de poner <- debes poner <<-.

Hay que tener cuidado con ésto porque si el nombre de ese objeto ya existe en el environment global, sobreescribirá la información de ese objeto.

3.6. Estructuras de control

A la hora de dar órdenes es importante poder especificar condiciones o repeticiones:

Si llueve, tiende la ropa. Si no, saca al perro y da tres vueltas a la manzana.

En programación, a este tipo de directrices se les llama estructuras de control.

Las estructuras de control tienen su propia sintaxis. En general hay que usar las palabras que crean las diferentes estructuras de control (condiciones) y {instrucciones}. Lo veremos a continuación.

3.6.1. Bucles: for y while

Un bucle define cuántas veces se debe repetir una cierta acción. El bucle más típico es el for:

for (i in 10:1) {
  print(paste("Quedan", i, "segundos para el despegue"))
}
## [1] "Quedan 10 segundos para el despegue"
## [1] "Quedan 9 segundos para el despegue"
## [1] "Quedan 8 segundos para el despegue"
## [1] "Quedan 7 segundos para el despegue"
## [1] "Quedan 6 segundos para el despegue"
## [1] "Quedan 5 segundos para el despegue"
## [1] "Quedan 4 segundos para el despegue"
## [1] "Quedan 3 segundos para el despegue"
## [1] "Quedan 2 segundos para el despegue"
## [1] "Quedan 1 segundos para el despegue"

Es muy frecuente empezar un bucle con un vector vacío (“inicializado”) y luego ir rellenándolo con las operaciones del bucle. En este ejemplo vamos a rellenar un vector vacío con 10:1 muestras aleatorias de un color primario.

colores_primarios <- c()
for (i in 1:100) {
  colores_primarios[i] <- sample(c("Magenta", "Cian", "Amarillo"),
                                 size = 1, replace = TRUE)
}

El contador, i, toma todos los valores posibles del vector 1:100, hace una instrucción y guarda el resultado en la posición que en el vector que le hemos dado. Si no ponemos la instrucción print cuando ejecutemos el bucle no nos mostrará el resultado mientras lo está realizando, pero cuando consultamos el objeto que habíamos creado vacío veremos que éste contiene distintos valores en sus distintas posiciones. Cada uno de esos valores son las elecciones aleatorias que ha tomado R de nuestro vector de colores primarios.

colores_primarios
##   [1] "Amarillo" "Magenta"  "Magenta"  "Cian"     "Amarillo" "Cian"    
##   [7] "Amarillo" "Magenta"  "Cian"     "Magenta"  "Cian"     "Cian"    
##  [13] "Cian"     "Amarillo" "Magenta"  "Cian"     "Magenta"  "Amarillo"
##  [19] "Amarillo" "Cian"     "Magenta"  "Cian"     "Cian"     "Cian"    
##  [25] "Amarillo" "Cian"     "Amarillo" "Cian"     "Magenta"  "Amarillo"
##  [31] "Amarillo" "Cian"     "Magenta"  "Magenta"  "Amarillo" "Cian"    
##  [37] "Cian"     "Cian"     "Cian"     "Cian"     "Amarillo" "Amarillo"
##  [43] "Cian"     "Cian"     "Cian"     "Amarillo" "Magenta"  "Magenta" 
##  [49] "Magenta"  "Amarillo" "Magenta"  "Magenta"  "Amarillo" "Amarillo"
##  [55] "Cian"     "Cian"     "Cian"     "Cian"     "Cian"     "Cian"    
##  [61] "Magenta"  "Amarillo" "Cian"     "Cian"     "Magenta"  "Cian"    
##  [67] "Cian"     "Magenta"  "Cian"     "Amarillo" "Magenta"  "Magenta" 
##  [73] "Cian"     "Amarillo" "Amarillo" "Amarillo" "Amarillo" "Cian"    
##  [79] "Amarillo" "Magenta"  "Cian"     "Amarillo" "Magenta"  "Magenta" 
##  [85] "Magenta"  "Amarillo" "Cian"     "Amarillo" "Cian"     "Cian"    
##  [91] "Amarillo" "Cian"     "Magenta"  "Amarillo" "Amarillo" "Amarillo"
##  [97] "Magenta"  "Magenta"  "Magenta"  "Magenta"

También podemos usar dos bucles anidados para, por ejemplo, recorrer los elementos de una matriz.

En los bucles for sabemos de antemano cuántas veces queremos repetir las acciones. En cambio, los bucles while se utilizan para repetir una instrucción hasta que se alcanza una condición:

x <- 0
while (x != 3) {
  print(x)
  x <- sample(1:10, 1)
}
## [1] 0
## [1] 6
## [1] 1
## [1] 5
## [1] 10
## [1] 7
## [1] 4
## [1] 8
## [1] 7
## [1] 8
## [1] 1
## [1] 9
## [1] 8
## [1] 10
## [1] 7
## [1] 10
## [1] 1

Mientras x != 3 (distinto) repite la siguiente instrucción. Cuando x == 3 (igual) el bucle se detiene.

3.6.2. Condiciones: if , else

La estructura if/else sirve para ordenar que se ejecute un comando sólo si se cumple una cierta condición (if). Si esa condición no se cumple, puede hacer otra cosa (else).

Por lo general, esta estructura suele usarse dentro de una función, de un bucle o de una tabla.

Ejemplo: Tenemos un vector de individuos en diferentes poblaciones y queremos saber qué poblaciones podemos considerar grandes o pequeñas. El criterio para considerar que la población es grande es que supere los 10000 individuos.

poblaciones <- c(200, 120000, 1300000, 2300, 9500)
for (indiv in poblaciones) {
  if (indiv > 10000) {
    print("Es grande")
  } else {
    print("Es pequeña")
  }
}
## [1] "Es pequeña"
## [1] "Es grande"
## [1] "Es grande"
## [1] "Es pequeña"
## [1] "Es pequeña"

No siempre hace falta que haya cláusula else. Si no se define ninguna condición con el else, el programa no hará nada.

poblaciones <- c(200, 120000, 1300000, 2300, 9500)
for (indiv in poblaciones) {
  if (indiv > 10000) {
    print("Es grande")
  }
}
## [1] "Es grande"
## [1] "Es grande"

También se pueden concatenar varias condiciones. Por ejemplo, para poblaciones pequeñas cuando sea menor a 5000 dime que son poblaciones en riesgo.

poblaciones <- c(200, 120000, 1300000, 2300, 9500)
for (indiv in poblaciones) {
  if (indiv > 10000) {
    print("Es grande")
  } else {
    if (indiv > 5000) {
      print("Es pequeña y sin riesgo")
    }else {
      print("Es pequeña y con  riesgo")
    }
  }
}
## [1] "Es pequeña y con  riesgo"
## [1] "Es grande"
## [1] "Es grande"
## [1] "Es pequeña y con  riesgo"
## [1] "Es pequeña y sin riesgo"

3.6.3. Vectorización

R es un lenguaje hecho para trabajar con vectores. Muchas funciones base sirven tanto para un vector de un solo elemento como de varios elementos. Cuando les pasamos un vector de varios elementos, R procesa todos a la vez.

A R se le da muy bien el trabajo simultáneo, pero no tanto el trabajo secuencial. Eso se traduce en que es más eficiente trabajando con vectores que con bucles, especialmente si son largos y tienen muchas instrucciones.

Al proceso de adaptar una función para que trabaje con vectores de cualquier longitud se le llama vectorización. La vectorización es un proceso complejo pero importante para escribir programas eficientes.

Hay dos estructuras de control que han sido vectorizadas y son MUY útiles.

3.6.3.1. ifelse

La función ifelse es una versión vectorizada de una condición if/else. Toma tres argumentos: un test lógico, el resultado si el test es verdadero y el resultado si el test es falso.

El ejemplo anterior quedaría de la siguiente manera:

ifelse(poblaciones > 10000, "Es grande", "Es pequeña")
## [1] "Es pequeña" "Es grande"  "Es grande"  "Es pequeña" "Es pequeña"

De igual manera podemos escribir condiciones ìfelse anidadas:

ifelse(poblaciones > 10000, "Es grande",
       ifelse(poblaciones > 5000, "Es pequeña y sin riesgo",
              "Es pequeña y con riesgo"))
## [1] "Es pequeña y con riesgo" "Es grande"              
## [3] "Es grande"               "Es pequeña y con riesgo"
## [5] "Es pequeña y sin riesgo"

Fíjate que ambos resultados son iguales.

3.6.3.2. apply

Cuando nuestra función no está vectorizada, es decir, no puede aplicarse a todos los elementos de un vector a la vez, aún nos queda un as en la manga:

La familia de funciones apply sirven para aplicar una función a los elementos de un vector, lista, matriz… Los casos más típicos son lapply, que devuelve una lista, y sapply, que devuelve un vector.

Imagina que tienes una lista con los pesos de las aves de distintas poblaciones y queremos hallar la media y la desviación típica de cada población:

pesos <- list(pob_1 = c(32, 24, 56, 47, 21), pob_2 = c(13, 16, 21, 12, 23))
lapply(pesos, mean) # Devuelve una lista
## $pob_1
## [1] 36
## 
## $pob_2
## [1] 17
lapply(pesos, sd)   # Devuelve una lista
## $pob_1
## [1] 15.04992
## 
## $pob_2
## [1] 4.84768
sapply(pesos, mean) # Devuelve un vector
## pob_1 pob_2 
##    36    17
sapply(pesos, sd)   # Devuelve un vector
##    pob_1    pob_2 
## 15.04992  4.84768

La clase de objeto que quiero obtener dependerá de cómo quiera utilizar posteriormente ese objeto.

TipComentarios adicionales, importantes, antes de comenzar a trabajar con R.

Hasta ahora hemos visto cómo utilizar R, aunque de manera un poco caótica.

Cuando empezamos a manipular datos y producir resultados y gráficos, conviene tener un proyecto organizado. Si os acostumbráis a trabajar de una manera organizada y constante luego será mucho más fácil buscar información de manera rápida, reutilizar código para utilizar en otros análisis o gráficos, encontrar resultados, etc.

Cada uno puede organizarse de la manera que le resulte más útil, pero existen ciertos buenos hábitos a la hora de trabajar:

  1. Un proyecto bien organizado debe estar en una sola carpeta. Dentro de ella tendremos diferentes subcarpetas para:
  • Datos
  • Scripts
  • Gráficos
  1. Utiliza una forma de nombrar todo: directorios de trabajo, carpetas, nombres de ficheros…

  2. Tengo mi libro en blanco y las carpetas organizadas, ¿cómo comienzo a escribir en un script?

Todo buen script debe comenzar con un preámbulo que contenga:

  • una descripción de qué hace el script,
  • quién ha escrito ese script (nombre y correo),
  • fecha: cuando he creado ese script y cuándo ha sido la última vez que lo he modificado,
  • el camino (“path”) al directorio de trabajo (*),
  • las librerías que se van a utilizar (incluye su versión con un comentario! e.g. library(tidyverse) # v2.0.0).

(*) Directorios de trabajo

En R (al igual que en muchos otros lenguajes de programación), el directorio de trabajo es la carpeta por defecto donde R buscará ficheros y guardará resultados (imágenes, scripts, tablas…).

Cada vez que abramos RStudio, el directorio de trabajo será el que viene por defecto. Debemos cambiarlo en cada sesión. El lugar ideal para hacerlo es al comienzo de nuestro script (el preámbulo).

¿Y qué pasa si tengo algunos datos en otro directorio de trabajo? No os preocupéis por ello, se pueden leer otras rutas para cargar datos, funciones, resultados distintas al directorio de trabajo que se defina. De igual manera se pueden guardar gráficos y resultados en otras carpetas que no sean el directorio de trabajo que hemos definido al principio del script.

Para saber cuál es nuestro directorio de trabajo actual: getwd(). Para cambiar el directorio de trabajo: setwd(RUTA).

Nota: R utiliza barras normales / para separar las carpetas de un directorio, mientras que Windows utiliza barras invertidas \. Si copias directamente de una carpeta de Windows la ruta debes acordarte de cambiar las barras. Sino R producirá un error.

Para ver qué archivos hay en tu directorio de trabajo o en otras carpetas puedes usar la función list.files(). Esta función permite ver todos los elementos, carpetas y ficheros. A su vez la función permite ver los elementos que contienen otras carpetas si están dentro de ella, por ejemplo, si existe la carpeta datos: list.files("datos/"), devolverá todos los ficheros que contiene la carpeta datos.

1. Funciones:

1A) Crea una función que añada las palabras “y tal” a cualquier string que pases como input. El resultado debería ser el siguiente:

[1] "Me encanta programar y tal"

Pista: Tendrás que usar la función paste.

¿Qué ocurre si das un vector de varios strings como argumento a la función? add_string(c("Hola", "Qué tal"))

1B) Crea una función que calcule el área y el volumen de un cilindro en función de su radio y su altura. Haz que altura sea un argumento opcional con valor por defecto 5.

2. Estructuras de control

for

2A) Es hora de castigos: Saca en pantalla diez mil veces la frase “No llamaré a ningún objeto data2”. Tendrás que usar la función print dentro del bucle.

2B) La serie de Fibonacci aparece constantemente en la naturaleza. En ella, cada elemento es igual a la suma de los dos anteriores: $x_{i} = x_{i - 1} + x_{i - 2}$

  • Crea un bucle para calcular los primeros 300 elementos de la serie.

Pista: Tendrás que inicializar el vector con los dos primeros valores de la serie, 0 y 1.

  • Utiliza ese bucle para crear una función que calcule los n primeros elementos de la serie.

while

  • Vamos a repetir el bucle de la serie de Fibonacci, pero en lugar de parar cuando alcance un número de repeticiones, el bucle parará cuando el último elemento calculado sea mayor de 1000.

Tendrás que utilizar un contador explícito, es decir, inicializarlo y luego añadirle uno en cada vuelta del bucle. Si no te sale, puedes encontrar la solución “aquí.”

ifelse

2C) Crea un pequeño programa que recorra los números del 1 al 100 y saque en pantalla “par” o “impar” si el número es par o impar.

2D) Vamos a crear una función solucionadora de ecuaciones de segundo grado. Debe tomar tres argumentos de entrada, a, b y c tal que \(x = \frac{-b \pm \sqrt(b^2 - 4 \times a \times c)}{2 \times a}\)

La función debe comprobar, primero, si el discriminante (lo que va dentro de la raíz cuadrada) es negativo, y de ser así devolver un mensaje como “La ecuación no tiene soluciones”.

Si el discriminante es positivo, calcula las dos soluciones posibles de x y devúelvelas en un solo vector.

A continuación veréis algunos ejercicios avanzados: no los resolveremos en clase. Puedes probar si te salen (te animo a ello!). Escríbeme si te quedas atascado en algún apartado.

3A) Ejercicio de dinámica de poblaciones.

Tenemos los siguientes datos:

años <- seq(1963, 1988, by=1)
Nt <- c(1, 9, 14, 16, 3, 1, 4, 16, 30, 14, 12, 19, 51, 11, 7, 137, 204, 67, 197, 183, 149, 102, 141, 147, 178, 52)
Nt1 <- c(Nt[(-1)], NA)          #¿Comprendes esto? Analiza lo que estás haciendo siempre.
  • ¿Cómo ha variado la población con el tiempo? ¿Cuándo aumenta drásticamente la población?

Míralo en un gráfico.

  • Observa si existe relación entre el tamaño de la población (Nt) y la tasa de crecimiento per cápita de la población.

Pista: Haz primero una función que calcule la tasa de crecimiento per cápita entre Nt y Nt1.

  • Sigamos avanzando: ¿cómo crees que es la población en la actualidad?

Para conocerlo se debe analizar el tipo de relación que hay, a través de un modelo, entre mi variable explicativa (población observada) y mi variable dependiente (tasa de crecimiento per cápita). Si quieres conocerlo puedes ajustar un modelo lineal, un modelo logarítmico, un modelo polinomial…

En este momento del curso no nos vamos a detener para ver cómo hacerlo (puedes llamar a tu amigo Google), pero te adelantamos que la varianza explicada de nuestros datos por el modelo es muy pequeña. Por tanto, con los datos que introducimos al modelo, éste no es capaz de generar un buen ajuste y por eso NO debe utilizarse para predecir cómo será la población en el futuro y debemos recurrir a una aproximación cualitativa teórica:
\(N_{t_{1_{teorico}}} = N_{t} * exp(r_{teorico})\)
\(r_{teorico}= R_{o} · (1- \frac {U}{N_{t}}) · (1-\frac{N_{t}}{K})^θ)\)
Ro, por parametrización del modelo sabemos que es el máximo de la tasa de crecimiento per cápita observada,
U es el umbral de extinción (En nuestro ejemplo: 0.5),
K máxima capacidad de carga (En nuestro ejemplo: 97.185),
θ toma 0.8 de manera general (Sibly et al. 2005).

¿Qué le pasa a mi población? Ayuda: Realiza el ejercicio en dos partes.

    1. Crea las funciones que necesites para conocer teóricamente cómo es la población de 1963-1988.
  • Analiza lo que estás haciendo: no puedes conocer el tamaño poblacional teórico para 1963, por falta de datos, en cambio si lo puedes conocer para 1989.
    1. Crea un bucle que calcule los valores de tu población a futuro (1989-2026) y de su tasa de crecimiento per cápita, a partir de los últimos valores teóricos que has podido calcular con los datos.
    1. Observa el gráfico de tendencia de la población.

3B) Teoría de islas.

La teoría de islas de McArthur y Wilson trata de comprender cómo cambia la riqueza de especies de las islas, es decir, de qué depende que el número de especies aumente, disminuya o se mantenga estable.

Para que aumente el número de especies debe producirse inmigración/colonización (I) y ello va a depender de la distancia entre la isla y el continente (fuente), es decir, cuanto más lejos esté una isla del continente es más complicado que puedan llegar especies nuevas. Así como de la cantidad de especies presentes en el continente que no están presentes en la isla, es decir, cuántas nuevas especies pueden llegar a la isla, y de la probabilidad de que estas especies puedan llegar (c).

Para que disminuya deben producirse extinciones (E) y ello va a depender del tamaño de la isla (A; cuanto más pequeña más probable que se extingan), y de las especies que haya (S; cuantas más especies, más probable que alguna se extinga).

Vamos a simular la teoría de islas. Para ello debes crear: la función de inmigración y la función de extinción. (Consulta Google si no estás seguro cómo son estas funciones, hay unos factores de escalamiento para la distancia (f) y para el área (m))

Supon que, inicialmente, tu isla está a 300 km del continente, su tamaño es de 200, que en ella aún no ha colonizado ninguna especie (0) y que la cantidad de especies en el continente es de 1000.

Hay factores que se mantienen constantes (¿recuerdas cómo hacer que un factor sea constante en una función?):

  • Factor de escalamiento para la distancia (f) = 0.01
  • Factor de escalamiento para el área es de (m) = 0.25
  • Probabilidad de colonización (c) = 0.1
  • Probabilidad de extinción (q) = 0.2

¿Antes de nada, has comprobado que tiene sentido los resultados de tu función? … ¿¿¿¿Seguro???? ¿Pueden inmigrar o extinguirse especies decimalmente? No. Redondea los resultados a la unidad.

  1. ¿Qué pasa si aumenta / disminuye la distancia? Prueba a cambiar el nº de especies, ¿qué ocurre? ¿Y si aumenta / disminuye el área de la isla? De nuevo, prueba a cambiar el nºde especies. Analiza tus resultados, ¿tiene sentido?.
  2. ¿Cómo aumenta/disminuye la tasa de inmigración/extinción según aumenta la riqueza de especies en la isla? Dibújalo.

Ayuda:
- Crea un vector mi_isla (llámalo como quieras!) que cambie la riqueza de especies en la isla de 100 en 100, hasta 1000. - Crea un bucle que te calcule la inmigración y la extinción de especies para cada valor del vector creado. - Haz un gráfico para la tasa de inmigración/riqueza de especies y otro para la tasa de extinción/riqueza de especies; pero haz que aparezcan simultáneamente en el plot (consulta la función par). Ponle: título al gráfico y a los ejes, y dibuja de distinto color la curva de cada gráfico. - Ahora haz que las dos curvas aparezcan en el mismo gráfico. Igualmente, éstas deben de ser de distinto color y el gráfico debe aparecer correctamente identificado (título y ejes) para entender correctamente la representación que estamos mostrando.

pero… ¿es este caso real? Analicemos uno que si lo sea:

  1. Mi isla está desierta en un inicio, pero según pasa el tiempo comienza a haber colonización y extinción de especies en ella: la riqueza de mi isla cambia con el tiempo, al igual que la cantidad de especies que colonizan y se extinguen.

Es buena idea escribir en un papel tus ideas y pensar cómo pedirle al programa lo que quieres. Una ayuda, con los datos que hemos estado usando:

Tiempo Riqueza Colonización Extinción
1 0 33 0
2 33 32 2
3 63 31 3

¿Ves el patrón? Ahora dile a R cómo poder generarlo. Utiliza la estructura de bucle y las funciones que has creado.

  • ​¿En qué momento (tiempo) alcanza el equilibrio mi isla? ¿Cuál es el valor de la tasa de inmigración/extinción en ese momento?