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
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/Curso R Intensivo/Marcelo"
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("https://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 |
---|---|---|---|---|
1 | species | ostric2 | Common Ostrich | Struthio camelus |
6 | species | ostric3 | Somali Ostrich | Struthio molybdophanes |
7 | slash | y00934 | Common/Somali Ostrich | Struthio camelus/molybdophanes |
8 | species | grerhe1 | Greater Rhea | Rhea americana |
14 | species | lesrhe2 | Lesser Rhea | Rhea pennata |
15 | 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 |
---|---|---|---|---|
1 | species | ostric2 | Common Ostrich | Struthio camelus |
6 | species | ostric3 | Somali Ostrich | Struthio molybdophanes |
7 | slash | y00934 | Common/Somali Ostrich | Struthio camelus/molybdophanes |
8 | species | grerhe1 | Greater Rhea | Rhea americana |
14 | species | lesrhe2 | Lesser Rhea | Rhea pennata |
15 | 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 |
## tibble[,4] [6 × 4] (S3: tbl_df/tbl/data.frame)
## $ country : chr [1:6] "Afghanistan" "Afghanistan" "Brazil" "Brazil" ...
## $ year : int [1:6] 1999 2000 1999 2000 1999 2000
## $ cases : chr [1:6] "745" "2666" "37737" "80488" ...
## $ population: chr [1:6] "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)
## tibble[,4] [6 × 4] (S3: tbl_df/tbl/data.frame)
## $ country : chr [1:6] "Afghanistan" "Afghanistan" "Brazil" "Brazil" ...
## $ year : int [1:6] 1999 2000 1999 2000 1999 2000
## $ cases : int [1:6] 745 2666 37737 80488 212258 213766
## $ population: int [1:6] 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 |
## tibble[,4] [6 × 4] (S3: tbl_df/tbl/data.frame)
## $ country : chr [1:6] "Afghanistan" "Afghanistan" "Brazil" "Brazil" ...
## $ year : int [1:6] 1999 2000 1999 2000 1999 2000
## $ cases : chr [1:6] "745" "2666" "37737" "80488" ...
## $ population: chr [1:6] "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" "June"
## [7] "July" "August" "September" "October" "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()
?
Los compendios de investigación estándar proporcionan un medio fácilmente reconocible para organizar materiales digitales, lo que permite a otros investigadores inspeccionar, reproducir y desarrollar esa investigación. El paquete sketchy
facilita el uso de compendios de investigación para el análisis de datos en el entorno R. A diferencia de otros paquetes de R para crear compendios de investigación (por ejemplo, vertical
, rrtools
), sketchy
no está vinculado a una estructura de carpetas en particular. Actualmente, el paquete proporciona 13 estructuras alternativas (ver compendios de objetos) y permite a los usuarios modificar o ingresar sus propias estructuras.
sketchy
lo podemos instalar y cargar así:
install.packages("devtools")
devtools::install_github("maRce10/sketchy")
library("sketchy")
Para crear un compendio de investigación con sketchy
usamos a función ‘make_compendium()’:
path <- "AQUI LA DIRECCION DE LA CARPETA DONDE SE CREARA EL COMPENDIO"
make_compendium(name = "proyecto_x", path = path, format = compendiums$basic$skeleton)
## Creating directories ...
## proyecto_x
## │
## ├── data/
## │ ├── processed/
## │ └── raw/
## ├── manuscript/
## ├── output/
## └── scripts/
## Done.
Podemos utilizar estructuras de carpetas de otras fuentes. Por ejemplo, en este ejemplo usamos la estructura sugerida por Wilson et al. (2017) (usando el argumento ‘format’):
make_compendium(name = "proyecto_y", path = path, format = compendiums$wilson$skeleton)
## Creating directories ...
## proyecto_y
## │
## ├── data/
## ├── doc/
## ├── requirements/
## ├── results/
## └── src/
## Done.
Las diferentes estructuras de compendios estan guardadas en el objeto ‘compendiums’.
Ejercicio 6
Cree un compendio de investigación con el formato ‘boettiger’
Araya-Salas, M., Willink, B., Arriaga, A. (2020), sketchy: research compendiums for data analysis in R. R package version 1.0.0.
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
Wilson G, Bryan J, Cranston K, Kitzes J, Nederbragt L. & Teal, T. K.. 2017. Good enough practices in scientific computing. PLOS Computational Biology 13(6): e1005510.
Informacíon de la sesión
## R version 4.0.5 (2021-03-31)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.2 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/atlas/libblas.so.3.10.3
## LAPACK: /usr/lib/x86_64-linux-gnu/atlas/liblapack.so.3.10.3
##
## locale:
## [1] LC_CTYPE=pt_BR.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=es_CR.UTF-8 LC_COLLATE=pt_BR.UTF-8
## [5] LC_MONETARY=es_CR.UTF-8 LC_MESSAGES=pt_BR.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] sketchy_1.0.2 rmdformats_1.0.2 dplyr_1.0.5 tidyr_1.1.3
## [5] readxl_1.3.1 kableExtra_1.3.4 knitr_1.33 ggplot2_3.3.3
## [9] RColorBrewer_1.1-2
##
## loaded via a namespace (and not attached):
## [1] Rcpp_1.0.6 cellranger_1.1.0 bslib_0.2.4 compiler_4.0.5
## [5] pillar_1.6.0 jquerylib_0.1.4 tools_4.0.5 packrat_0.6.0
## [9] digest_0.6.27 viridisLite_0.4.0 jsonlite_1.7.2 evaluate_0.14
## [13] lifecycle_1.0.0 tibble_3.1.1 gtable_0.3.0 pkgconfig_2.0.3
## [17] rlang_0.4.11 cli_2.5.0 rstudioapi_0.13 yaml_2.2.1
## [21] xfun_0.22 xml2_1.3.2 httr_1.4.2 withr_2.4.2
## [25] stringr_1.4.0 systemfonts_1.0.1 generics_0.1.0 sass_0.3.1
## [29] vctrs_0.3.8 webshot_0.5.2 grid_4.0.5 tidyselect_1.1.1
## [33] svglite_2.0.0 glue_1.4.2 R6_2.5.0 fansi_0.4.2
## [37] bookdown_0.22 rmarkdown_2.7 purrr_0.3.4 magrittr_2.0.1
## [41] scales_1.1.1 htmltools_0.5.1.1 ellipsis_0.3.2 rvest_1.0.0
## [45] colorspace_2.0-0 utf8_1.2.1 stringi_1.5.3 munsell_0.5.0
## [49] crayon_1.4.1