Guía de R y RStudio con IA como copiloto

Módulo 2 — Entorno RStudio y manejo de datos biológicos

Autor/a
Afiliación

Universidad de La Guajira

Fecha de publicación

29 de octubre de 2026

Inteligencia Artificial aplicada a los datos en Ciencias Biológicas

Módulo 2 de 6 — Entorno RStudio y manejo de datos
Intensidad del módulo 3 horas (curso completo: 16 horas)
Modalidad Virtual asincrónica (autoguiada), con sesiones en vivo de acompañamiento
Dirigido a Profesionales egresados en Biología
Herramientas R, RStudio, tidyverse, Quarto y asistentes de IA
Institución Universidad de La Guajira — Facultad de Ciencias Básicas y Aplicadas, Programa de Biología
Coordinación académica Dr. Cristian Enrique Granados Martínez

Sobre el autor

Cristian Enrique Granados Martínez es biólogo y Doctor en Ciencias Naturales para el Desarrollo (DOCINADE, Instituto Tecnológico de Costa Rica), con énfasis en Gestión de Recursos Naturales. Es docente-investigador del Programa de Biología de la Universidad de La Guajira, donde coordina el Comité de Investigación y Extensión de la Facultad de Ciencias Básicas y Aplicadas, e integra los grupos de investigación en Biotecnología y en Ecología y Biodiversidad de Ecosistemas Tropicales (EBET). Es Investigador Asociado reconocido por Minciencias.

Con más de 17 años de experiencia de campo en la Sierra Nevada de Santa Marta y La Guajira, su investigación se centra en los macroinvertebrados acuáticos, la limnología y la biodiversidad de agua dulce del Caribe colombiano. Ha descrito cuatro especies nuevas para la ciencia y es autor de más de 28 artículos indexados, 4 libros y 17 capítulos de libro.

ORCID: 0000-0003-0161-9537 · Sitio web: biolocristiam.github.io

Cómo citar esta guía: Granados-Martínez, C. E. (2026). Guía de R y RStudio con IA como copiloto. Módulo 2: Entorno RStudio y manejo de datos biológicos. Curso Inteligencia Artificial aplicada a los datos en Ciencias Biológicas. Universidad de La Guajira, Riohacha, Colombia.

1 Antes de empezar

1.1 Cómo usar esta guía

Esta guía reúne en un solo recorrido todo lo que necesitas para trabajar con datos biológicos en R, desde abrir RStudio por primera vez hasta producir una matriz de comunidad lista para los análisis de diversidad y bioindicación de los módulos siguientes.

Está organizada en tres bloques. Al final de cada uno hay un punto de control: un ejercicio corto que te dice si estás listo para seguir.

Bloque Contenido Tiempo
A RStudio, proyectos, Quarto y la IA como copiloto; fundamentos de R ≈ 60 min
B Importar, limpiar, transformar y visualizar datos con tidyverse ≈ 85 min
C Datos abiertos de biodiversidad (GBIF e iNaturalist) ≈ 35 min

A lo largo del texto encontrarás cuatro tipos de recuadros:

Tip💡 Consejo

Buenas prácticas y atajos que te ahorran tiempo.

Importante🤖 Prompt para tu copiloto

Una instrucción lista para copiar en tu asistente de IA. Úsala, modifícala y compara lo que te responde con lo que dice esta guía.

Advertencia⚠️ Cuidado

Errores frecuentes o situaciones en las que la IA suele equivocarse.

Nota✅ Punto de control

Ejercicio para verificar lo aprendido, con solución desplegable.

1.2 Objetivos de aprendizaje

Al terminar este módulo podrás:

  1. Organizar tu trabajo en un proyecto reproducible de RStudio con documentos Quarto.
  2. Configurar y usar un asistente de IA como copiloto, sabiendo pedirle ayuda y verificando lo que responde.
  3. Importar, limpiar y transformar datos de campo (CSV y Excel) con tidyverse.
  4. Pasar datos de abundancia del formato largo a una matriz de comunidad (sitios × taxones).
  5. Construir gráficos de calidad científica con ggplot2.
  6. Descargar registros de GBIF e iNaturalist directamente desde R.

1.3 Los datos del curso

Durante todo el módulo trabajaremos con un único caso de estudio: el monitoreo de macroinvertebrados acuáticos y variables fisicoquímicas en seis estaciones de un río de la vertiente norte de la Sierra Nevada de Santa Marta, desde la cabecera (≈ 870 m) hasta la desembocadura (≈ 15 m), en época seca y de lluvias, con tres réplicas por estación.

Advertencia⚠️ Datos simulados

Los datos son simulados con fines didácticos. Reproducen patrones realistas (gradiente de perturbación, efecto de una descarga municipal, arrastre en lluvias), pero no corresponden a un muestreo real y no deben citarse como tales.

Descarga del aula virtual los tres archivos y guárdalos en una carpeta llamada datos/ dentro de tu proyecto (sección Sección 2.2):

Archivo Contenido Formato
macroinvertebrados.csv Una fila por familia encontrada en cada muestra: orden, familia y abundancia Largo
fisicoquimicos.xlsx Una fila por muestra: temperatura, oxígeno disuelto, pH, conductividad, turbidez, velocidad Ancho
estaciones.csv Altitud, coordenadas y uso del suelo de las seis estaciones Tabla de referencia

Los archivos traen a propósito algunos errores típicos de digitación y datos faltantes, como los que aparecen en cualquier libreta de campo. Aprenderás a detectarlos y corregirlos en el Bloque B.

2 Bloque A — RStudio, Quarto y la IA como copiloto

2.1 ¿Qué son R y RStudio?

R es un lenguaje de programación libre y gratuito, creado para el análisis estadístico y la visualización de datos. Es el estándar de facto en ecología: paquetes como vegan, iNEXT o betapart existen principalmente en R.

RStudio es el entorno de desarrollo (IDE) que usamos para escribir y ejecutar código R de forma cómoda. R es el motor; RStudio es el tablero.

Para el trabajo en biología, R permite:

  • Analizar datos experimentales y de monitoreo con métodos estadísticos rigurosos.
  • Producir gráficos de calidad para publicación.
  • Analizar comunidades: diversidad, ordenación, índices bióticos.
  • Acceder a bases de datos abiertas como GBIF.
  • Documentar todo el análisis de forma reproducible: cualquiera puede repetirlo y obtener el mismo resultado.

2.1.1 Instalación

Instala en este orden:

  1. R desde CRAN, en la versión más reciente para tu sistema operativo.
  2. RStudio Desktop desde posit.co/download/rstudio-desktop. Es gratuito.
Tip💡 Consejo

Si ya tenías R instalado hace más de un año, actualízalo. Muchos errores de instalación de paquetes se deben a versiones antiguas de R.

2.1.2 La interfaz de RStudio

RStudio se divide en cuatro paneles:

Panel Para qué sirve
Editor (arriba a la izquierda) Escribir y guardar scripts (.R) y documentos Quarto (.qmd)
Consola (abajo a la izquierda) Donde R ejecuta el código y muestra los resultados
Entorno / Historial (arriba a la derecha) Los objetos creados en la sesión (tablas, vectores, modelos)
Archivos / Gráficos / Paquetes / Ayuda (abajo a la derecha) Explorar carpetas, ver gráficos, consultar la ayuda

Si tienes activado un asistente de IA (sección Sección 2.4), aparecerá además un panel lateral de chat.

2.2 Proyectos: la base de un trabajo reproducible

Un proyecto de RStudio es una carpeta con un archivo .Rproj que le dice a RStudio: “todo lo de este análisis vive aquí”. Al abrir el proyecto, el directorio de trabajo se ubica automáticamente en esa carpeta y las rutas relativas (datos/archivo.csv) funcionan en cualquier computador.

Para crearlo:

  1. File → New Project… → New Directory → New Project.
  2. Nómbralo, por ejemplo, curso_ia_modulo2.
  3. Dentro, crea esta estructura de carpetas:
curso_ia_modulo2/
├── curso_ia_modulo2.Rproj
├── datos/          ← archivos originales (¡nunca se modifican!)
├── resultados/     ← tablas generadas por el análisis
├── figuras/        ← gráficos exportados
└── modulo2.qmd     ← tu documento de trabajo
Advertencia⚠️ Cuidado

Evita setwd("C:/Users/...") al inicio de tus scripts. Esa ruta solo existe en tu computador; si compartes el análisis, fallará en cualquier otro. Con proyectos no la necesitas.

2.3 Scripts y documentos Quarto

RStudio permite trabajar de dos formas:

  • Script .R (File → New File → R Script): solo código y comentarios. Es ideal para funciones o pruebas rápidas.
  • Documento Quarto .qmd (File → New File → Quarto Document): mezcla texto, código y resultados en un solo informe que se renderiza a HTML, Word o PDF. Esta guía está escrita en Quarto.

Un documento Quarto tiene tres partes:

---
title: "Mi análisis de macroinvertebrados"
author: "Tu nombre"
format: html
---

## Introducción

Texto normal en *Markdown*: **negritas**, listas, enlaces...

```{r}
# Bloque de código R (chunk)
mean(c(8.2, 7.8, 6.7))
```
  1. El encabezado YAML, entre ---, define el título, el autor y el formato de salida.
  2. El texto se escribe en Markdown.
  3. Los bloques de código (chunks) se insertan con Ctrl + Alt + I.

El botón Render (Ctrl + Shift + K) ejecuta todo el código desde cero y genera el informe. Si el documento renderiza sin errores, tu análisis es reproducible.

Tip💡 Recomendación para este módulo

Crea un documento modulo2.qmd y ve copiando y ejecutando allí los bloques de código de esta guía. Al final tendrás tu propio informe del módulo.

2.4 La IA como copiloto en RStudio

En este curso la IA no reemplaza tu criterio estadístico ni biológico: es un copiloto que escribe borradores de código, explica errores y sugiere alternativas. El piloto, quien decide y responde por el análisis, eres tú.

2.4.1 Opciones disponibles

Opción Cómo funciona Costo Ventaja principal
Posit Assistant (servicio Posit AI) Agente integrado en el panel lateral de RStudio. Ve tu sesión: paquetes cargados, tablas en memoria, errores Suscripción desde USD 20/mes, con prueba gratuita Responde con base en tus datos reales; puede ejecutar código
GitHub Copilot Autocompletado de código mientras escribes, dentro del editor Plan gratuito con límites; gratuito para docentes y estudiantes verificados Sugerencias en línea, rápido
Chat externo (Claude, ChatGPT, Gemini…) Copias código, errores o la estructura de tus datos y pegas la respuesta Planes gratuitos disponibles Accesible para todos; no requiere configuración

Para seguir el curso basta con un chat externo gratuito. Si tienes acceso a Posit Assistant o Copilot, aprovéchalos.

2.4.2 Configuración

Posit Assistant. Actualiza RStudio a la versión más reciente, haz clic en el ícono de Posit Assistant en la barra de herramientas y crea tu cuenta de Posit AI cuando te lo pida.

GitHub Copilot. Necesitas una cuenta de GitHub con Copilot activo. En RStudio ve a Tools → Global Options → Copilot, marca Enable GitHub Copilot e inicia sesión.

Chat externo. Abre el asistente en tu navegador junto a RStudio. Es la opción más flexible, pero recuerda que la IA no ve tu sesión: tú debes darle el contexto.

2.4.3 Cómo pedirle ayuda: anatomía de un buen prompt

La calidad de la respuesta depende del contexto que des. Un buen prompt tiene cinco elementos:

  1. Rol: quién quieres que sea la IA.
  2. Contexto: qué datos tienes (pega la salida de str() o glimpse(), nunca la base completa).
  3. Tarea: qué necesitas, de forma concreta.
  4. Restricciones: qué paquetes usar y qué evitar.
  5. Formato: cómo quieres la respuesta.
Importante🤖 Ejemplo de prompt bien construido
Actúa como un ecólogo experto en R y tidyverse.
Tengo un data frame llamado `macro` con esta estructura:
  muestra (chr), estacion (chr), epoca (chr), orden (chr),
  familia (chr), abundancia (dbl)
Necesito calcular, para cada estación y época, la riqueza de
familias y la abundancia total.
Usa dplyr con el operador |>. No uses bucles for.
Explica cada línea con un comentario breve.

Compáralo con “hazme la riqueza en R”: con esa instrucción la IA tendría que adivinar el nombre de tus columnas, tus paquetes y tu nivel.

2.4.4 Reglas de oro del copiloto

Advertencia⚠️ La IA se equivoca, y lo hace con mucha seguridad
  • Inventa funciones y argumentos que no existen (las llamadas alucinaciones). Si una función no te suena, búscala en la ayuda: ?nombre_funcion.
  • Puede sugerir análisis inadecuados para tus datos, por ejemplo un ANOVA sobre conteos con muchos ceros. Por eso el Módulo 3 se dedica a entender la estadística.
  • No compartas datos sensibles: coordenadas exactas de especies amenazadas, datos de comunidades o información personal. Para pedir ayuda basta con la estructura de los datos (str()) o un ejemplo inventado.
  • Ejecuta y entiende cada línea antes de aceptarla. Si no puedes explicar qué hace un código, todavía no es tuyo.
  • Documenta en tu .qmd cuándo y para qué usaste la IA. Es parte de la transparencia científica.

2.5 Primeros pasos con R

2.5.1 Objetos y asignación

En R guardamos información en objetos con el operador de asignación <- (atajo: Alt + -):

Código
# Oxígeno disuelto promedio (mg/L) en las seis estaciones, de cabecera a desembocadura
oxigeno <- c(8.2, 7.8, 6.7, 4.4, 5.9, 6.2)
oxigeno
[1] 8.2 7.8 6.7 4.4 5.9 6.2
Código
# Operaciones sobre todo el vector a la vez (vectorización)
oxigeno_porcentaje_max <- oxigeno / max(oxigeno) * 100
round(oxigeno_porcentaje_max, 1)
[1] 100.0  95.1  81.7  53.7  72.0  75.6

2.5.2 Funciones y ayuda

Las funciones reciben argumentos entre paréntesis y devuelven un resultado:

Código
mean(oxigeno)          # promedio
[1] 6.533333
Código
round(sd(oxigeno), 2)  # desviación estándar, redondeada a 2 decimales
[1] 1.38
Código
length(oxigeno)        # número de elementos
[1] 6

Para consultar la ayuda de cualquier función escribe en la consola ?mean o help(mean). La sección Examples, al final de cada página de ayuda, suele ser lo más útil.

2.5.3 Atajos de teclado esenciales

Atajo Acción
Ctrl + Enter Ejecuta la línea actual o la selección
Ctrl + Shift + Enter Ejecuta todo el bloque o script
Alt + - Inserta <-
Ctrl + Shift + M Inserta el pipe |>
Ctrl + Alt + I Inserta un bloque de código en Quarto
Ctrl + Shift + K Renderiza el documento Quarto
Ctrl + Shift + C Comenta o descomenta líneas
Tab Autocompleta nombres de objetos y funciones

En macOS reemplaza Ctrl por Cmd y Alt por Option.

Tip💡 Consejo

Para que Ctrl + Shift + M inserte el pipe nativo |> en lugar de %>%, activa Tools → Global Options → Code → Use native pipe operator.

2.6 Tipos de datos y estructuras

Los datos biológicos combinan distintos tipos de información, y R tiene un tipo para cada uno:

Código
# Numérico (double): mediciones continuas
conductividad <- c(52, 98, 160, 410, 255, 230)

# Entero: conteos (la L indica entero)
individuos_baetidae <- c(84L, 61L, 22L, 0L, 9L, 17L)

# Carácter: nombres y categorías de texto
familias <- c("Baetidae", "Leptophlebiidae", "Perlidae", "Chironomidae")

# Lógico: verdadero/falso
es_EPT <- c(TRUE, TRUE, TRUE, FALSE)

# Factor: variables categóricas con niveles definidos
epoca <- factor(c("Seca", "Lluvias", "Seca", "Lluvias"),
                levels = c("Seca", "Lluvias"))

class(conductividad); class(individuos_baetidae); class(familias)
[1] "numeric"
[1] "integer"
[1] "character"
Código
class(es_EPT); levels(epoca)
[1] "logical"
[1] "Seca"    "Lluvias"
Tip💡 ¿Por qué importan los factores?

Con un factor tú decides el orden de los niveles, y ese orden se respeta en tablas y gráficos. Sin factor, R ordena alfabéticamente: “Lluvias” quedaría antes que “Seca” y las estaciones E10 antes que E2.

2.6.1 Indexación: extraer elementos

Código
familias[2]            # el segundo elemento
[1] "Leptophlebiidae"
Código
familias[es_EPT]       # solo las familias EPT (indexación lógica)
[1] "Baetidae"        "Leptophlebiidae" "Perlidae"       
Código
conductividad[conductividad > 200]  # estaciones con conductividad alta
[1] 410 255 230

2.6.2 El data frame: la tabla de datos

Un data frame organiza los datos en filas (observaciones) y columnas (variables). Cada columna es un vector y todas tienen la misma longitud. Es el equivalente a una hoja de Excel bien organizada.

Código
estaciones_mini <- data.frame(
  estacion      = paste0("E", 1:6),
  oxigeno_mg_l  = oxigeno,
  conductividad = conductividad,
  baetidae      = individuos_baetidae
)
estaciones_mini
Código
estaciones_mini$oxigeno_mg_l          # una columna con $
[1] 8.2 7.8 6.7 4.4 5.9 6.2
Código
estaciones_mini[estaciones_mini$oxigeno_mg_l < 5, ]   # filas que cumplen una condición

2.7 Estadística descriptiva rápida

Código
summary(estaciones_mini$conductividad)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   52.0   113.5   195.0   200.8   248.8   410.0 
Código
quantile(estaciones_mini$conductividad, probs = c(0.1, 0.5, 0.9))
  10%   50%   90% 
 75.0 195.0 332.5 
Código
# Coeficiente de variación (%): dispersión relativa a la media
cv <- sd(conductividad) / mean(conductividad) * 100
round(cv, 1)
[1] 63.7

R base también hace gráficos rápidos, útiles para explorar antes de invertir tiempo en un gráfico final:

Código
plot(estaciones_mini$oxigeno_mg_l, estaciones_mini$baetidae,
     xlab = "Oxígeno disuelto (mg/L)", ylab = "Individuos de Baetidae",
     pch = 19, col = "steelblue")

Gráfico exploratorio rápido con R base: oxígeno disuelto frente a abundancia de Baetidae.

Para gráficos de publicación usaremos ggplot2 (sección Sección 3.8).

Ejercicio. Crea un vector con la temperatura (°C) de las seis estaciones: 19.7, 22.3, 23.9, 26.4, 27.1, 28.0. Luego:

  1. Calcula la media y la desviación estándar.
  2. Agrega la temperatura como columna temperatura a estaciones_mini.
  3. Filtra las estaciones con temperatura mayor a 25 °C y oxígeno menor a 6 mg/L.

Pregúntale a tu copiloto por qué el oxígeno disuelto tiende a bajar cuando sube la temperatura, y verifica su respuesta con tus conocimientos de limnología.

Solución:

Código
temperatura <- c(19.7, 22.3, 23.9, 26.4, 27.1, 28.0)
mean(temperatura); sd(temperatura)
[1] 24.56667
[1] 3.188521
Código
estaciones_mini$temperatura <- temperatura
estaciones_mini[estaciones_mini$temperatura > 25 & estaciones_mini$oxigeno_mg_l < 6, ]

3 Bloque B — Importar, limpiar, transformar y visualizar

3.1 Paquetes

Un paquete es una colección de funciones, datos y documentación que amplía lo que R puede hacer. Es como instalar una aplicación en el celular.

Código
# Instalar: UNA sola vez por computador
install.packages(c("tidyverse",  # dplyr, ggplot2, readr, tidyr, stringr...
                   "readxl",     # leer archivos de Excel
                   "janitor",    # limpiar nombres de columnas
                   "writexl",    # exportar a Excel
                   "rgbif"))     # descargar datos de GBIF (Bloque C)
Código
# Cargar: al inicio de CADA sesión o documento
library(tidyverse)
library(readxl)
library(janitor)
Tip💡 Regla de oro

install.packages() se ejecuta una vez. library() va al inicio de cada documento. No dejes install.packages() dentro de tu .qmd: se reinstalaría cada vez que renderizas.

Advertencia⚠️ Conflictos entre paquetes

Al cargar tidyverse verás mensajes como dplyr::filter() masks stats::filter(). Significa que dos paquetes tienen una función con el mismo nombre y se usará la del último cargado. Si alguna vez necesitas la otra, llámala explícitamente: stats::filter().

3.2 Importar datos de campo

3.2.1 Archivos CSV con read_csv()

Código
macro_crudo <- read_csv("datos/macroinvertebrados.csv")
estaciones  <- read_csv("datos/estaciones.csv")

3.2.2 Archivos Excel con read_excel()

Código
fq_crudo <- read_excel("datos/fisicoquimicos.xlsx", sheet = "fisicoquimicos")
Tip💡 Consejo

read_csv() de readr es más rápido que read.csv() de R base, detecta los tipos de columna con más acierto y no convierte el texto en factores sin avisar. Si tu CSV usa ; como separador y , como decimal (configuración regional de Excel en español), usa read_csv2().

3.3 Inspeccionar antes de analizar

Nunca analices sin antes mirar los datos. Estas funciones te dicen qué hay en ellos:

Código
glimpse(macro_crudo)   # estructura: columnas, tipos y primeros valores
Rows: 775
Columns: 8
$ muestra    <chr> "E1-S-R1", "E1-S-R1", "E1-S-R1", "E1-S-R1", "E1-S-R1", "E1-…
$ estacion   <chr> "E1", "E1", "E1", "E1", "E1", "E1", "E1", "E1", "E1", "E1",…
$ epoca      <chr> "Seca", "Seca", "Seca", "Seca", "Seca", "Seca", "Seca", "Se…
$ replica    <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ fecha      <date> 2025-02-18, 2025-02-18, 2025-02-18, 2025-02-18, 2025-02-18…
$ orden      <chr> "Amphipoda", "Basommatophora", "Basommatophora", "Coleopter…
$ familia    <chr> "Hyalellidae", "Physidae", "Planorbidae", "Elmidae", "Pseph…
$ abundancia <dbl> 5, 30, 7, 49, 4, 109, 2, 25, 7, 50, 131, 12, 29, 16, 2, 5, …
Código
head(estaciones)       # primeras filas
Código
names(fq_crudo)        # nombres de columnas
 [1] "Muestra"                   "Estación"                 
 [3] "Época"                     "Réplica"                  
 [5] "Fecha muestreo"            "Temperatura (°C)"         
 [7] "Oxígeno disuelto (mg/L)"   "pH"                       
 [9] "Conductividad (µS/cm)"     "Turbidez (NTU)"           
[11] "Velocidad corriente (m/s)"
Importante🤖 Prompt para tu copiloto

Pega la salida de glimpse() de tus propios datos y pregunta:

Esta es la estructura de mi base de datos de campo [pegar glimpse].
¿Qué problemas potenciales ves (tipos de columna, nombres,
valores sospechosos)? ¿Qué verificaciones me recomiendas hacer
en R antes de analizarla?

3.4 Limpieza de datos

3.4.1 Nombres de columnas con clean_names()

Los nombres del archivo de Excel tienen espacios, tildes y símbolos (Oxígeno disuelto (mg/L)), y en R eso obliga a escribirlos entre comillas invertidas. clean_names() los convierte a un formato limpio: minúsculas, sin tildes y con guion bajo.

Código
fq <- fq_crudo |> clean_names()
names(fq)
 [1] "muestra"                 "estacion"               
 [3] "epoca"                   "replica"                
 [5] "fecha_muestreo"          "temperatura_c"          
 [7] "oxigeno_disuelto_mg_l"   "p_h"                    
 [9] "conductividad_m_s_cm"    "turbidez_ntu"           
[11] "velocidad_corriente_m_s"

Funcionó casi todo, pero mira con atención: pH quedó como p_h y el símbolo µ de µS/cm se convirtió en m (conductividad_m_s_cm). Esto pasaría a ser milisiemens, un error de mil veces. Corregimos con rename(), poniendo primero el nombre nuevo:

Código
fq <- fq |>
  rename(ph              = p_h,
         conductividad_us_cm = conductividad_m_s_cm,
         od_mg_l         = oxigeno_disuelto_mg_l,
         velocidad_m_s   = velocidad_corriente_m_s)
names(fq)
 [1] "muestra"             "estacion"            "epoca"              
 [4] "replica"             "fecha_muestreo"      "temperatura_c"      
 [7] "od_mg_l"             "ph"                  "conductividad_us_cm"
[10] "turbidez_ntu"        "velocidad_m_s"      
Advertencia⚠️ Lección

Las herramientas automáticas, incluida la IA, ahorran trabajo, pero siempre hay que revisar el resultado. Un cambio de unidad silencioso puede invalidar un análisis completo.

3.4.2 Inconsistencias en texto

Los errores de digitación en nombres taxonómicos son de los más comunes en bases de campo. count() nos ayuda a detectarlos:

Código
macro_crudo |>
  count(familia) |>
  filter(str_detect(str_to_lower(familia), "baetid|chironomid"))

Aparecen baetidae y CHIRONOMIDAE. R las trata como familias distintas de Baetidae y Chironomidae, lo que inflaría la riqueza. (En el archivo original también hay un "Baetidae " con un espacio al final, pero read_csv() elimina esos espacios automáticamente; read_excel() y otras funciones no siempre lo hacen.) Las corregimos con funciones de stringr:

Código
macro <- macro_crudo |>
  mutate(familia = familia |>
           str_trim() |>        # quita espacios al inicio y al final
           str_to_title())      # primera letra en mayúscula, resto minúscula

n_distinct(macro_crudo$familia)   # antes
[1] 35
Código
n_distinct(macro$familia)         # después
[1] 33

3.4.3 Datos faltantes (NA)

Código
# ¿Cuántos NA hay en cada columna?
fq |> summarise(across(everything(), \(x) sum(is.na(x))))
Código
# Las funciones devuelven NA si hay un faltante...
mean(fq$od_mg_l)
[1] NA
Código
# ...a menos que indiquemos explícitamente que se ignoren
mean(fq$od_mg_l, na.rm = TRUE)
[1] 6.518286
Tip💡 ¿Eliminar o conservar los NA?

drop_na() elimina las filas con faltantes, pero en una base con muchas variables puedes perder muestras completas por un solo sensor fallido. Normalmente es mejor conservar la fila y usar na.rm = TRUE en cada cálculo. Si decides imputar valores, hazlo de forma justificada y documentada; ese es un buen tema para discutir con tu copiloto y con tu estadístico.

3.4.4 Tipos de variable

Convertimos a factor las variables categóricas, con un orden con sentido ecológico:

Código
orden_estaciones <- paste0("E", 1:6)

macro <- macro |>
  mutate(estacion = factor(estacion, levels = orden_estaciones),
         epoca    = factor(epoca, levels = c("Seca", "Lluvias")))

fq <- fq |>
  mutate(estacion = factor(estacion, levels = orden_estaciones),
         epoca    = factor(epoca, levels = c("Seca", "Lluvias")),
         fecha_muestreo = as.Date(fecha_muestreo))

3.5 Transformar datos con dplyr

dplyr ofrece un conjunto de verbos que se encadenan con el pipe |>, que se lee como “y luego”:

Verbo Qué hace
filter() Selecciona filas que cumplen una condición
select() Selecciona columnas
mutate() Crea o modifica columnas
group_by() + summarise() Resume datos por grupos
arrange() Ordena filas
count() Cuenta observaciones por categoría

3.5.1 filter(): seleccionar filas

Código
# Solo los órdenes EPT (Ephemeroptera, Plecoptera, Trichoptera)
ept <- macro |>
  filter(orden %in% c("Ephemeroptera", "Plecoptera", "Trichoptera"))

ept |> count(orden, sort = TRUE)

3.5.2 select(): seleccionar columnas

Código
macro |>
  select(muestra, estacion, familia, abundancia) |>
  head()

3.5.3 mutate() y case_when(): crear columnas

Clasificamos cada muestra según su oxígeno disuelto, usando como referencia el umbral de 4 mg/L, un mínimo comúnmente aceptado para la vida acuática en aguas cálidas:

Código
fq <- fq |>
  mutate(estado_od = case_when(
    is.na(od_mg_l) ~ NA_character_,
    od_mg_l >= 6   ~ "Bueno",
    od_mg_l >= 4   ~ "Aceptable",
    TRUE           ~ "Crítico"
  ))

fq |> count(estacion, estado_od)

3.5.4 group_by() + summarise(): resúmenes por grupo

Este es el corazón del análisis de comunidades. Calculamos métricas por muestra:

Código
metricas_muestra <- macro |>
  group_by(muestra, estacion, epoca) |>
  summarise(
    riqueza          = n_distinct(familia),
    abundancia_total = sum(abundancia),
    riqueza_ept      = n_distinct(familia[orden %in% c("Ephemeroptera", "Plecoptera", "Trichoptera")]),
    prop_chironomidae = sum(abundancia[familia == "Chironomidae"]) / sum(abundancia),
    .groups = "drop"
  )

metricas_muestra
Advertencia⚠️ El orden y los nombres importan dentro de summarise()

Dentro de summarise(), cada línea ve los resultados de las anteriores. Si hubiéramos llamado abundancia (igual que la columna original) al total, en la línea de prop_chironomidae la palabra abundancia ya sería el total resumido —un solo número— y no los conteos por familia, y la proporción saldría errónea sin ningún mensaje de error. Por eso el total se llama abundancia_total. Es un error sutil que la IA comete a menudo: revísalo siempre.

Y un resumen por estación y época, ordenado con arrange():

Código
resumen_estacion <- metricas_muestra |>
  group_by(estacion, epoca) |>
  summarise(
    riqueza_media = mean(riqueza),
    riqueza_ee    = sd(riqueza) / sqrt(n()),   # error estándar
    ept_media     = mean(riqueza_ept),
    n_replicas    = n(),
    .groups = "drop"
  ) |>
  arrange(desc(riqueza_media))

resumen_estacion
Importante🤖 Prompt para tu copiloto
Tengo esta tabla de métricas por estación [pegar resumen_estacion].
Las estaciones van de E1 (cabecera, 870 m) a E6 (desembocadura,
15 m) y E4 está aguas abajo de una descarga municipal.
¿Qué patrones ecológicos observas? ¿Qué hipótesis plantearías
y qué análisis estadístico usarías para ponerlas a prueba?

Contrasta su interpretación con la tuya. ¿Propone pruebas adecuadas para conteos con réplicas? Lo verás en el Módulo 3.

3.6 Unir tablas con left_join()

Nuestros datos están en tres tablas relacionadas por columnas en común. left_join() las une conservando todas las filas de la tabla de la izquierda:

Código
datos_integrados <- metricas_muestra |>
  left_join(fq |> select(muestra, temperatura_c, od_mg_l, ph,
                         conductividad_us_cm, turbidez_ntu, velocidad_m_s),
            by = "muestra") |>
  left_join(estaciones |> mutate(estacion = factor(estacion, levels = orden_estaciones)),
            by = "estacion")

glimpse(datos_integrados)
Rows: 36
Columns: 18
$ muestra             <chr> "E1-L-R1", "E1-L-R2", "E1-L-R3", "E1-S-R1", "E1-S-…
$ estacion            <fct> E1, E1, E1, E1, E1, E1, E2, E2, E2, E2, E2, E2, E3…
$ epoca               <fct> Lluvias, Lluvias, Lluvias, Seca, Seca, Seca, Lluvi…
$ riqueza             <int> 29, 28, 29, 27, 29, 29, 27, 28, 26, 30, 27, 28, 19…
$ abundancia_total    <dbl> 180, 239, 195, 568, 307, 420, 158, 286, 340, 665, …
$ riqueza_ept         <int> 12, 12, 11, 10, 9, 11, 8, 10, 9, 11, 9, 11, 4, 7, …
$ prop_chironomidae   <dbl> 0.361111111, 0.259414226, 0.112820513, 0.191901408…
$ temperatura_c       <dbl> 18.6, 18.6, 19.3, 20.6, 20.1, 20.7, 21.5, 21.5, 21…
$ od_mg_l             <dbl> 8.39, 8.54, 8.22, 8.09, 7.83, 8.24, 7.61, 8.61, 8.…
$ ph                  <dbl> 7.13, 7.12, 7.32, 7.22, 7.12, 7.11, 7.11, 7.17, 7.…
$ conductividad_us_cm <dbl> 36, 51, 43, 58, 40, 67, 80, 81, 101, 89, 79, 97, 1…
$ turbidez_ntu        <dbl> 9.0, 8.6, 9.9, 3.1, 2.8, 3.4, 11.4, 12.1, 14.5, 5.…
$ velocidad_m_s       <dbl> 1.10, 1.07, 1.25, 0.85, 0.82, 0.92, 1.00, 0.85, 0.…
$ nombre              <chr> "Cabecera", "Cabecera", "Cabecera", "Cabecera", "C…
$ altitud_m           <dbl> 870, 870, 870, 870, 870, 870, 610, 610, 610, 610, …
$ latitud             <dbl> 11.0312, 11.0312, 11.0312, 11.0312, 11.0312, 11.03…
$ longitud            <dbl> -73.4521, -73.4521, -73.4521, -73.4521, -73.4521, …
$ uso_suelo           <chr> "Bosque", "Bosque", "Bosque", "Bosque", "Bosque", …

Esta tabla, con una fila por muestra, las métricas biológicas, las variables ambientales y las características de la estación, es la base para relacionar biología y ambiente en el Módulo 3.

3.7 Formato largo y formato ancho: la matriz de comunidad

Este es probablemente el concepto más importante del módulo para el análisis ecológico.

  • Formato largo (long): una fila por cada combinación muestra–taxón. Así se digitan los datos en campo y así trabajan dplyr y ggplot2.
  • Formato ancho (wide): una fila por muestra y una columna por taxón. Es la matriz de comunidad que exigen vegan, iNEXT, betapart y casi todo el análisis multivariado.

3.7.1 De largo a ancho con pivot_wider()

Código
matriz_comunidad <- macro |>
  group_by(muestra, familia) |>
  summarise(abundancia = sum(abundancia), .groups = "drop") |>   # por si hay duplicados
  pivot_wider(names_from  = familia,
              values_from = abundancia,
              values_fill = 0) |>          # ausencia = 0 individuos
  arrange(muestra) |>
  column_to_rownames("muestra")            # los nombres de muestra pasan a nombres de fila

dim(matriz_comunidad)        # muestras × familias
[1] 36 33
Código
matriz_comunidad[1:6, 1:6]
Advertencia⚠️ ¿Por qué values_fill = 0?

En formato largo solo registramos lo que se encontró. Al pasar a matriz, las combinaciones muestra–familia que no existían quedarían como NA. En ecología de comunidades, no haber encontrado una familia en una muestra es una ausencia (0), no un dato faltante. Confundir ambos casos altera todos los índices de diversidad.

La matriz también se puede construir a nivel de estación, sumando las réplicas y épocas:

Código
matriz_estacion <- macro |>
  group_by(estacion, familia) |>
  summarise(abundancia = sum(abundancia), .groups = "drop") |>
  pivot_wider(names_from = familia, values_from = abundancia, values_fill = 0) |>
  column_to_rownames("estacion")

matriz_estacion[, 1:6]

3.7.2 De ancho a largo con pivot_longer()

La operación inversa es muy útil para graficar varias variables a la vez. Por ejemplo, todas las variables fisicoquímicas en un solo gráfico con paneles:

Código
fq_largo <- fq |>
  pivot_longer(cols      = c(temperatura_c, od_mg_l, ph, conductividad_us_cm,
                             turbidez_ntu, velocidad_m_s),
               names_to  = "variable",
               values_to = "valor")

fq_largo |> select(muestra, estacion, epoca, variable, valor) |> head(8)

3.8 Visualización con ggplot2

ggplot2 construye los gráficos por capas, siguiendo la gramática de gráficos:

ggplot(datos, aes(x = ..., y = ..., color = ...)) +   # datos y mapeo estético
  geom_*() +                                          # tipo de geometría
  labs() +                                            # títulos y etiquetas
  theme_*()                                           # apariencia

Definimos primero un tema base para que todos los gráficos sean consistentes:

Código
theme_set(theme_minimal(base_size = 13) +
            theme(plot.title = element_text(face = "bold"),
                  legend.position = "bottom"))

colores_epoca <- c("Seca" = "#D9822B", "Lluvias" = "#2B6CB0")

3.8.1 Composición de la comunidad: barras apiladas

Código
macro |>
  group_by(estacion, orden) |>
  summarise(abundancia = sum(abundancia), .groups = "drop") |>
  mutate(orden = fct_lump_n(orden, n = 7, w = abundancia, other_level = "Otros")) |>
  ggplot(aes(x = estacion, y = abundancia, fill = orden)) +
  geom_col(position = "fill", color = "white", linewidth = 0.2) +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_viridis_d(option = "turbo", begin = 0.05, end = 0.95) +
  labs(title = "Composición de la comunidad a lo largo del río",
       x = "Estación (cabecera → desembocadura)", y = "Abundancia relativa",
       fill = "Orden") +
  guides(fill = guide_legend(nrow = 2))

Composición relativa de órdenes de macroinvertebrados por estación (ambas épocas).

3.8.2 Riqueza por estación: boxplot con puntos

Código
ggplot(metricas_muestra, aes(x = estacion, y = riqueza, fill = epoca)) +
  geom_boxplot(alpha = 0.6, outlier.shape = NA) +
  geom_point(position = position_jitterdodge(jitter.width = 0.15, seed = 1),
             size = 2, alpha = 0.8, aes(color = epoca), show.legend = FALSE) +
  scale_fill_manual(values = colores_epoca) +
  scale_color_manual(values = colores_epoca) +
  labs(title = "Riqueza de familias por estación",
       x = "Estación", y = "Riqueza (n.º de familias)", fill = "Época")

Riqueza de familias por muestra en cada estación y época. Cada punto es una réplica.

3.8.3 Media ± error estándar

Código
metricas_muestra |>
  group_by(estacion, epoca) |>
  summarise(media = mean(riqueza_ept),
            ee    = sd(riqueza_ept) / sqrt(n()),
            .groups = "drop") |>
  ggplot(aes(x = estacion, y = media, fill = epoca)) +
  geom_col(position = position_dodge(0.8), width = 0.7, alpha = 0.85) +
  geom_errorbar(aes(ymin = media - ee, ymax = media + ee),
                position = position_dodge(0.8), width = 0.25) +
  scale_fill_manual(values = colores_epoca) +
  labs(title = "Riqueza EPT por estación",
       x = "Estación", y = "Riqueza EPT (media ± EE)", fill = "Época")

Riqueza media de familias EPT por estación y época (barras de error: ± 1 error estándar, n = 3).
Advertencia⚠️ Desviación estándar ≠ error estándar

La desviación estándar (DE) describe la variabilidad de los datos. El error estándar (EE = DE/√n) describe la precisión de la media. Indica siempre en la leyenda cuál estás mostrando: es uno de los errores más frecuentes en manuscritos y en código generado por IA.

3.8.4 Relación biología–ambiente: dispersión con tendencia

Código
datos_integrados |>
  filter(!is.na(od_mg_l)) |>
  ggplot(aes(x = od_mg_l, y = riqueza_ept)) +
  geom_smooth(method = "lm", se = TRUE, color = "grey30", linewidth = 0.8) +
  geom_point(aes(color = estacion, shape = epoca), size = 3, alpha = 0.85) +
  scale_color_viridis_d(option = "viridis", end = 0.9) +
  labs(title = "Oxígeno disuelto y riqueza EPT",
       x = "Oxígeno disuelto (mg/L)", y = "Riqueza EPT",
       color = "Estación", shape = "Época")

Relación entre el oxígeno disuelto y la riqueza EPT. La línea muestra un ajuste lineal exploratorio.

3.8.5 Gradiente fisicoquímico: paneles con facet_wrap()

Código
etiquetas_variables <- c(
  temperatura_c       = "Temperatura (°C)",
  od_mg_l             = "Oxígeno disuelto (mg/L)",
  ph                  = "pH",
  conductividad_us_cm = "Conductividad (µS/cm)",
  turbidez_ntu        = "Turbidez (NTU)",
  velocidad_m_s       = "Velocidad (m/s)"
)

fq_largo |>
  group_by(estacion, epoca, variable) |>
  summarise(valor = mean(valor, na.rm = TRUE), .groups = "drop") |>
  ggplot(aes(x = estacion, y = valor, color = epoca, group = epoca)) +
  geom_line(linewidth = 1) +
  geom_point(size = 2.5) +
  facet_wrap(~ variable, scales = "free_y", ncol = 3,
             labeller = labeller(variable = etiquetas_variables)) +
  scale_color_manual(values = colores_epoca) +
  labs(title = "Gradiente longitudinal de variables fisicoquímicas",
       x = "Estación", y = NULL, color = "Época")

Variables fisicoquímicas a lo largo del río (media por estación y época).

3.8.6 Mapa de calor de la matriz de comunidad

Código
matriz_estacion |>
  rownames_to_column("estacion") |>
  pivot_longer(-estacion, names_to = "familia", values_to = "abundancia") |>
  mutate(familia = fct_reorder(familia, abundancia * (estacion == "E1"), .fun = sum)) |>
  ggplot(aes(x = estacion, y = familia, fill = log10(abundancia + 1))) +
  geom_tile(color = "white") +
  scale_fill_viridis_c(option = "mako", direction = -1) +
  labs(title = "Matriz de comunidad",
       x = "Estación", y = NULL, fill = "log10(N + 1)") +
  theme(legend.position = "right",
        axis.text.y = element_text(face = "italic", size = 9))

Abundancia total (escala logarítmica) de cada familia por estación. Las familias están ordenadas por su abundancia en la estación de cabecera.
Importante🤖 Prompt para mejorar un gráfico
Este es mi código de ggplot2 [pegar código]. Quiero que el gráfico
cumpla los estándares de una revista científica: tipografía legible,
paleta accesible para daltónicos, sin elementos innecesarios y
exportable a 300 dpi. Sugiere cambios y explica cada uno.

3.9 Exportar resultados

Código
# Crear carpetas si no existen
dir.create("resultados", showWarnings = FALSE)
dir.create("figuras", showWarnings = FALSE)

# Tablas
write_csv(datos_integrados, "resultados/datos_integrados.csv")
write_csv(matriz_comunidad |> rownames_to_column("muestra"),
          "resultados/matriz_comunidad.csv")
writexl::write_xlsx(list(metricas = metricas_muestra,
                         resumen  = resumen_estacion),
                    "resultados/metricas_macroinvertebrados.xlsx")

# Figuras: guardar un gráfico en un objeto y exportarlo
fig_ept <- ggplot(datos_integrados, aes(od_mg_l, riqueza_ept)) +
  geom_point(aes(color = estacion), size = 3)

ggsave("figuras/od_vs_ept.png", plot = fig_ept,
       width = 18, height = 12, units = "cm", dpi = 300)
Tip💡 Consejo

Guarda la matriz de comunidad y la tabla de datos integrados: serán el punto de partida de los Módulos 3 y 4.

Ejercicio.

  1. A partir de macro, calcula para cada muestra la abundancia de los órdenes Ephemeroptera, Plecoptera y Trichoptera y la proporción EPT (abundancia EPT / abundancia total).
  2. Une el resultado con fq y grafica la proporción EPT contra la conductividad, coloreando por estación.
  3. Pídele a tu copiloto que interprete el gráfico. ¿Menciona la estación E4 y su posible causa? ¿Sugiere algo que no se sostiene con los datos?

Solución:

Código
prop_ept <- macro |>
  group_by(muestra) |>
  summarise(abund_ept = sum(abundancia[orden %in% c("Ephemeroptera", "Plecoptera", "Trichoptera")]),
            abund_total = sum(abundancia),
            .groups = "drop") |>
  mutate(prop_ept = abund_ept / abund_total) |>
  left_join(fq |> select(muestra, estacion, epoca, conductividad_us_cm), by = "muestra")

ggplot(prop_ept, aes(conductividad_us_cm, prop_ept, color = estacion)) +
  geom_point(size = 3) +
  scale_y_continuous(labels = scales::percent) +
  scale_color_viridis_d(end = 0.9) +
  labs(x = "Conductividad (µS/cm)", y = "Proporción EPT", color = "Estación")

Proporción de individuos EPT frente a la conductividad.

4 Bloque C — Datos abiertos de biodiversidad

Además de tus datos de campo, puedes complementar tus análisis con millones de registros públicos. La Infraestructura Mundial de Información en Biodiversidad (GBIF) reúne datos de museos, colecciones y ciencia ciudadana de todo el mundo, incluidas las observaciones de iNaturalist con grado de investigación. En Colombia, el nodo nacional es el SiB Colombia, que publica sus datos a través de GBIF.

El paquete rgbif permite consultarlos directamente desde R.

Advertencia⚠️ Requiere conexión a internet

Los bloques de esta sección no se ejecutan al renderizar la guía porque dependen de la conexión y de la disponibilidad del servicio. Ejecútalos tú en tu sesión.

4.1 Buscar un taxón en el árbol taxonómico de GBIF

Antes de descargar registros conviene verificar el nombre y obtener su identificador (usageKey). Usaremos Anacroneuria (Plecoptera: Perlidae), un género de perlas sensible a la contaminación y común en los ríos de la Sierra Nevada:

Código
library(rgbif)

taxon <- name_backbone(name = "Anacroneuria", rank = "genus")
taxon |> select(usageKey, scientificName, rank, status, family, order)

4.2 Descargar ocurrencias

Código
# ¿Cuántos registros hay en Colombia?
occ_count(taxonKey = taxon$usageKey, country = "CO")

# Descargar hasta 1000 registros con coordenadas
anacroneuria <- occ_search(
  taxonKey      = taxon$usageKey,
  country       = "CO",
  hasCoordinate = TRUE,
  limit         = 1000
)$data

anacroneuria |>
  select(scientificName, decimalLatitude, decimalLongitude,
         stateProvince, year, basisOfRecord, institutionCode) |>
  head()

4.3 Observaciones de iNaturalist

Las observaciones de iNaturalist con grado de investigación llegan a GBIF como un conjunto de datos propio, así que se pueden filtrar por su identificador:

Código
inat_key <- "50c9509d-22c7-4a22-a47d-8c48425ef4a7"  # iNaturalist Research-grade Observations

odonatos_guajira <- occ_search(
  orderKey      = name_backbone(name = "Odonata", rank = "order")$usageKey,
  datasetKey    = inat_key,
  country       = "CO",
  stateProvince = "La Guajira",
  limit         = 500
)$data

odonatos_guajira |> count(family, sort = TRUE)

4.4 Limpiar y mapear los registros

Los datos abiertos también necesitan limpieza: coordenadas imprecisas, registros duplicados y nombres sin resolver.

Código
anacroneuria_limpio <- anacroneuria |>
  filter(!is.na(decimalLatitude),
         is.na(coordinateUncertaintyInMeters) | coordinateUncertaintyInMeters < 5000) |>
  distinct(species, decimalLatitude, decimalLongitude, .keep_all = TRUE)

ggplot(anacroneuria_limpio, aes(decimalLongitude, decimalLatitude)) +
  borders("world", regions = "Colombia", fill = "grey95", colour = "grey60") +  # requiere el paquete maps
  geom_point(aes(color = basisOfRecord), alpha = 0.7, size = 2) +
  coord_quickmap() +
  labs(title = "Registros de Anacroneuria en Colombia (GBIF)",
       x = "Longitud", y = "Latitud", color = "Tipo de registro")
Tip💡 Cita siempre los datos de GBIF

occ_search() es ideal para explorar. Para un artículo o una tesis usa occ_download(), que requiere una cuenta gratuita en gbif.org y genera un DOI citable para exactamente los registros que usaste. Citar el DOI reconoce el trabajo de las colecciones y hace tu análisis reproducible.

Importante🤖 Prompt para tu copiloto
Descargué registros de GBIF con rgbif para un género de
macroinvertebrados acuáticos en Colombia. Tengo las columnas
decimalLatitude, decimalLongitude, coordinateUncertaintyInMeters,
basisOfRecord, year y species. ¿Qué pasos de control de calidad
me recomiendas antes de usarlos en un análisis de distribución?
Sugiere código con dplyr y menciona paquetes especializados.

Verifica que los paquetes que te sugiera (por ejemplo CoordinateCleaner) existan y estén vigentes.

Ejercicio. Elige una familia de macroinvertebrados de nuestra base (por ejemplo, Psephenidae o Corydalidae) y:

  1. Obtén su usageKey con name_backbone().
  2. Cuenta cuántos registros con coordenadas hay en Colombia.
  3. Descarga los registros y haz una tabla con el número de registros por departamento (stateProvince).

¿Qué departamentos tienen más registros? ¿Refleja eso la distribución real de la familia o el esfuerzo de muestreo? Discútelo con tu copiloto.

5 Cierre del módulo

5.1 Lo que aprendiste

5.2 Lo que viene

En el Módulo 3 usarás datos_integrados y matriz_comunidad para:

  • Comparar estaciones con pruebas de hipótesis y verificar supuestos.
  • Ordenar las comunidades con PCA, NMDS y RDA/CCA.
  • Calcular índices de bioindicación (BMWP/Col, EPT).
  • Analizar la diversidad con números de Hill, rarefacción (iNEXT) y diversidad beta.

5.3 Banco de prompts del módulo

Situación Prompt sugerido
Error que no entiendes “Ejecuté este código [código] y obtuve este error [error]. Explícame en lenguaje sencillo qué significa, por qué ocurre y cómo corregirlo.”
Entender código ajeno “Explícame línea por línea qué hace este código de R, como si yo fuera un biólogo que empieza a programar: [código]”
Traducir de R base a tidyverse “Reescribe este código usando dplyr y el pipe nativo |>, manteniendo el mismo resultado: [código]”
Revisar un análisis “Revisa este código de análisis ecológico y señala posibles errores lógicos o estadísticos, no solo de sintaxis: [código]”
Elegir un gráfico “Tengo estas variables [glimpse]. Quiero mostrar [objetivo]. ¿Qué tipo de gráfico de ggplot2 me recomiendas y por qué?”

5.4 Errores frecuentes y cómo leerlos

Mensaje de error Qué significa Solución habitual
could not find function "..." El paquete no está cargado o el nombre está mal escrito Ejecuta library(paquete) y revisa la ortografía
object '...' not found El objeto no existe en la sesión Ejecuta antes el bloque que lo crea; revisa mayúsculas y minúsculas
there is no package called '...' El paquete no está instalado install.packages("paquete")
'...' does not exist in current working directory R no encuentra el archivo Verifica que abriste el proyecto y que el archivo está en datos/
unexpected symbol / unexpected ')' Error de sintaxis: falta una coma, un paréntesis o unas comillas Revisa la línea indicada y la anterior
argument is not numeric or logical Aplicaste una función numérica a texto Revisa el tipo de la columna con glimpse()

5.5 Información de la sesión

Incluir sessionInfo() al final de tus documentos permite saber con qué versiones de R y de los paquetes se obtuvieron los resultados:

Código
sessionInfo()
R version 4.3.3 (2024-02-29 ucrt)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 11 x64 (build 26200)

Matrix products: default


locale:
[1] LC_COLLATE=Spanish_Spain.utf8  LC_CTYPE=Spanish_Spain.utf8   
[3] LC_MONETARY=Spanish_Spain.utf8 LC_NUMERIC=C                  
[5] LC_TIME=Spanish_Spain.utf8    

time zone: America/Bogota
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] janitor_2.2.1   readxl_1.4.5    lubridate_1.9.3 forcats_1.0.0  
 [5] stringr_1.6.0   dplyr_1.2.0     purrr_1.0.2     readr_2.1.5    
 [9] tidyr_1.3.2     tibble_3.2.1    ggplot2_4.0.2   tidyverse_2.0.0

loaded via a namespace (and not attached):
 [1] generics_0.1.4     lattice_0.22-6     stringi_1.8.3      hms_1.1.3         
 [5] digest_0.6.35      magrittr_2.0.3     evaluate_1.0.5     grid_4.3.3        
 [9] timechange_0.3.0   RColorBrewer_1.1-3 fastmap_1.1.1      Matrix_1.6-5      
[13] cellranger_1.1.0   jsonlite_1.8.8     mgcv_1.9-1         viridisLite_0.4.2 
[17] scales_1.4.0       cli_3.6.2          rlang_1.1.7        crayon_1.5.2      
[21] splines_4.3.3      bit64_4.0.5        withr_3.0.2        yaml_2.3.10       
[25] tools_4.3.3        parallel_4.3.3     tzdb_0.4.0         vctrs_0.7.1       
[29] R6_2.6.1           lifecycle_1.0.5    snakecase_0.11.1   htmlwidgets_1.6.4 
[33] bit_4.0.5          vroom_1.6.5        pkgconfig_2.0.3    pillar_1.11.0     
[37] gtable_0.3.6       glue_1.7.0         xfun_0.52          tidyselect_1.2.1  
[41] rstudioapi_0.16.0  knitr_1.50         farver_2.1.2       nlme_3.1-164      
[45] htmltools_0.5.8.1  rmarkdown_2.29     labeling_0.4.3     compiler_4.3.3    
[49] S7_0.2.1