Introducción

Los datos oceanográficos suelen provenir de diferentes fuentes como por ejemplo estaciones oceanográficas fijas, cruceros de investigación, información satelital, entre otras. Estos datos suelen ser estandarizados y venir en diferentes formatos de lectura e interpretación. A nivel general, los principales motores de análisis de datos convencionales suelen ser software como MatLab (de pago), Ocean Data View (libre) y plataformas específicas de acuerdo a los instrumentos de medición empleados.

En estos laboratorios el objetivo principal es que los estudiantes manipulen datos oceanográficos básicos, desarrollen recursos gráficos, generen análisis simples y sean capaces de inferir, interpretar y explicar los resultados gráficos de los datos trabajados.

Para estos laboratorios prácticos, haremos uso de R y RStudio como herramientas de lectura y análisis de datos. Cabe destacar que varios de los ejercicios que realizaremos en este laboratorio particular, pueden ser realizados en otras plataformas como Excel, Calc (LibreOffice) o Past.

Antes de comenzar este laboratorio, se recomienda revisar el video de instalación e introducción básica a R y RStudio, disponible en el aula virtual del curso GEO 1012.

1.- Configuración script en RStudio

Abra el programa RStudio y cree un nuevo script.

Identifique el número del práctico en el nombre del script y genere un encabezado adecuado para este utilizando el símbolo “#” para generar notas que no afecten la lectura del script ni generen errores en el procesamiento básico de los datos.

Configure el directorio de trabajo considerando la ubicación de los archivos del laboratorio. En este caso, es recomendable mantener un directorio de trabajo establecido en una ruta conocida y corta idealmente.

#set your working directoy
setwd("C:/lab_1") #replace to your path of files

1.1.- Instalación de librerías

Para el análisis básico de los datos en este práctico, se emplearán principalmente las funciones base de R, las funciones de filtro de la librería dplyr y las herramientas de lectura de la librería readxl para apertura de archivos Excel. Para instalar los paquetes puede emplear la función install.packages(c(‘tidyverse’,‘readxl’)) y luego de la instalación puede cargar la librería usando el comando library(tidyverse) y library(readxl). Realice la instalación de los paquetes una sola vez, luego de eso solo debe llamarlas utilizando la función library().

library('tidyverse')
library('readxl')

1.2.- Lectura de archivos

En este laboratorio se harán ejercicios de exploración de información empleando la tabla de nombre oceanografia2020.xls que se encuentra en el directorio de trabajo en la carpeta tablas. Los datos de esta tabla corresponden a un crucero oceanográfico realizado por el Instituto de Fomento Pesquero (IFOP) durante el año 2020 (marzo-abril) enmarcado en la “Evaluación hidroacústica de jurel entre las Regiones de Arica y Parinacota - Valparaíso, año 2020”. La información se compone de 135 estaciones oceanigráficas.

Esta información es de libre acceso y usted puede disponer de la totalidad de la misma en el sitio web de IFOP, en la sección Buscador de Informes.

Ya que R es un lenguaje orientado a objetos, la lectura de la tabla será guardada en un objeto que usted creará. La lectura de tablas se puede hacer de diversas formas; para este caso emplee el siguiente código:

#read data frames
CTD.df <- read_excel("oceanografia2020.xls")

Usted podrá ver el nuevo objeto creado en la pestaña Environment de su interfaz de trabajo.

2.- Exploración y manipulación de datos

2.1.- Exploración básica

Algunos aspectos claves de la exploración de información, consiste en identificar los campos disponibles y estadísticas básicas de los elementos a trabajar; esto con el fin de tener una mirada general de la información. Para identificar el tipo de objeto y las columnas disponibles haremos uso de las funciones class() y names().

class(CTD.df)
## [1] "tbl_df"     "tbl"        "data.frame"
names(CTD.df)
##  [1] "BUQUE"    "ESTACION" "LAT"      "MIN_LAT"  "LONG"     "MIN_LONG"
##  [7] "ANNO"     "MES"      "DIA"      "HORA"     "MINUTO"   "PROF"    
## [13] "TEMP"     "PSU"      "DENSIDAD" "OXIGENO"  "CLO_a"

Una forma simple de revisar las estadísticas es emplear la función summary(), que entrega algunas características generales de cualquier ojeto de R.

summary(CTD.df)
##     BUQUE              ESTACION           LAT           MIN_LAT     
##  Length:65535       Min.   :  1.00   Min.   :25.00   Min.   : 0.00  
##  Class :character   1st Qu.: 36.00   1st Qu.:27.00   1st Qu.:10.00  
##  Mode  :character   Median : 68.00   Median :29.00   Median :30.00  
##                     Mean   : 68.81   Mean   :28.68   Mean   :27.47  
##                     3rd Qu.:102.00   3rd Qu.:30.00   3rd Qu.:45.00  
##                     Max.   :135.00   Max.   :33.00   Max.   :55.00  
##                                                                     
##       LONG          MIN_LONG          ANNO           MES             DIA       
##  Min.   :70.00   Min.   : 0.00   Min.   :2020   Min.   :3.000   Min.   : 1.00  
##  1st Qu.:71.00   1st Qu.:20.10   1st Qu.:2020   1st Qu.:3.000   1st Qu.:17.00  
##  Median :71.00   Median :32.00   Median :2020   Median :3.000   Median :22.00  
##  Mean   :71.53   Mean   :32.61   Mean   :2020   Mean   :3.234   Mean   :19.17  
##  3rd Qu.:72.00   3rd Qu.:49.00   3rd Qu.:2020   3rd Qu.:3.000   3rd Qu.:27.00  
##  Max.   :73.00   Max.   :59.80   Max.   :2020   Max.   :4.000   Max.   :31.00  
##                                                                                
##       HORA           MINUTO           PROF            TEMP       
##  Min.   : 0.00   Min.   : 0.00   Min.   :  1.0   Min.   : 5.297  
##  1st Qu.: 6.00   1st Qu.:12.00   1st Qu.:130.0   1st Qu.: 7.749  
##  Median :11.00   Median :25.00   Median :278.0   Median :10.180  
##  Mean   :11.41   Mean   :26.96   Mean   :286.3   Mean   :10.160  
##  3rd Qu.:17.00   3rd Qu.:40.00   3rd Qu.:438.0   3rd Qu.:11.955  
##  Max.   :23.00   Max.   :59.00   Max.   :649.0   Max.   :20.779  
##                                                                  
##       PSU           DENSIDAD        OXIGENO          CLO_a      
##  Min.   :33.98   Min.   :24.46   Min.   :0.271   Min.   : 0.00  
##  1st Qu.:34.42   1st Qu.:26.33   1st Qu.:0.431   1st Qu.: 0.17  
##  Median :34.54   Median :26.64   Median :1.057   Median : 0.28  
##  Mean   :34.54   Mean   :26.52   Mean   :1.753   Mean   : 0.47  
##  3rd Qu.:34.66   3rd Qu.:26.91   3rd Qu.:2.694   3rd Qu.: 0.53  
##  Max.   :35.13   Max.   :27.14   Max.   :7.676   Max.   :16.60  
##                                                  NA's   :52923

Otra forma de calcular estadísticos es llamar algunas funciones como por ejemplo: mean(), sd(), median() o max(). Usted puede ver los argumentos de estas funciones usando el siguiente comando ?min. Recuerde que en un data frame existen elementos de texto u otros que pueden no ser captados por las funciones lo que arrojará el siguiente error:

mean(CTD.df) #error tipo 1
## Warning in mean.default(CTD.df): argument is not numeric or logical: returning
## NA
## [1] NA
mean(CTD.df$CLO_a) #error tipo 2
## [1] NA

Otro aspecto importante en las funciones de cálculos estadísticos es el uso del argumento na.rm, el cual entrega la orden (cuando se fija TRUE o T) de omitir las filas sin información. Si este argumento no se fija y existen filas sin datos, el restultado del estadístico sera NA.

#Ejemplos correctos
mean(CTD.df$CLO_a, na.rm = T) 
## [1] 0.4748549
sd(CTD.df$CLO_a, na.rm = T) 
## [1] 0.8052743
median(CTD.df$CLO_a, na.rm = T)
## [1] 0.28
min(CTD.df$CLO_a, na.rm = T) 
## [1] 0

2.2.- Manipulación básica

Seguiremos trabajando con los datos de CTD.df; para esto filtraremos la información de las primeras 50 filas y las columnas que disponen de información de profundidad y densidad (Sigma-t). La función head, nos sirve para visualizar en la consola los primeros valores de la tabla.

df50 <- CTD.df[1:50,c(12,15)] #filtered records
head(df50)#first rows

Esta es una forma de generar un conjunto del total de datos que sea de nuestro interés. Dentro de los [ ] indicamos los valores que queremos extraer; las filas son los elementos antes de la coma y las columnas lo que viene después de la coma. Note que después de la coma, se empleó un vector para seleccionar solo las columnas de interés. Si se deja la sección de las columnas vacía, R entiende que se quieren todas las columnas y pasa lo mismo si dejamos el espacio de las filas vacío, seleccionando todas las filas.

Si queremos ser un poco más específicos y eficientes con nuestras selecciones, podemos hacer filtros de información empleando los datos dentro de la tabla. Para esto usaremos las funciones de la librería dplyr cargada previamente en nuestro script.

En este caso, solo nos interesa desarrollar un análisis sobre una de las estaciones, para lo cual identificaremos las estaciones disponibles utilizando la función unique() sobre la columna Estación, que nos dará los valores únicos dentro de la columna. Luego haremos uso de la función filter(), considerando la estación 1 como aparece en el siguiente código:

#filtering stations
unique(CTD.df$ESTACION)
##   [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
##  [19]  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
##  [37]  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
##  [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
##  [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
##  [91]  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107 108
## [109] 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
## [127] 127 128 129 130 131 132 133 134 135
est.1 <- filter(CTD.df, ESTACION == 1) 

2.3.- Resúmenes de información

Además de las cosas que podemos calcular de forma directa empleando las funciones de base de R, también podemos realizar resúmenes estadísticos empleando algunas funciones de las librerías que se cargan al agregar tidyverse a nuestro entorno de trabajo.

Un flujo normal para obtener el promedio de temperatura por latitud sería algo como lo siguiente:

lat <- filter(CTD.df, LAT == 33)
mean(lat$TEMP)
## [1] 9.671937

El “problema” de esta aproximación es que si tenemos muchas latitudes (estaciones, zonas, cuadrantes, etc.) tendremos que repetir este procedimiento o deberemos armar un ciclio de programación que nos entregue el reporte.

Una alternativa para esto y muchos otros casos, puede ser el siguiente ejemplo que emplea funciones de dplyr (importado con tidyverse):

CTD.df %>% group_by(LAT) %>% summarise(mean_temp = mean(TEMP)) 

También, podríamos ver si ese promedio es representativo considerando el número de datos:

CTD.df %>% group_by(LAT) %>% summarise(n_datos = n()) 

También podemos realizar un resumen de varias estadísticas simultáneas, agrupando por algún criterio particular.

CTD.df %>% group_by(LAT) %>% 
  summarise(mean_temp = mean(TEMP),mean_psu = mean(PSU),
            mean_dens = mean(DENSIDAD),mean_ox = mean(OXIGENO),
            n_datos = n()) 

3.- Gráficando datos oceanográficos

Otra forma muy importante de analizar información cuantitativa y cualitativa es mediante la realización de gráficos. R dispone de un conjunto de funciones para graficar que puede ser llamarda usando plot().

plot(est.1$DENSIDAD)#sigma-t basic plot

Este gráfico nos muestra la información de una sola estación y un solo perfil. Una forma más útil de ver esta información para varias estaciones, sería el uso de boxplot como se muestra en el siguiente ejemplo:

#filtrando 10 estaciones
est.1_10 <- filter(CTD.df, ESTACION >= 1 & ESTACION <= 10) 

boxplot(est.1_10$DENSIDAD ~ est.1_10$ESTACION)#sigma-t basic boxplot

Con esta información ¿cuáles son las estaciones con mayor densidad y dónde se encuentran en relación a la costa? ¿cuáles son las estaciones con menos variabilidad y dónde se encuentran en relación a la costa? Finalmente ¿cómo explica la variabilidad de sigma-t en estas estaciones?

Los gráficos pueden ser estéticamente mejorados empleando diferentes argumentos como main, xlab, ylab entre otros (use ?plot para ver más argumentos). Ahora seleccionaremos una estación con información y procederemos a crear un perfil vertical de densidad básico, utilizando las funciones filter y plot.

data.1 <- filter(CTD.df,ESTACION == 1)#create a new dataframe with selected data

plot(data.1$DENSIDAD,data.1$PROF) #basic plot

Como podemos apreciar, el gráfico muestra la información en profundidad invertida y con etiquetas poco claras. Ahora realizaremos el mismo gráfico modificando argumentos que permitan facilitar la interpretación: xlab, ylab, ylim, type y main. Los argumentos xlab e ylab nos permiten modificar los nombres de los ejes de nuestros gráficos; ylim nos permitirá establecer valores mínimos y máximos de nuestro eje y; type nos proporciona el tipo de gráfico a realizar (puntos, lineas, etc.) y main nos permitirá poner un título a nuestro gráfico. Para asegurar que la información de profundidad esté correctamente desplegada, haremos uso de la función rev().

plot(data.1$DENSIDAD,data.1$PROF, xlab = 'Sigma t (kg/m^3)',
     ylab = 'Prof. (m)', ylim = rev(c(0,35)), type='l', 
     main = 'Sigma-t Estación 1') #customized plot

Con este gráfico ¿qué inferencias podemos realizar sobre la columna de agua y la distribución vertical de la densidad?

Finalmente, podemos extender las capacidades de análisis con gráficos que proporcionen más información. Un ejemplo de algunas cosas que veremos en el próximo laboratorio:

CTD.df %>% ggplot(aes(x = PSU, y = TEMP, color=OXIGENO)) +
    geom_point()+scale_color_viridis_c()

4.- Ejercicios

A continuación, dispone de una sección con algunos ejercicios prácticos para fortalecer lo visto en este laboratorio e incorporar análisis y aplicación de conceptos.

Fecha de entrega: 19 de Mayo, 2021

  1. Genere un reporte de estadísticas básicas (tabla) para los registros de: Temperatura, Salinidad, Densidad y Oxígeno disuelto. Considere los siguientes estadísticos: media, mediana, desviación estándar, mínimo y máximo

  2. Localice los registros de máxima y mínima temperatura observados en los datos e indique su posición en el data frame. Para esto investigue sobre las funciones which.min() y which.max()

  • ¿A qué estación/es corresponden el mínimo y el máximo observado?
  • ¿A qué profundidad se ubican el mínimo y el máximo observado?
  1. Calcule la desviación estandar de la temperatura y la salinidad para las estaciones que se encuentran a 70°39.0’ O y 73°32.2’ O. Genere un pequeño análisis de los resultados obtenidos.

  2. Construya un perfil de temperatura en profundidad para 3 estaciones dentro del dataframe (1 gráfico por estación). Realice un pequeño reporte de los resultados observados.