Hay algunos hábitos para la entrada de datos que facilitarán la importación de datos correctamente en R
:
Reserve la primera fila para el encabezado
Reserve la primera columna a la unidad de muestreo
Utilice "_“,”." o “-” en lugar de espacios vacíos (por ejemplo, “Cornell_University”)
Use nombres cortos
Evite usar símbolos poco comunes como?, $,%, ^, &, *, (,), -, #,? ,,, <,>, /, |, , [,], {, y}
Sea coherente cuando se refiera a las mismas cosas (es decir, escríbalas siempre de la misma manera)
Eliminar cualquier comentario adicional fuera de las columnas del conjunto de datos
Indicar valores faltantes con NA (o al menos espacios vacíos)
Ni siquiera piense en codificar por colores tus datos en Excel
Basado en la Guía de estilo R de Google
Los nombres de archivo deben terminar en ‘.R’ y, por supuesto, tener sentido:
Variables y funciones:
- BIEN: dia_uno: dia_1, dia.promedio(),
- MAL: diaUno, dia1, primer_dia.delmes, mean <- function(x) sum(x), c <- 10
Espaciado:
- BIEN:
a <- rnorm(n = 10, sd = 10, mean = 1)
tab.prior <- table(df[df$days.from.opt < 0, "campaign.id"])
total <- sum(x[, 1])
total <- sum(x[1, ])
if (debug)
mean(1:10)
- MAL:
a<-rnorm(n=10,sd=10,mean=1)
tab.prior <- table(df[df$days.from.opt<0, "campaign.id"]) # necesita espacio al lado de '<'
tab.prior <- table(df[df$days.from.opt < 0,"campaign.id"]) # necesita espacio despues de la coma
tab.prior<- table(df[df$days.from.opt < 0, "campaign.id"]) # necesita espacio antes de <-
tab.prior<-table(df[df$days.from.opt < 0, "campaign.id"]) # necesita espacio a los lados de <-
total <- sum(x[,1]) # necesita espacio despues de la coma
total <- sum(x[ ,1]) # necesita espacio despues de la coma, no antes
if(debug) # necesita espacio antes del parentesis
mean (1:10) # ) # espacio extra antes del parentesis
Llaves:
- BIEN:
if (is.null(ylim)) {
ylim <- c(0, 0.06)
}
if (is.null(ylim))
ylim <- c(0, 0.06)
- MAL:
if (is.null(ylim)) ylim <- c(0, 0.06)
if (is.null(ylim)) {ylim <- c(0, 0.06)}
if (is.null(ylim)) {
ylim <- c(0, 0.06)
}
Crear objetos:
- BIEN:
x <- 5
- MAL:
x = 5
Comentar el código:
# Crear un hisograma con la columna de gastos
hist(df$pct.spent,
breaks = "scott", # metodo para escoger numero de columnas
main = "Histograma: fraccion del presupuesto",
xlab = "Fraccion gastada",
ylab = "Frecuencia")
Importar datos a R
es un paso crucial y aparentemente simple. Sin embargo, dada la diversidad de formatos de datos y sistemas operativos, así como las muchas posibles fuentes de error, ingresar datos en R
no siempre es tan sencillo. La mayoría de los problemas están relacionados con:
Indicar a R
en qué directorio se encuentra el archivo
Indicar a R
cómo se codifican los datos (por ejemplo, separados por comas, ancho fijo, etc.)
Manejo de celdas vacías y caracteres poco comunes
Para leer datos en R, debe especificar el directorio de trabajo. Se puede configurar con la función setwd ()
. La forma de hacerlo depende del sistema operativo (Windows, Mac, Linux). La sintaxis del directorio de carpetas sigue la estructura anidada de las carpetas. Por ejemplo:
setwd("/inicio/m/Escritorio/")
… establece el directorio de trabajo en la carpeta “Escritorio”, que se encuentra dentro de “m”, que se encuentra dentro de “inicio”.
Algunos consejos básicos para configurar el directorio de trabajo:
Asegúrese de que se cita la ubicación
Asegúrese de tener una barra diagonal (/) entre los nombres de las carpetas (aunque las barras diagonales dobles parecen funcionar en Windows)
No incluya ningún nombre de archivo en el nombre del directorio de la carpeta
Para encontrar la ubicación, puede mirar las propiedades de un archivo en esa carpeta y copiarlo
La ruta a la carpeta debe citarse ("")
El nombre coincide exactamente (mejor copiar / pegar)
Use list.files ()
para verificar qué archivos están en el directorio de trabajo
R
puede sugerir y completar automáticamente los nombres de las carpetas presionando" tab "cuando está entre comillas:
Configuración del directorio de trabajo en Windows
En Windows debería ser algo como esto:
setwd("C:/carpeta")
También puede hacer esto (¡solo en Windows!):
setwd(choose.dir())
Eso debería abrir una ventana donde puedes elegir la ubicación. Sin embargo, esto solo debe usarse para descubrir la forma correcta de escribir la ubicación del directorio, no como parte del código en sí.
Configuración del directorio de trabajo en OSX (mac)
Para mac, la configuración del directorio de trabajo debería ser algo como esto:
setwd("/Usuarios/nombre/..")
no incluya lo que tenga antes de “usuarios” (como macintosh …)
Configuración del directorio de trabajo en Linux
Similar al código utilizado en OSX:
setwd("/inicio/m/Escritorio/")
El símbolo “~” (virgulilla) también se puede utilizar para omitir la carpeta “inicio” y “usuario” en Linux:
setwd("~/Escritorio/")
El directorio de trabajo actual se puede verificar de la siguiente manera:
getwd()
## [1] "/home/m/Dropbox/Cursos/R_avanzado_2019/Clases_M_Araya/Importar y dar formato a bases de datos"
Cualquier archivo se puede leer en R
. Solo se trata de informar a R
en qué formato está codificado el archivo (por ejemplo, qué convenciones se siguieron al generar el archivo). Los formatos más comunes para almacenar / intercambiar conjuntos de datos como los que usualmente manejamos en ciencias biológicas son txt, csv y xls/xlsx.
La función más utilizada para importar datos en R
esread.table
. La documentación de esta función en realidad incluye todas las funciones predeterminadas para ingresar datos:
?read.table
Los archivos txt se pueden leer usando read.table
. Primero descarguemos un conjunto de datos disponible gratuitamente en formato txt:
# definir directorio de trabajo
setwd("PONER EL NOMBRE DEL DIRECTORIO DONDE QUIERE GUARDAR LOS ARCHIVOS AQUI")
# bajar archivo
download.file("http://esapubs.org/archive/ecol/E090/184/PanTHERIA_1-0_WR93_Aug2008.txt", destfile = "pantheria_mammals_data.txt")
También puede descargar manualmente el archivo desde aquí.
El archivo se puede ingresar en R
de la siguiente manera:
# leer archivo
pntr_dt <- read.table("pantheria_mammals_data.txt", stringsAsFactors = FALSE, sep = "\t", header = TRUE)
# revisar la clase de los datos
sapply(pntr_dt[, 1:10], class)
# revisar estructura
head(pntr_dt)
MSW93_Order | MSW93_Family | MSW93_Genus | MSW93_Species | MSW93_Binomial | X1.1_ActivityCycle |
---|---|---|---|---|---|
Rodentia | Muridae | Abditomys | latidens | Abditomys latidens | -999 |
Rodentia | Muridae | Abrawayaomys | ruschii | Abrawayaomys ruschii | -999 |
Rodentia | Abrocomidae | Abrocoma | bennettii | Abrocoma bennettii | 1 |
Rodentia | Abrocomidae | Abrocoma | boliviensis | Abrocoma boliviensis | -999 |
Rodentia | Abrocomidae | Abrocoma | cinerea | Abrocoma cinerea | -999 |
Chiroptera | Pteropodidae | Acerodon | celebensis | Acerodon celebensis | -999 |
X5.1_AdultBodyMass_g | X8.1_AdultForearmLen_mm | X13.1_AdultHeadBodyLen_mm | X2.1_AgeatEyeOpening_d |
---|---|---|---|
268 | -999.00 | 223.99 | -999 |
63 | -999.00 | -999.00 | -999 |
251 | -999.00 | -999.00 | -999 |
158 | -999.00 | -999.00 | -999 |
194 | -999.00 | -999.00 | -999 |
382 | 133.49 | 201.55 | -999 |
El nombre del archivo se pone en comillas y debe incluir la extensión del archivo.
Tenga en cuenta que el valor -999 se utiliza para definir celdas vacías. Podemos leer estos valores como NA mientras importamos los datos usando el argumento ‘na.strings’:
# leer archivo
pntr_dt <- read.table("pantheria_mammals_data.txt", sep = "\t", header = TRUE, na.strings = "-999")
# revisar estructura
head(pntr_dt)
MSW93_Order | MSW93_Family | MSW93_Genus | MSW93_Species | MSW93_Binomial | X1.1_ActivityCycle |
---|---|---|---|---|---|
Rodentia | Muridae | Abditomys | latidens | Abditomys latidens | NA |
Rodentia | Muridae | Abrawayaomys | ruschii | Abrawayaomys ruschii | NA |
Rodentia | Abrocomidae | Abrocoma | bennettii | Abrocoma bennettii | 1 |
Rodentia | Abrocomidae | Abrocoma | boliviensis | Abrocoma boliviensis | NA |
Rodentia | Abrocomidae | Abrocoma | cinerea | Abrocoma cinerea | NA |
Chiroptera | Pteropodidae | Acerodon | celebensis | Acerodon celebensis | NA |
X5.1_AdultBodyMass_g | X8.1_AdultForearmLen_mm | X13.1_AdultHeadBodyLen_mm | X2.1_AgeatEyeOpening_d |
---|---|---|---|
268 | NA | 223.99 | NA |
63 | NA | NA | NA |
251 | NA | NA | NA |
158 | NA | NA | NA |
194 | NA | NA | NA |
382 | 133.49 | 201.55 | NA |
Nuevamente, podemos descargar un archivo de ejemplo en línea:
# bajar archivo
download.file("http://www.birds.cornell.edu/clementschecklist/wp-content/uploads/2019/08/eBird_Taxonomy_v2019.csv", destfile = "clements_bird_list.csv")
# leer archivo
clm_lst <- read.csv("clements_bird_list.csv", stringsAsFactors = FALSE)
head(clm_lst)
TAXON_ORDER | CATEGORY | SPECIES_CODE | PRIMARY_COM_NAME | SCI_NAME |
---|---|---|---|---|
3 | species | ostric2 | Common Ostrich | Struthio camelus |
5 | species | ostric3 | Somali Ostrich | Struthio molybdophanes |
6 | slash | y00934 | Common/Somali Ostrich | Struthio camelus/molybdophanes |
7 | species | grerhe1 | Greater Rhea | Rhea americana |
13 | species | lesrhe2 | Lesser Rhea | Rhea pennata |
14 | issf | lesrhe4 | Lesser Rhea (Puna) | Rhea pennata tarapacensis/garleppi |
ORDER1 | FAMILY | SPECIES_GROUP | REPORT_AS |
---|---|---|---|
Struthioniformes | Struthionidae (Ostriches) | Ostriches | |
Struthioniformes | Struthionidae (Ostriches) | ||
Struthioniformes | Struthionidae (Ostriches) | ||
Rheiformes | Rheidae (Rheas) | Rheas | |
Rheiformes | Rheidae (Rheas) | ||
Rheiformes | Rheidae (Rheas) | lesrhe2 |
También puede descargar manualmente el archivo desde aquí
Como en el ejemplo anterior, podemos decirle a R
cómo identificar celdas vacías usando el argumento ‘na.strings’:
# bajar archivo
download.file("http://www.birds.cornell.edu/clementschecklist/wp-content/uploads/2019/08/eBird_Taxonomy_v2019.csv", destfile = "clements_bird_list.csv")
# leer archivo
clm_lst <- read.csv("clements_bird_list.csv", stringsAsFactors = FALSE)
# ver datos
head(clm_lst)
TAXON_ORDER | CATEGORY | SPECIES_CODE | PRIMARY_COM_NAME | SCI_NAME |
---|---|---|---|---|
3 | species | ostric2 | Common Ostrich | Struthio camelus |
5 | species | ostric3 | Somali Ostrich | Struthio molybdophanes |
6 | slash | y00934 | Common/Somali Ostrich | Struthio camelus/molybdophanes |
7 | species | grerhe1 | Greater Rhea | Rhea americana |
13 | species | lesrhe2 | Lesser Rhea | Rhea pennata |
14 | issf | lesrhe4 | Lesser Rhea (Puna) | Rhea pennata tarapacensis/garleppi |
ORDER1 | FAMILY | SPECIES_GROUP | REPORT_AS |
---|---|---|---|
Struthioniformes | Struthionidae (Ostriches) | Ostriches | NA |
Struthioniformes | Struthionidae (Ostriches) | NA | NA |
Struthioniformes | Struthionidae (Ostriches) | NA | NA |
Rheiformes | Rheidae (Rheas) | Rheas | NA |
Rheiformes | Rheidae (Rheas) | NA | NA |
Rheiformes | Rheidae (Rheas) | NA | lesrhe2 |
La mayoría de los investigadores ingresan datos en hojas de cálculo de Excel. Por lo tanto, sería bastante útil leer los datos directamente desde allí. Para leer los archivos xls y xlsx necesitamos instalar el paquete “readxl” (hay otros paquetes que se pueden usar pero todos funcionan de manera similar):
install.packages(pkgs = "readxl")
… y cargarglo:
library(readxl)
Como hicimos anteriormente, descargue un archivo de ejemplo de un repositorio en línea. En este caso, es la misma lista de taxonomía de aves Clements en formato xlsx:
download.file("http://www.birds.cornell.edu/clementschecklist/wp-content/uploads/2017/08/eBird_Taxonomy_v2017_18Aug2017.xlsx", destfile = "clements_bird_list.xlsx")
También puede descargar manualmente el archivo desde aquí.
Ahora podemos usar la función read_excel()
para leer el archivo:
# leer archivo
clm_lst2 <- read_excel("clements_bird_list.xlsx", sheet = 1)
# ver datos
head(clm_lst2)
TAXON_ORDER | CATEGORY | SPECIES_CODE | PRIMARY_COM_NAME | SCI_NAME |
---|---|---|---|---|
3 | species | ostric2 | Common Ostrich | Struthio camelus |
5 | species | ostric3 | Somali Ostrich | Struthio molybdophanes |
6 | slash | y00934 | Common/Somali Ostrich | Struthio camelus/molybdophanes |
7 | species | grerhe1 | Greater Rhea | Rhea americana |
13 | species | lesrhe2 | Lesser Rhea | Rhea pennata |
14 | issf | lesrhe4 | Lesser Rhea (Puna) | Rhea pennata tarapacensis/garleppi |
ORDER1 | FAMILY | SPECIES_GROUP | REPORT_AS |
---|---|---|---|
Struthioniformes | Struthionidae (Ostriches) | Ostriches | NA |
Struthioniformes | Struthionidae (Ostriches) | NA | NA |
Struthioniformes | Struthionidae (Ostriches) | NA | NA |
Rheiformes | Rheidae (Rheas) | Rheas | NA |
Rheiformes | Rheidae (Rheas) | NA | NA |
Rheiformes | Rheidae (Rheas) | NA | lesrhe2 |
Debe especificar el nombre del archivo (incluida la extensión) y el nombre de la hoja de Excel (pestaña). read_excel()
auto detecta el formato de la extensión del archivo. Las funciones read_xls()
y read_xlsx()
se pueden usar para leer archivos sin extensión.
Ejercicio 1
Todas las funciones predeterminadas para ingresar datos en R
tienen una contraparte para exportar el mismo tipo de datos. Los nombres de estas otras funciones son similares a los de lectura de datos, aunque generalmente comienzan con “write” o “save”.
1.1 ¿Cuáles son los nombres de las funciones predeterminadas para exportar los formatos de datos que utilizamos anteriormente? (sugerencia: intente apropos()
para verificar qué funciones están disponibles)
1.2 Exporte los datos de mamíferos como un archivo .csv
1.3 Exporte los datos de mamíferos nuevamente, esta vez excluyendo los nombres de las filas
1.4 Lea el archivo .csv usando read.table
1.5 ¿Qué otros paquetes pueden importar archivos de Excel en R
?
1.6 ¿Puede exportar un archivo de Excel o agregar datos a un archivo de Excel existente desde R
?
1.7 Usando el archivo “clements_bird_list.csv”, ¿cómo le dirías a R
que lea “Rheiformes”y “Avestruces” (Ostriches) como celdas vacías (mientras sigue leyendo celdas vacías como celdas vacías)?
Esta sección trate acerca de organizar sus datos de una manera que simplifique su manejo, exploración y análisis. Como probablemente pueda adivinar, cuanto más consistentes se hagan las cosas, más predecibles se volverán. Esto también se aplica a los datos. Si los datos se organizan con la misma lógica, puede esperar que se aplique el mismo tipo de manipulaciones y análisis en diferentes conjuntos de datos. Organizar los datos es un aspecto clave (pero generalmente descuidado) del flujo de trabajo de análisis de datos. Cuando los datos se organizan correctamente, pasará mucho menos tiempo formateando y más tiempo en las preguntas analíticas reales.
Cuando sea posible, ejecutaremos los ejemplos de formato de datos utilizando tanto el paquete ‘tidyr’ como las funciones base R
.
“Tidy data” es una lógica para organizar conjuntos de datos de manera coherente e intuitiva. Para ejecutar parte del código a continuación, necesitará los paquetes ‘tidyr’ y ‘dplyr’, que pueden instalarse/cargarse de la siguiente manera:
# instalar paquetes
install.packages(pkgs = c("tidyr", "dplyr"))
# cargar paquetes
library(tidyr)
library(dplyr)
Los mismos datos se pueden representar de muchas maneras. En el siguiente ejemplo, cada conjunto de datos muestra exactamente los mismos valores de cuatro variables country, year, population y cases, pero en cada conjunto de datos los valores se organizan de manera diferente. Los datos muestran el número de casos de tuberculosis en Afganistán, Brasil y China entre 1999 y 2000:
# ver datos
as.data.frame(table1)
country | year | cases | population |
---|---|---|---|
Afghanistan | 1999 | 745 | 19987071 |
Afghanistan | 2000 | 2666 | 20595360 |
Brazil | 1999 | 37737 | 172006362 |
Brazil | 2000 | 80488 | 174504898 |
China | 1999 | 212258 | 1272915272 |
China | 2000 | 213766 | 1280428583 |
# ver datos
as.data.frame(table2)
country | year | type | count |
---|---|---|---|
Afghanistan | 1999 | cases | 745 |
Afghanistan | 1999 | population | 19987071 |
Afghanistan | 2000 | cases | 2666 |
Afghanistan | 2000 | population | 20595360 |
Brazil | 1999 | cases | 37737 |
Brazil | 1999 | population | 172006362 |
Brazil | 2000 | cases | 80488 |
Brazil | 2000 | population | 174504898 |
China | 1999 | cases | 212258 |
China | 1999 | population | 1272915272 |
China | 2000 | cases | 213766 |
China | 2000 | population | 1280428583 |
# ver datos
as.data.frame(table3)
country | year | rate |
---|---|---|
Afghanistan | 1999 | 745/19987071 |
Afghanistan | 2000 | 2666/20595360 |
Brazil | 1999 | 37737/172006362 |
Brazil | 2000 | 80488/174504898 |
China | 1999 | 212258/1272915272 |
China | 2000 | 213766/1280428583 |
O incluso distribuido en 2 conjuntos de datos diferentes:
# ver datos
as.data.frame(table4a)
country | 1999 | 2000 |
---|---|---|
Afghanistan | 745 | 2666 |
Brazil | 37737 | 80488 |
China | 212258 | 213766 |
# ver datos
as.data.frame(table4b)
country | 1999 | 2000 |
---|---|---|
Afghanistan | 19987071 | 20595360 |
Brazil | 172006362 | 174504898 |
China | 1272915272 | 1280428583 |
Todos estos conjuntos de datos contenían los mismos datos subyacentes. Sin embargo, no son igualmente fáciles de usar.
Hay tres reglas interrelacionadas para ordenar un conjunto de datos:
Cada variable debe tener su propia columna
Cada observación debe tener su propia fila
Cada valor debe tener su propia celda
Esta figura muestra las reglas visualmente:
*Modificado de R para Data Science
Estas tres reglas están interrelacionadas porque es imposible satisfacer solo dos de las tres. Esa interrelación conduce a un conjunto aún más simple de instrucciones prácticas:
Coloque cada conjunto de datos en un marco de datos
Ponga cada variable en una columna
En el ejemplo anterior, solo table1
es ordenado. Es la única representación donde cada columna es una variable. Hay dos ventajas principales de formatear los datos de esta manera:
Si tiene una estructura de datos coherente, es más fácil aprender las herramientas que funcionan con ella porque tienen una uniformidad subyacente
Colocar variables en columnas se ajusta bien a la naturaleza vectorizada de R
. Como hemos visto, las funciones incorporadas R
funcionan con vectores de valores. Eso hace que la transformación de datos ordenados se sienta particularmente natural
Ejercicio 2
2.1 Describa cómo se organizan las variables y observaciones en cada uno de los marcos de datos de muestra
2.2 Calcule la tasa de casos por 10000 personas para “table1”, “table2” y “table4a” / “table4b”
Un problema común es un conjunto de datos donde algunos de los nombres de columna no son nombres de variables, sino valores de una variable. Tome “table4a”: los nombres de columna 1999 y 2000 representan valores de la variable del año, y cada fila representa dos observaciones, no una:
# ver datos
as.data.frame(table4a)
country | 1999 | 2000 |
---|---|---|
Afghanistan | 745 | 2666 |
Brazil | 37737 | 80488 |
China | 212258 | 213766 |
Para ordenar un conjunto de datos como este, necesitamos juntar esas columnas en un nuevo par de variables. Para hacer esto necesitamos tres parámetros:
El conjunto de columnas que representan valores, no variables. En este ejemplo, esas son las columnas ‘1999’ y ’2000`
El nombre de la variable cuyos valores forman los nombres de columna. En la sintaxis ‘tidyr’ que se llama la clave (key), que en este caso es year
El nombre de la variable cuyos valores se extienden por las celdas. En la sintaxis ‘tidyr’ que se llama ese valor (value), que en este caso es el número de cases
Estos parámetros se pueden usar para crear un conjunto de datos ordenado usando la función gather()
:
# unir
gather(table4a, key = "year", value = "cases", `1999`, `2000`)
country | year | cases |
---|---|---|
Afghanistan | 1999 | 745 |
Brazil | 1999 | 37737 |
China | 1999 | 212258 |
Afghanistan | 2000 | 2666 |
Brazil | 2000 | 80488 |
China | 2000 | 213766 |
Podemos visualizar este formato de la siguiente manera:
* Modificado de R para Data Science
gather()
también se puede usar para ordenar table4b
. La única diferencia es la variable almacenada en los valores de la celda:
#unir
gather(data = table4b, key = "year", value = "population", `1999`, `2000`)
country | year | population |
---|---|---|
Afghanistan | 1999 | 19987071 |
Brazil | 1999 | 172006362 |
China | 1999 | 1272915272 |
Afghanistan | 2000 | 20595360 |
Brazil | 2000 | 174504898 |
China | 2000 | 1280428583 |
Para combinar las versiones ordenadas de table4a
ytable4b
en un solo marco de datos (o ‘tibble’), podemos usar dplyr::left_join()
:
# unir
tidy4a <- gather(table4a, key = "year", value = "cases", `1999`, `2000`)
# unir
tidy4b <- gather(table4b, key = "year", value = "population", `1999`, `2000`)
left_join(x = tidy4a, y = tidy4b, by = c("country", "year"))
country | year | cases | population |
---|---|---|---|
Afghanistan | 1999 | 745 | 19987071 |
Brazil | 1999 | 37737 | 172006362 |
China | 1999 | 212258 | 1272915272 |
Afghanistan | 2000 | 2666 | 20595360 |
Brazil | 2000 | 80488 | 174504898 |
China | 2000 | 213766 | 1280428583 |
Tambien podemos usar la función merge()
de R
básico, la cual identifica columnas en común de dos bases de datos distintas:
# combinar
merge(x = tidy4a, y = tidy4b)
country | year | cases | population |
---|---|---|---|
Afghanistan | 1999 | 745 | 19987071 |
Afghanistan | 2000 | 2666 | 20595360 |
Brazil | 1999 | 37737 | 172006362 |
Brazil | 2000 | 80488 | 174504898 |
China | 1999 | 212258 | 1272915272 |
China | 2000 | 213766 | 1280428583 |
Lo cual es equivalente a:
# combinar
merge(x = tidy4a, y = tidy4b, by = c("country", "year"))
country | year | cases | population |
---|---|---|---|
Afghanistan | 1999 | 745 | 19987071 |
Afghanistan | 2000 | 2666 | 20595360 |
Brazil | 1999 | 37737 | 172006362 |
Brazil | 2000 | 80488 | 174504898 |
China | 1999 | 212258 | 1272915272 |
China | 2000 | 213766 | 1280428583 |
Como se muestra, la función merge()
encuentra automáticamente las columnas en común entre las dos bases de datos.
La función merge()
tiene un número grande de argumentos. Sin embargo, estos se pueden resumir en cuatro grupos:
x: base de datos 1
y: base de datos 2
by, by.x, by.y: nombres de las columnas en común de la base de datos 1 y base de datos 2. Lo usual es usar las columnas de ambas bases de datos que tengan el mismo nombre.
all, all.x, all.y: valores lógicos que especifican la forma en que se combinarían ambas bases de datos. Por defecto, all=FALSE
, lo que significa que solo las filas que son iguales serán escogidas.
En el siguiente ejemplo, veremos varias formas en las que podemos unir o combinar dos bases de datos usando merge()
:
# Crear dos bases de datos
dat1 <- data.frame(ind = c(1:6), sexo = c(rep("macho", 3), rep("hembra", 3)))
dat1
## ind sexo
## 1 1 macho
## 2 2 macho
## 3 3 macho
## 4 4 hembra
## 5 5 hembra
## 6 6 hembra
dat2 <- data.frame(ind = c(2, 4, 6), sitio = c(rep("arrecife", 2), rep("estuario", 1)))
dat2
## ind sitio
## 1 2 arrecife
## 2 4 arrecife
## 3 6 estuario
# Opción 1: "inner join"
dat.new <- merge(dat1, dat2, by = "ind")
dat.new
## ind sexo sitio
## 1 2 macho arrecife
## 2 4 hembra arrecife
## 3 6 hembra estuario
# Opción 2: "full outer join"
dat.new2 <- merge(dat1, dat2, by = "ind", all = T)
dat.new2
## ind sexo sitio
## 1 1 macho <NA>
## 2 2 macho arrecife
## 3 3 macho <NA>
## 4 4 hembra arrecife
## 5 5 hembra <NA>
## 6 6 hembra estuario
# Opción 3: "left outer join"
dat.new3 <- merge(dat1, dat2, by = "ind", all.x = T)
dat.new3
## ind sexo sitio
## 1 1 macho <NA>
## 2 2 macho arrecife
## 3 3 macho <NA>
## 4 4 hembra arrecife
## 5 5 hembra <NA>
## 6 6 hembra estuario
# Opción 4: "right outer join"
dat.new4 <- merge(dat1, dat2, by = "ind", all.y = T)
dat.new4
## ind sexo sitio
## 1 2 macho arrecife
## 2 4 hembra arrecife
## 3 6 hembra estuario
### ¿Qué pasa si las columnas en común de las dos bases de datos tienen distintos nombres? ###
# Crear dos bases de datos
dat1a <- data.frame(individuo = c(1:6), sexo = c(rep("macho", 3), rep("hembra", 3)))
dat1a
## individuo sexo
## 1 1 macho
## 2 2 macho
## 3 3 macho
## 4 4 hembra
## 5 5 hembra
## 6 6 hembra
dat2a <- data.frame(ind = c(2, 4, 6), sitio = c(rep("arrecife", 2), rep("estuario", 1)))
dat2a
## ind sitio
## 1 2 arrecife
## 2 4 arrecife
## 3 6 estuario
# Unir ambas bases de datos
dat.merge <- merge(dat1a, dat2a, by = "ind")
## Error in fix.by(by.x, x): 'by' must specify a uniquely valid column
dat.merge <- merge(dat1a, dat2a, by.x = "individuo", by.y = "ind")
dat.merge
## individuo sexo sitio
## 1 2 macho arrecife
## 2 4 hembra arrecife
## 3 6 hembra estuario
dat.merge2 <- merge(dat2a, dat1a, by.x = "ind", by.y = "individuo")
dat.merge2
## ind sitio sexo
## 1 2 arrecife macho
## 2 4 arrecife hembra
## 3 6 estuario hembra
Extender (spreading) es lo contrario de “juntar”. Lo usa cuando una observación está dispersa en varias filas. Por ejemplo, en table2
una observación es un país en un año, pero cada observación se distribuye en dos filas:
# ver datos
table2
country | year | type | count |
---|---|---|---|
Afghanistan | 1999 | cases | 745 |
Afghanistan | 1999 | population | 19987071 |
Afghanistan | 2000 | cases | 2666 |
Afghanistan | 2000 | population | 20595360 |
Brazil | 1999 | cases | 37737 |
Brazil | 1999 | population | 172006362 |
Brazil | 2000 | cases | 80488 |
Brazil | 2000 | population | 174504898 |
China | 1999 | cases | 212258 |
China | 1999 | population | 1272915272 |
China | 2000 | cases | 213766 |
China | 2000 | population | 1280428583 |
Para ordenar esta configuración de datos, solo necesitamos dos parámetros:
La columna que contiene nombres de variables, la columna key
. Aqui estype
.
La columna que contiene valores forma múltiples variables, la columna value
. Aquí es count
.
Para hacer esto podemos usar spread()
:
# extender
spread(table2, key = "type", value = "count")
country | year | cases | population |
---|---|---|---|
Afghanistan | 1999 | 745 | 19987071 |
Afghanistan | 2000 | 2666 | 20595360 |
Brazil | 1999 | 37737 | 172006362 |
Brazil | 2000 | 80488 | 174504898 |
China | 1999 | 212258 | 1272915272 |
China | 2000 | 213766 | 1280428583 |
que se puede visualizar de la siguiente manera:
*Modificado de R para Data Science
spread()
y gather()
son funciones complementarias. collect()
hace que las mesas anchas sean más angostas y largas; spread()
hace que las cuadros de datos largos sean más cortos y anchos.
Ejercicio 3
3.1 Ordene el siguiente conjunto de datos con la altura de árboles de 2 especies:
# crear datos
tmn_plnt <- data.frame(bosque = c("maduro", "perturbado"),
especies_1 = c(154, 160),
especies_2 = c(120, 113))
Separar y unir
Hasta ahora hemos arreglado table2
y table4
, pero no table3
. table3
tiene un problema diferente: tenemos una columna (tasa) que contiene dos variables (casos y población). Esto se puede solucionar con la función separate()
. También veremos su complementounite()
, que se usa cuando una sola variable se extiende a través de múltiples columnas.
separate()
separa una columna en varias columnas, dividiéndolas donde aparezca un carácter separador. Tome table3
:
# ver datos
as.data.frame(table3)
country | year | rate |
---|---|---|
Afghanistan | 1999 | 745/19987071 |
Afghanistan | 2000 | 2666/20595360 |
Brazil | 1999 | 37737/172006362 |
Brazil | 2000 | 80488/174504898 |
China | 1999 | 212258/1272915272 |
China | 2000 | 213766/1280428583 |
Visualmente hace algo como esto:
*Modificado de R para Data Science
La columna rate contiene la información para ‘número de casos’ y ‘población’, y necesitamos dividirla en dos variables. separate()
toma el nombre de la columna para separar, y los nombres de las nuevas columnas que se crearán:
# separar
separate(data = table3, col = rate, into = c("cases", "population"))
country | year | cases | population |
---|---|---|---|
Afghanistan | 1999 | 745 | 19987071 |
Afghanistan | 2000 | 2666 | 20595360 |
Brazil | 1999 | 37737 | 172006362 |
Brazil | 2000 | 80488 | 174504898 |
China | 1999 | 212258 | 1272915272 |
China | 2000 | 213766 | 1280428583 |
Por defecto, separate()
dividirá en función de cualquier carácter no alfanumérico (es decir, un carácter que no sea un número o letra). En el código anterior, separate()
divide los valores de velocidad en los caracteres de barra diagonal. Esto se puede establecer explícitamente (para evitar cualquier error):
tb3 <- separate(data = table3, col = rate, into = c("cases", "population"), sep = "/")
tb3
country | year | cases | population |
---|---|---|---|
Afghanistan | 1999 | 745 | 19987071 |
Afghanistan | 2000 | 2666 | 20595360 |
Brazil | 1999 | 37737 | 172006362 |
Brazil | 2000 | 80488 | 174504898 |
China | 1999 | 212258 | 1272915272 |
China | 2000 | 213766 | 1280428583 |
## Classes 'tbl_df', 'tbl' and 'data.frame': 6 obs. of 4 variables:
## $ country : chr "Afghanistan" "Afghanistan" "Brazil" "Brazil" ...
## $ year : int 1999 2000 1999 2000 1999 2000
## $ cases : chr "745" "2666" "37737" "80488" ...
## $ population: chr "19987071" "20595360" "172006362" "174504898" ...
Tenga en cuenta que case y population son columnas de caracteres. Por defecto, separate()
deja el tipo de las nuevas columnas como en la original. En este caso esto no es útil, ya que realmente son números. Podemos pedirle a separate()
que intente convertir a tipos mejores usando convert = TRUE
:
tb3 <- separate(data = table3, col = rate, into = c("cases", "population"), convert = TRUE)
str(tb3)
## Classes 'tbl_df', 'tbl' and 'data.frame': 6 obs. of 4 variables:
## $ country : chr "Afghanistan" "Afghanistan" "Brazil" "Brazil" ...
## $ year : int 1999 2000 1999 2000 1999 2000
## $ cases : int 745 2666 37737 80488 212258 213766
## $ population: int 19987071 20595360 172006362 174504898 1272915272 1280428583
También puede pasar un vector de enteros a sep
, que se interpretará como posiciones para dividir. Los valores positivos comienzan en 1 en el extremo izquierdo de las cadenas; el valor negativo comienza en -1 en el extremo derecho de las cadenas. Cuando se usan números enteros para separar cadenas, la longitud de sep
debe ser uno menos que el número de nombres eninto
. Puede usar esto para separar los dos últimos dígitos de cada año:
separate(data = table3, col = year, into = c("century", "year"),
sep = 2)
country | century | year | rate |
---|---|---|---|
Afghanistan | 19 | 99 | 745/19987071 |
Afghanistan | 20 | 00 | 2666/20595360 |
Brazil | 19 | 99 | 37737/172006362 |
Brazil | 20 | 00 | 80488/174504898 |
China | 19 | 99 | 212258/1272915272 |
China | 20 | 00 | 213766/1280428583 |
La separación de columnas también se puede hacer con R
básico, aunque requiere un poco más de código:
table3$cases <- sapply(table3$rate, function(x) try(strsplit(x, "/")[[1]][1]), USE.NAMES = FALSE)
table3$population <- sapply(table3$rate, function(x) try(strsplit(x, "/")[[1]][2]), USE.NAMES = FALSE)
tb3
country | year | rate | cases | population |
---|---|---|---|---|
Afghanistan | 1999 | 745/19987071 | 745 | 19987071 |
Afghanistan | 2000 | 2666/20595360 | 2666 | 20595360 |
Brazil | 1999 | 37737/172006362 | 37737 | 172006362 |
Brazil | 2000 | 80488/174504898 | 80488 | 174504898 |
China | 1999 | 212258/1272915272 | 212258 | 1272915272 |
China | 2000 | 213766/1280428583 | 213766 | 1280428583 |
## Classes 'tbl_df', 'tbl' and 'data.frame': 6 obs. of 4 variables:
## $ country : chr "Afghanistan" "Afghanistan" "Brazil" "Brazil" ...
## $ year : int 1999 2000 1999 2000 1999 2000
## $ cases : chr "745" "2666" "37737" "80488" ...
## $ population: chr "19987071" "20595360" "172006362" "174504898" ...
unite()
es el inverso de separate()
: combina varias columnas en una sola columna:
* Modificado de R para Data Science
Sin embargo, lo necesitará con mucha menos frecuencia que separate()
.
Podemos usar unite()
para volver a unir las columnas * century * y * year * que creamos anteriormente:
# unir
unite(data = table5, col = "new", "century", "year")
country | new | rate |
---|---|---|
Afghanistan | 19_99 | 745/19987071 |
Afghanistan | 20_00 | 2666/20595360 |
Brazil | 19_99 | 37737/172006362 |
Brazil | 20_00 | 80488/174504898 |
China | 19_99 | 212258/1272915272 |
China | 20_00 | 213766/1280428583 |
En esta función también podemos usar el argumento sep
(aunque en este ejemplo no se especificó).
Ejercicio 4
4.1 Unir century y year en “table5” usando R
básico (sugerencia:paste()
)
A veces necesitamos seleccionar un subconjunto de datos usando caracteres con un patrón particular. R
básico provee de funciones parar buscar y manipular caracteres que pueden ser muy útil en el manejo de datos.
La función grep()
realiza una busqueda de un patrón de caracteres sobre un vector y regresa un índice de todos los valores en donde se encontró el patrón. Por ejemplo el siguiente código busca los meses que contienen el patrón “Ju”:
# vector con nombre de meses
month.name
## [1] "January" "February" "March" "April" "May"
## [6] "June" "July" "August" "September" "October"
## [11] "November" "December"
# busqueda de "Ju"
grep(pattern = "Ju", month.name)
## [1] 6 7
Podemos usar esos indices para extraer un el subconjunto del vector con los meses que coinciden con la búsqueda:
# busqueda de "Ju"
month.name[grep(pattern = "Ju", month.name)]
## [1] "June" "July"
Tambien podemos buscar por varios patrones al mismo tiempo separando los patrones con “|”:
# busqueda de "Ju"
month.name[grep(pattern = "Ju|Au", month.name)]
## [1] "June" "July" "August"
La función gsub()
funciona de manera similar a grep()
, sin embargo esta reemplaza todas las instancias donde el patrón fue identificado:
# remplazar macho por M
dat1$sexo <- gsub(pattern = "macho", replacement = "M", dat1$sexo)
dat1$sexo
## [1] "M" "M" "M" "hembra" "hembra" "hembra"
Ejercicio 5
5.1 ¿Para que sirve los argumentos “value” y “ignore.case” de grep()
?
5.2 Remplace “hembras” por “H” como en el ejemplo de la función gsub()
pero esta vez utilizando la función grep()
5.3 ¿Cómo difiere la función grepl()
de la función grep()
?
Caso de estudio
A continuación vamos a usar datos reales donde trataremos de unir dos bases de datos usando una columna en común. Estos datos fueron colectados usando cámaras de video con cebo o cámaras pescadoras (“BRUVS”, por sus siglas en inglés) para monitorear la diversidad de tiburones en la Gran Barrera de Australia.
Vamos a importar dos bases de datos, la primera contiene información de cada uno de los sitios en donde se pusieron las cámaras “BRUVS” (localidad, fecha, duración, etc,.). La segunda base de datos contiene información de las especies que fueron observadas en las cámaras. Ambas bases de datos tienen una columna en común (“BRUVSID”) que usaremos para realizar la unión, y análisis posteriores.
# Importar base de datos de sitios
sitios <- read.csv("bruvs.sitios.csv", header = T, sep = ",")
head(sitios)
## BRUVSID OPCODE CAMERA SITE LOCATION DEPTH LAT LON
## 1 3046 92 3 S_92 #10 Ribbon reef 38.2 -14.694 145.65
## 2 3047 92 2 S_92 #10 Ribbon reef 37.4 -14.693 145.64
## 3 3048 92 1 S_92 #10 Ribbon reef 39.2 -14.690 145.64
## 4 7054 ARP3G15 1 S_ARP3G15 _20348S 37.5 -20.874 150.94
## 5 7055 ARP3G15 2 S_ARP3G15 _20348S 34.0 -20.875 150.94
## 6 7056 ARP3G15 3 S_ARP3G15 _20348S 39.2 -20.876 150.94
## DATETIME YEAR MONTH DAY SoaktimeTotal_mins TAPEREADER
## 1 10/5/2003 2003 10 5 62.083 Peter Speare
## 2 10/5/2003 2003 10 5 62.467 Peter Speare
## 3 10/5/2003 2003 10 5 62.417 Peter Speare
## 4 1/20/2009 2009 1 20 62.533 Mike Cappo
## 5 1/20/2009 2009 1 20 62.467 Mike Cappo
## 6 1/20/2009 2009 1 20 62.450 Mike Cappo
str(sitios)
## 'data.frame': 499 obs. of 14 variables:
## $ BRUVSID : int 3046 3047 3048 7054 7055 7056 7057 7059 7060 7061 ...
## $ OPCODE : Factor w/ 43 levels "2647","815","92",..: 3 3 3 22 22 22 22 22 22 22 ...
## $ CAMERA : int 3 2 1 1 2 3 4 6 7 8 ...
## $ SITE : Factor w/ 38 levels "S_2647","S_815",..: 3 3 3 22 22 22 22 22 22 22 ...
## $ LOCATION : Factor w/ 36 levels "_20348S","_20353S",..: 33 33 33 1 1 1 1 1 1 1 ...
## $ DEPTH : num 38.2 37.4 39.2 37.5 34 39.2 29.6 43 37.7 37.7 ...
## $ LAT : num -14.7 -14.7 -14.7 -20.9 -20.9 ...
## $ LON : num 146 146 146 151 151 ...
## $ DATETIME : Factor w/ 26 levels "1/11/2009","1/16/2009",..: 13 13 13 6 6 6 6 6 6 6 ...
## $ YEAR : int 2003 2003 2003 2009 2009 2009 2009 2009 2009 2009 ...
## $ MONTH : int 10 10 10 1 1 1 1 1 1 1 ...
## $ DAY : int 5 5 5 20 20 20 20 20 20 20 ...
## $ SoaktimeTotal_mins: num 62.1 62.5 62.4 62.5 62.5 ...
## $ TAPEREADER : Factor w/ 4 levels "Charlotte Johansson",..: 4 4 4 3 3 3 3 3 3 3 ...
dim(sitios)
## [1] 499 14
length(unique(sitios$BRUVSID))
## [1] 499
# Importar base de datos de especies
especies <- read.csv("bruvs.spp.csv", header = T, sep = ",")
head(especies)
## BRUVSID FISHID GROUP FAMILY GENUS SPECIES
## 1 3649 7770 Rays Rhinobatidae Aptychotrema rostrata
## 2 7470 18516 Rays Rhinobatidae Aptychotrema rostrata
## 3 2097 3233 Sharks Carcharhinidae Carcharhinus albimarginatus
## 4 2117 3377 Sharks Carcharhinidae Carcharhinus albimarginatus
## 5 2123 736 Sharks Carcharhinidae Carcharhinus albimarginatus
## 6 2132 8231 Sharks Carcharhinidae Carcharhinus albimarginatus
## COMMON SPP STAGE
## 1 Eastern shovelnose guitarfish Aptychotrema rostrata AD
## 2 Eastern shovelnose guitarfish Aptychotrema rostrata AD
## 3 Silvertip shark Carcharhinus albimarginatus AD
## 4 Silvertip shark Carcharhinus albimarginatus AD
## 5 Silvertip shark Carcharhinus albimarginatus AD
## 6 Silvertip shark Carcharhinus albimarginatus AD
## ENVIRON Depthrange TAPEREADER TimeMaxNmins MaxN
## 1 Marine-brackish-demersal 1 to 60m Mike Cappo 10.633 1
## 2 Marine-brackish-demersal 1 to 60m Mike Cappo 19.067 1
## 3 Reef-associated 1 to 800m Peter Speare 37.450 1
## 4 Reef-associated 1 to 800m Peter Speare 40.283 1
## 5 Reef-associated 1 to 800m Helen Sturmey 33.350 1
## 6 Reef-associated 1 to 800m Mike Cappo 43.683 1
str(especies)
## 'data.frame': 971 obs. of 14 variables:
## $ BRUVSID : int 3649 7470 2097 2117 2123 2132 2135 2165 2668 2669 ...
## $ FISHID : int 7770 18516 3233 3377 736 8231 8997 3209 7587 7571 ...
## $ GROUP : Factor w/ 2 levels "Rays","Sharks": 1 1 2 2 2 2 2 2 2 2 ...
## $ FAMILY : Factor w/ 9 levels "Carcharhinidae",..: 7 7 1 1 1 1 1 1 1 1 ...
## $ GENUS : Factor w/ 23 levels "Aptychotrema",..: 1 1 2 2 2 2 2 2 2 2 ...
## $ SPECIES : Factor w/ 35 levels "acutidens","albimarginatus",..: 27 27 2 2 2 2 2 2 2 2 ...
## $ COMMON : Factor w/ 38 levels "Australian blacktip shark",..: 10 10 27 27 27 27 27 27 27 27 ...
## $ SPP : Factor w/ 38 levels "Aptychotrema rostrata",..: 1 1 2 2 2 2 2 2 2 2 ...
## $ STAGE : Factor w/ 3 levels "","AD","JUV": 2 2 2 2 2 2 3 2 2 2 ...
## $ ENVIRON : Factor w/ 13 levels "Marine-brackish-benthopelagic",..: 2 2 13 13 13 13 13 13 13 13 ...
## $ Depthrange : Factor w/ 29 levels "1 to 1000m","1 to 100m",..: 17 17 19 19 19 19 19 19 19 19 ...
## $ TAPEREADER : Factor w/ 5 levels "Charlotte Johansson",..: 4 4 5 5 2 4 4 5 4 4 ...
## $ TimeMaxNmins: num 10.6 19.1 37.5 40.3 33.4 ...
## $ MaxN : int 1 1 1 1 1 1 1 1 1 1 ...
dim(especies)
## [1] 971 14
length(unique(especies$BRUVSID))
## [1] 785
# Unir ambas bases de datos por columna en común ("BRUVSID")
db.final <- merge(sitios, especies, by = "BRUVSID", all.x=T)
head(db.final)
## BRUVSID OPCODE CAMERA SITE LOCATION DEPTH LAT LON DATETIME
## 1 2400 2647 5 S_2647 Acheron I 21.8 -18.915 146.62 4/26/2004
## 2 2401 2647 3 S_2647 Acheron I 21.9 -18.914 146.62 4/26/2004
## 3 2402 2647 2 S_2647 Acheron I 21.9 -18.913 146.61 4/26/2004
## 4 2809 815 4 S_815 Arc Reef 48.3 -18.491 147.40 9/19/2003
## 5 2810 815 3 S_815 Arc Reef 29.5 -18.489 147.40 9/19/2003
## 6 2811 815 2 S_815 Arc Reef 42.9 -18.486 147.39 9/19/2003
## YEAR MONTH DAY SoaktimeTotal_mins TAPEREADER.x FISHID GROUP FAMILY GENUS
## 1 2004 4 26 62.550 Mike Cappo NA <NA> <NA> <NA>
## 2 2004 4 26 62.500 Mike Cappo NA <NA> <NA> <NA>
## 3 2004 4 26 57.567 Mike Cappo NA <NA> <NA> <NA>
## 4 2003 9 19 62.467 Peter Speare NA <NA> <NA> <NA>
## 5 2003 9 19 62.467 Peter Speare NA <NA> <NA> <NA>
## 6 2003 9 19 62.533 Peter Speare NA <NA> <NA> <NA>
## SPECIES COMMON SPP STAGE ENVIRON Depthrange TAPEREADER.y TimeMaxNmins
## 1 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## 2 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## 3 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## 4 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## 5 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## 6 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## MaxN
## 1 NA
## 2 NA
## 3 NA
## 4 NA
## 5 NA
## 6 NA
dim(db.final)
## [1] 557 27
# Exportar base de datos final
name <- paste(Sys.Date(), "_", "bd.final.exportada.csv", sep = "")
write.csv(db.final, name, row.names = F)
Luego de unir ambas bases de datos vamos a “limpiar” un poco los datos y manipularlos para determinar cuales especies fueron más abundantes.
# Visualizar base de datos
head(db.final)
## BRUVSID OPCODE CAMERA SITE LOCATION DEPTH LAT LON DATETIME
## 1 2400 2647 5 S_2647 Acheron I 21.8 -18.915 146.62 4/26/2004
## 2 2401 2647 3 S_2647 Acheron I 21.9 -18.914 146.62 4/26/2004
## 3 2402 2647 2 S_2647 Acheron I 21.9 -18.913 146.61 4/26/2004
## 4 2809 815 4 S_815 Arc Reef 48.3 -18.491 147.40 9/19/2003
## 5 2810 815 3 S_815 Arc Reef 29.5 -18.489 147.40 9/19/2003
## 6 2811 815 2 S_815 Arc Reef 42.9 -18.486 147.39 9/19/2003
## YEAR MONTH DAY SoaktimeTotal_mins TAPEREADER.x FISHID GROUP FAMILY GENUS
## 1 2004 4 26 62.550 Mike Cappo NA <NA> <NA> <NA>
## 2 2004 4 26 62.500 Mike Cappo NA <NA> <NA> <NA>
## 3 2004 4 26 57.567 Mike Cappo NA <NA> <NA> <NA>
## 4 2003 9 19 62.467 Peter Speare NA <NA> <NA> <NA>
## 5 2003 9 19 62.467 Peter Speare NA <NA> <NA> <NA>
## 6 2003 9 19 62.533 Peter Speare NA <NA> <NA> <NA>
## SPECIES COMMON SPP STAGE ENVIRON Depthrange TAPEREADER.y TimeMaxNmins
## 1 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## 2 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## 3 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## 4 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## 5 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## 6 <NA> <NA> <NA> <NA> <NA> <NA> <NA> NA
## MaxN
## 1 NA
## 2 NA
## 3 NA
## 4 NA
## 5 NA
## 6 NA
names(db.final)
## [1] "BRUVSID" "OPCODE" "CAMERA"
## [4] "SITE" "LOCATION" "DEPTH"
## [7] "LAT" "LON" "DATETIME"
## [10] "YEAR" "MONTH" "DAY"
## [13] "SoaktimeTotal_mins" "TAPEREADER.x" "FISHID"
## [16] "GROUP" "FAMILY" "GENUS"
## [19] "SPECIES" "COMMON" "SPP"
## [22] "STAGE" "ENVIRON" "Depthrange"
## [25] "TAPEREADER.y" "TimeMaxNmins" "MaxN"
# Crear un subset de la base de datos con variables de interés
#db <- db.final[, c("BRUVSID", "SITE", "LOCATION", "DEPTH", "LAT", "LON", "DATETIME",
# "YEAR", "MONTH", "DAY", "SoaktimeTotal_mins")]
db <- db.final[, c(1, 4:13, 18:19, 21, 27)]
head(db)
## BRUVSID SITE LOCATION DEPTH LAT LON DATETIME YEAR MONTH DAY
## 1 2400 S_2647 Acheron I 21.8 -18.915 146.62 4/26/2004 2004 4 26
## 2 2401 S_2647 Acheron I 21.9 -18.914 146.62 4/26/2004 2004 4 26
## 3 2402 S_2647 Acheron I 21.9 -18.913 146.61 4/26/2004 2004 4 26
## 4 2809 S_815 Arc Reef 48.3 -18.491 147.40 9/19/2003 2003 9 19
## 5 2810 S_815 Arc Reef 29.5 -18.489 147.40 9/19/2003 2003 9 19
## 6 2811 S_815 Arc Reef 42.9 -18.486 147.39 9/19/2003 2003 9 19
## SoaktimeTotal_mins GENUS SPECIES SPP MaxN
## 1 62.550 <NA> <NA> <NA> NA
## 2 62.500 <NA> <NA> <NA> NA
## 3 57.567 <NA> <NA> <NA> NA
## 4 62.467 <NA> <NA> <NA> NA
## 5 62.467 <NA> <NA> <NA> NA
## 6 62.533 <NA> <NA> <NA> NA
names(db)
## [1] "BRUVSID" "SITE" "LOCATION"
## [4] "DEPTH" "LAT" "LON"
## [7] "DATETIME" "YEAR" "MONTH"
## [10] "DAY" "SoaktimeTotal_mins" "GENUS"
## [13] "SPECIES" "SPP" "MaxN"
str(db)
## 'data.frame': 557 obs. of 15 variables:
## $ BRUVSID : int 2400 2401 2402 2809 2810 2811 2812 3046 3047 3047 ...
## $ SITE : Factor w/ 38 levels "S_2647","S_815",..: 1 1 1 2 2 2 2 3 3 3 ...
## $ LOCATION : Factor w/ 36 levels "_20348S","_20353S",..: 34 34 34 35 35 35 35 33 33 33 ...
## $ DEPTH : num 21.8 21.9 21.9 48.3 29.5 42.9 47.3 38.2 37.4 37.4 ...
## $ LAT : num -18.9 -18.9 -18.9 -18.5 -18.5 ...
## $ LON : num 147 147 147 147 147 ...
## $ DATETIME : Factor w/ 26 levels "1/11/2009","1/16/2009",..: 23 23 23 26 26 26 26 13 13 13 ...
## $ YEAR : int 2004 2004 2004 2003 2003 2003 2003 2003 2003 2003 ...
## $ MONTH : int 4 4 4 9 9 9 9 10 10 10 ...
## $ DAY : int 26 26 26 19 19 19 19 5 5 5 ...
## $ SoaktimeTotal_mins: num 62.5 62.5 57.6 62.5 62.5 ...
## $ GENUS : Factor w/ 23 levels "Aptychotrema",..: NA NA NA NA NA NA NA NA 2 2 ...
## $ SPECIES : Factor w/ 35 levels "acutidens","albimarginatus",..: NA NA NA NA NA NA NA NA 5 4 ...
## $ SPP : Factor w/ 38 levels "Aptychotrema rostrata",..: NA NA NA NA NA NA NA NA 5 4 ...
## $ MaxN : int NA NA NA NA NA NA NA NA 1 1 ...
# Crear base de datos de sitios
db.sitios <- db[, c(1:11)]
head(db.sitios)
## BRUVSID SITE LOCATION DEPTH LAT LON DATETIME YEAR MONTH DAY
## 1 2400 S_2647 Acheron I 21.8 -18.915 146.62 4/26/2004 2004 4 26
## 2 2401 S_2647 Acheron I 21.9 -18.914 146.62 4/26/2004 2004 4 26
## 3 2402 S_2647 Acheron I 21.9 -18.913 146.61 4/26/2004 2004 4 26
## 4 2809 S_815 Arc Reef 48.3 -18.491 147.40 9/19/2003 2003 9 19
## 5 2810 S_815 Arc Reef 29.5 -18.489 147.40 9/19/2003 2003 9 19
## 6 2811 S_815 Arc Reef 42.9 -18.486 147.39 9/19/2003 2003 9 19
## SoaktimeTotal_mins
## 1 62.550
## 2 62.500
## 3 57.567
## 4 62.467
## 5 62.467
## 6 62.533
names(db.sitios)
## [1] "BRUVSID" "SITE" "LOCATION"
## [4] "DEPTH" "LAT" "LON"
## [7] "DATETIME" "YEAR" "MONTH"
## [10] "DAY" "SoaktimeTotal_mins"
### Formato de columnas con información de especies ###
# Crear código de 3 letras para especies
db$GENUS <- as.character(db$GENUS)
db$SPECIES <- as.character(db$SPECIES)
spp.code1 <- abbreviate(db$GENUS, 1, strict = T)
spp.code2 <- abbreviate(db$SPECIES, 4, strict = T, method = "left.kept")
db$spp.code <- paste(spp.code1, spp.code2, sep = "")
db[db == "NANA" ] = NA
# Analizar datos de especies
unique(db$spp.code)
## [1] NA "Cambn" "Cambl" "Tmeyn" "Tobss" "Calbm" "Dkuhl" "Rdjdd"
## [9] "Cplmb" "Gcuvr" "Psphn" "Nfrrg" "Hastr" "Smkrr" "Hfai" "Lmcrr"
## [17] "Clecs" "Helng" "Mbrst" "Rtylr" "Cbrvp" "Rancy" "Arstr"
unique(db$SPP)
## [1] <NA> Carcharhinus amboinensis
## [3] Carcharhinus amblyrhynchos Taeniura meyeni
## [5] Triaenodon obesus Carcharhinus albimarginatus
## [7] Neotrygon kuhlii Rhynchobatus djiddensis
## [9] Carcharhinus plumbeus Galeocerdo cuvier
## [11] Pastinachus sephen Nebrius ferrugineus
## [13] Hemigaleus australiensis Sphyrna mokarran
## [15] Himantura fai Loxodon macrorhinus
## [17] Carcharhinus leucas Hemipristis elongata
## [19] Manta birostris Rhizoprionodon taylori
## [21] Carcharhinus brevipinna Rhina ancylostoma
## [23] Aptychotrema rostrata
## 38 Levels: Aptychotrema rostrata ... Triaenodon obesus
length(unique(db$SPP))
## [1] 23
# Cambiar el nombre de base de datos
dat.maxn <- db
# Ordenar base de datos por códigos de especies
dat.maxn <- dat.maxn[order(dat.maxn$spp.code), ]
head(dat.maxn)
## BRUVSID SITE LOCATION DEPTH LAT LON DATETIME
## 539 7470 S_ARP4BB-1 Barcoo Bank 25.5 -22.831 151.67 11/5/2009
## 33 6111 S_RAPBBgB Barcoo Bank 23.2 -22.831 151.68 8/6/2007
## 34 6112 S_RAPBBgB Barcoo Bank 39.6 -22.831 151.69 8/6/2007
## 135 6910 S_ARP3B19 _21245S 34.0 -21.296 152.44 1/22/2009
## 148 6922 S_ARP3B20 _SMALL LAGOON REEF 38.2 -21.863 152.53 1/24/2009
## 149 6923 S_ARP3B20 _SMALL LAGOON REEF 38.4 -21.862 152.53 1/24/2009
## YEAR MONTH DAY SoaktimeTotal_mins GENUS SPECIES
## 539 2009 11 5 62.000 Aptychotrema rostrata
## 33 2007 8 6 62.450 Carcharhinus albimarginatus
## 34 2007 8 6 62.433 Carcharhinus albimarginatus
## 135 2009 1 22 62.467 Carcharhinus albimarginatus
## 148 2009 1 24 62.433 Carcharhinus albimarginatus
## 149 2009 1 24 62.400 Carcharhinus albimarginatus
## SPP MaxN spp.code
## 539 Aptychotrema rostrata 1 Arstr
## 33 Carcharhinus albimarginatus 1 Calbm
## 34 Carcharhinus albimarginatus 1 Calbm
## 135 Carcharhinus albimarginatus 1 Calbm
## 148 Carcharhinus albimarginatus 1 Calbm
## 149 Carcharhinus albimarginatus 1 Calbm
# Calcular abundancias
dat.maxn2 <- reshape2:::dcast(dat.maxn, BRUVSID ~ spp.code, value.var = "MaxN")
## Aggregation function missing: defaulting to length
head(dat.maxn2)
## BRUVSID Arstr Calbm Cambl Cambn Cbrvp Clecs Cplmb Dkuhl Gcuvr Hastr
## 1 2400 0 0 0 0 0 0 0 0 0 0
## 2 2401 0 0 0 0 0 0 0 0 0 0
## 3 2402 0 0 0 0 0 0 0 0 0 0
## 4 2809 0 0 0 0 0 0 0 0 0 0
## 5 2810 0 0 0 0 0 0 0 0 0 0
## 6 2811 0 0 0 0 0 0 0 0 0 0
## Helng Hfai Lmcrr Mbrst Nfrrg Psphn Rancy Rdjdd Rtylr Smkrr Tmeyn Tobss
## 1 0 0 0 0 0 0 0 0 0 0 0 0
## 2 0 0 0 0 0 0 0 0 0 0 0 0
## 3 0 0 0 0 0 0 0 0 0 0 0 0
## 4 0 0 0 0 0 0 0 0 0 0 0 0
## 5 0 0 0 0 0 0 0 0 0 0 0 0
## 6 0 0 0 0 0 0 0 0 0 0 0 0
## NA
## 1 1
## 2 1
## 3 1
## 4 1
## 5 1
## 6 1
dim(dat.maxn2)
## [1] 499 24
str(dat.maxn2)
## 'data.frame': 499 obs. of 24 variables:
## $ BRUVSID: int 2400 2401 2402 2809 2810 2811 2812 3046 3047 3048 ...
## $ Arstr : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Calbm : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Cambl : int 0 0 0 0 0 0 0 0 1 0 ...
## $ Cambn : int 0 0 0 0 0 0 0 0 1 0 ...
## $ Cbrvp : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Clecs : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Cplmb : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Dkuhl : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Gcuvr : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Hastr : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Helng : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Hfai : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Lmcrr : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Mbrst : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Nfrrg : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Psphn : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Rancy : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Rdjdd : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Rtylr : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Smkrr : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Tmeyn : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Tobss : int 0 0 0 0 0 0 0 0 0 0 ...
## $ NA : int 1 1 1 1 1 1 1 1 0 1 ...
dat.maxn <- dat.maxn2
# Unir bases de abundancias y sitios
d.bruvs <- merge(db.sitios, dat.maxn, by="BRUVSID", all.x=T)
head(d.bruvs)
## BRUVSID SITE LOCATION DEPTH LAT LON DATETIME YEAR MONTH DAY
## 1 2400 S_2647 Acheron I 21.8 -18.915 146.62 4/26/2004 2004 4 26
## 2 2401 S_2647 Acheron I 21.9 -18.914 146.62 4/26/2004 2004 4 26
## 3 2402 S_2647 Acheron I 21.9 -18.913 146.61 4/26/2004 2004 4 26
## 4 2809 S_815 Arc Reef 48.3 -18.491 147.40 9/19/2003 2003 9 19
## 5 2810 S_815 Arc Reef 29.5 -18.489 147.40 9/19/2003 2003 9 19
## 6 2811 S_815 Arc Reef 42.9 -18.486 147.39 9/19/2003 2003 9 19
## SoaktimeTotal_mins Arstr Calbm Cambl Cambn Cbrvp Clecs Cplmb Dkuhl Gcuvr
## 1 62.550 0 0 0 0 0 0 0 0 0
## 2 62.500 0 0 0 0 0 0 0 0 0
## 3 57.567 0 0 0 0 0 0 0 0 0
## 4 62.467 0 0 0 0 0 0 0 0 0
## 5 62.467 0 0 0 0 0 0 0 0 0
## 6 62.533 0 0 0 0 0 0 0 0 0
## Hastr Helng Hfai Lmcrr Mbrst Nfrrg Psphn Rancy Rdjdd Rtylr Smkrr Tmeyn
## 1 0 0 0 0 0 0 0 0 0 0 0 0
## 2 0 0 0 0 0 0 0 0 0 0 0 0
## 3 0 0 0 0 0 0 0 0 0 0 0 0
## 4 0 0 0 0 0 0 0 0 0 0 0 0
## 5 0 0 0 0 0 0 0 0 0 0 0 0
## 6 0 0 0 0 0 0 0 0 0 0 0 0
## Tobss NA
## 1 0 1
## 2 0 1
## 3 0 1
## 4 0 1
## 5 0 1
## 6 0 1
names(d.bruvs)
## [1] "BRUVSID" "SITE" "LOCATION"
## [4] "DEPTH" "LAT" "LON"
## [7] "DATETIME" "YEAR" "MONTH"
## [10] "DAY" "SoaktimeTotal_mins" "Arstr"
## [13] "Calbm" "Cambl" "Cambn"
## [16] "Cbrvp" "Clecs" "Cplmb"
## [19] "Dkuhl" "Gcuvr" "Hastr"
## [22] "Helng" "Hfai" "Lmcrr"
## [25] "Mbrst" "Nfrrg" "Psphn"
## [28] "Rancy" "Rdjdd" "Rtylr"
## [31] "Smkrr" "Tmeyn" "Tobss"
## [34] "NA"
# Columnas que contienen spp
n1 <- 12 # first species column
n2 <- 33 # last species column
colSums(d.bruvs[,c(n1:n2)])
## Arstr Calbm Cambl Cambn Cbrvp Clecs Cplmb Dkuhl Gcuvr Hastr Helng Hfai
## 1 26 159 2 2 1 2 23 29 2 3 2
## Lmcrr Mbrst Nfrrg Psphn Rancy Rdjdd Rtylr Smkrr Tmeyn Tobss
## 2 9 14 2 2 30 2 8 26 58
# Ordenar columnas según abundancia
ord.db <- rev(order(apply(d.bruvs[n1:n2], 2, sum)))
db1 <- d.bruvs[n1:n2]
names(db1)
## [1] "Arstr" "Calbm" "Cambl" "Cambn" "Cbrvp" "Clecs" "Cplmb" "Dkuhl"
## [9] "Gcuvr" "Hastr" "Helng" "Hfai" "Lmcrr" "Mbrst" "Nfrrg" "Psphn"
## [17] "Rancy" "Rdjdd" "Rtylr" "Smkrr" "Tmeyn" "Tobss"
# Ordenar presencia/ausencia por ocurrencia
db2 <- db1[, ord.db]
names(db2)
## [1] "Cambl" "Tobss" "Rdjdd" "Gcuvr" "Tmeyn" "Calbm" "Dkuhl" "Nfrrg"
## [9] "Mbrst" "Smkrr" "Helng" "Rtylr" "Rancy" "Psphn" "Lmcrr" "Hfai"
## [17] "Hastr" "Cplmb" "Cbrvp" "Cambn" "Clecs" "Arstr"
maxn.spp <- cbind(d.bruvs[,c(1:(n1-1))], db2)
head(maxn.spp)
## BRUVSID SITE LOCATION DEPTH LAT LON DATETIME YEAR MONTH DAY
## 1 2400 S_2647 Acheron I 21.8 -18.915 146.62 4/26/2004 2004 4 26
## 2 2401 S_2647 Acheron I 21.9 -18.914 146.62 4/26/2004 2004 4 26
## 3 2402 S_2647 Acheron I 21.9 -18.913 146.61 4/26/2004 2004 4 26
## 4 2809 S_815 Arc Reef 48.3 -18.491 147.40 9/19/2003 2003 9 19
## 5 2810 S_815 Arc Reef 29.5 -18.489 147.40 9/19/2003 2003 9 19
## 6 2811 S_815 Arc Reef 42.9 -18.486 147.39 9/19/2003 2003 9 19
## SoaktimeTotal_mins Cambl Tobss Rdjdd Gcuvr Tmeyn Calbm Dkuhl Nfrrg Mbrst
## 1 62.550 0 0 0 0 0 0 0 0 0
## 2 62.500 0 0 0 0 0 0 0 0 0
## 3 57.567 0 0 0 0 0 0 0 0 0
## 4 62.467 0 0 0 0 0 0 0 0 0
## 5 62.467 0 0 0 0 0 0 0 0 0
## 6 62.533 0 0 0 0 0 0 0 0 0
## Smkrr Helng Rtylr Rancy Psphn Lmcrr Hfai Hastr Cplmb Cbrvp Cambn Clecs
## 1 0 0 0 0 0 0 0 0 0 0 0 0
## 2 0 0 0 0 0 0 0 0 0 0 0 0
## 3 0 0 0 0 0 0 0 0 0 0 0 0
## 4 0 0 0 0 0 0 0 0 0 0 0 0
## 5 0 0 0 0 0 0 0 0 0 0 0 0
## 6 0 0 0 0 0 0 0 0 0 0 0 0
## Arstr
## 1 0
## 2 0
## 3 0
## 4 0
## 5 0
## 6 0
# Crear un gráfico resumen de abundancias
sum.maxn.spp <- colSums(maxn.spp[,c(n1:n2)])
# Parámetros del gráfico
par(mar = c(4, 6, 1, 2))
# Visualizar gráfico de barras
barplot(as.matrix(t(sum.maxn.spp)), horiz = T, ann = F, col = "indianred1",
xlim = c(0, max(sum.maxn.spp + 10)),
las = 1, axes = F, font = 1, xlab = "", ylab = "")
# Poner eje X
axis(1)
# Títulos de ejes
mtext("MaxN", 1, line = 2.5, cex = 1.5)
mtext("Especies", 2, line = 3.85, cex = 1.5)
box(bty = "l")
Clements, J. F., T. S. Schulenberg, M. J. Iliff, D. Roberson, T. A. Fredericks, B. L. Sullivan, and C. L. Wood. 2017. The eBird/Clements checklist of birds of the world: v2016.
Jones, Jon Bielby, Marcel Cardillo, Susanne A. Fritz, Justin O’Dell, C. David L. Orme, Kamran Safi, Wes Sechrest, Elizabeth H. Boakes, Chris Carbone, Christina Connolly, Michael J. Cutts, Janine K. Foster, Richard Grenyer, Michael Habib, Christopher A. Plaster, Samantha A. Price, Elizabeth A. Rigby, Janna Rist, Amber Teacher, Olaf R. P. Bininda-Emonds, John L. Gittleman, Georgina M. Mace, and Andy Purvis. 2009. PanTHERIA: a species-level database of life history, ecology, and geography of extant and recently extinct mammals. Ecology 90:2648.
Wickham, Hadley, and Garrett Grolemund. 2016. R for data science: import, tidy, transform, visualize, and model data. sitio web
Informacíon de la sesión
## R version 3.6.1 (2019-07-05)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 19.04
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.8.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.8.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=es_CR.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=es_CR.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=es_CR.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=es_CR.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] rmdformats_0.3.5 dplyr_0.8.0.1 tidyr_0.8.3
## [4] readxl_1.3.1 kableExtra_1.1.0 knitr_1.23
## [7] ggplot2_3.1.1 RColorBrewer_1.1-2
##
## loaded via a namespace (and not attached):
## [1] tidyselect_0.2.5 xfun_0.7 reshape2_1.4.3
## [4] purrr_0.3.2 colorspace_1.4-1 miniUI_0.1.1.1
## [7] htmltools_0.3.6 viridisLite_0.3.0 yaml_2.2.0
## [10] rlang_0.3.4 pillar_1.4.0 later_0.8.0
## [13] glue_1.3.1 withr_2.1.2 plyr_1.8.4
## [16] questionr_0.7.0 stringr_1.4.0 munsell_0.5.0
## [19] gtable_0.3.0 cellranger_1.1.0 rvest_0.3.3
## [22] evaluate_0.14 httpuv_1.5.1 highr_0.8
## [25] Rcpp_1.0.1 xtable_1.8-4 readr_1.3.1
## [28] scales_1.0.0 promises_1.0.1 webshot_0.5.1
## [31] mime_0.6 hms_0.4.2 digest_0.6.19
## [34] stringi_1.4.3 bookdown_0.11 shiny_1.3.2
## [37] grid_3.6.1 tools_3.6.1 magrittr_1.5
## [40] lazyeval_0.2.2 tibble_2.1.1 crayon_1.3.4
## [43] pkgconfig_2.0.2 xml2_1.2.0 assertthat_0.2.1
## [46] rmarkdown_1.13 httr_1.4.0 rstudioapi_0.10
## [49] R6_2.4.0 compiler_3.6.1