Manipulación de data frames

Los data frames son objetos recursivos que pueden reunir en su contenido los diferentes tipos de objetos básicos (numérico, vector, etc). Su estructura bidimensional, ordenada por columnas (variables), filas (observaciones) y celdas (valores), facilita el almacenamiento de datos con los que se trabaja frecuentemente en cualquier área, puesto que se podría entender como una tabla o una matriz. Si bien, el término anglicano data frame, es empleado en campos donde la vía de manipulación de sus datos es la informática y tiene una finalidad estadística, como la bioinformática. De hecho, en el apartado Graficación se requiere este tipo de objeto o aquellos que sean coercionables a data frame para la graficación avanzada con ggplot2.

En primer lugar, sería recomendable recordar los conocimientos básicos que tenemos de los data frames, los cuales se encuentran en Estructuras de datos. Para ello se muestra un simple ejemplo a continuación:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
a <- c(1,2,2,1,2,1,1,2)
b <- c(5,6,3,1,4,2,7,8)
df <- data.frame(a,b)                                   #Creación a partir de vectores
c <- c("A","C","B","F","E","G","H","D")     
df <- cbind(df, c)                                      #Nueva columna
colnames(df) <- c("Clase", "Notas_medias", "Profesor")  #Nombres de columnas
a1 <- df[1,1]                                           #Subconjuntos 
B <- df[,2]
c5 <- df[5, "Profesor"]
C5 <- df$Profesor[5]
df$Notas_medias[4] <- sqrt(df$Notas_medias[5])          #Operaciones 
df$Profesor <- NULL                                     #Elimina columna

Funciones interesantes de R base

Función attach()

Esta función agiliza la manipulación del data frame, ya que permite referenciar las columnas sin tener que especificar el nombre del data frame y la columna, esta última precedida de $. La función detach() desactiva a attach().

Ejemplo

1
2
3
attach(df)
mean(Notas_medias)
detach(df)

Función order()

Esta función permite ordenar predeterminadamente de forma creciente el contenido del data frame seleccionado. El argumento decreasing=T cambia el sentido de la ordenación a decreciente.

Ejemplo

1
df <- df[order(df$Notas_medias, decreasing=T),]

Función apply()

Esta función permite aplicar otras funciones al total del data frame numérico. Esto es posible indicando en su interior el data frame deseado, si actúa por fila o columna (números 1 y 2, respectivamente), y la función a realizar. Esta función se dirige a matrices o data frames de contenido numérico, ya que produce NA en las celdas cuyo objeto atómico es de otro tipo.

Ejemplos

1
2
ejemplo_apply <- apply(df,2,mean)
ejemplo_apply2 <- apply(df,2,sum)

Función by()

Mediante by() se puede aplicar una función determinada a un subgrupo del data frame. En primer lugar, se indica la columna a partir de la cual se pretende tomar las categorías que dividen el data frame. A continuación, se indica la columna cuyos valores se someterán a la función, que se indica justo después. El resultado es contenido en un tipo de objeto específico denominado by.

Ejemplos

1
ejemplo_by <- by(df$Notas_medias, df$Clase, summary)

Función aggregate()

Esta función es muy similar a by(). La diferencia radica en sus argumentos y el resultado, ya que la columna debe ser presentada como una lista y el resultado es de tipo data frame.

Ejemplos

1
ejemplo_aggregate <- aggregate(df$Notas_medias, list(df$Clase), summary)

Función split()

El data frame puede ser dividido atendiendo a sus factores mediante esta función. El resultado es contenido en una lista.

Ejemplo

1
ejemplo_split <- split(df,df$Clase)

Función subset()

Ejemplo

1
ejemplo_subset <- subset(df, Clase==1 & Notas_medias>=5, select = Notas_medias)

Función merge()

Mediante merge() se pueden mezclar dos diferentes data frames que guarden relación en alguna variable y sus observaciones.

Ejemplo

1
2
3
df2 <- data.frame(aa=c("Val", "Glu", "Arg"), polaridad=c("No polar", "Ácido", "Básico"))
df3 <- data.frame(aa=c("Glu", "Arg", "Ile"), cantidad=c(23,10,14))
ejemplo_merge <- merge(df2,df3,by="aa")

Formatos de un data frame

Los data frame pueden encontrarse en formato "wide" o "long" (ancho o largo), aunque existen modos parciales. El tipo de formato que presente el data frame es crucial en diferentes tipos de paquetes para tomar la información y tratarla.

El conjunto de datos muestran formato ancho cuando diversos valores se encuentran en múltiples columnas. En cambio, el formato largo se refiere al data frame que contiene varias observaciones por variable. La diferencia es apreciable en los siguientes casos:

1
2
wide <- data.frame(aa=c("Glu", "Cys"), enzima=c("SOD","GSH"), p_hidrógeno=c(4,5), p_disulfuro=c(2,1))
long <- data.frame(aa=c("Glu", "Cys", "Glu", "Cys"), enzima=c("SOD","GSH","SOD","GSH"), interaccion_puentes=c("hidrógeno","disulfuro","disulfuro","hidrógeno"), cantidad=c(4,2,1,5))

R base ofrece unas funciones para transformar el data frame de un formato a otro, lo que se conoce como pivotar:

  • La función stack() rehace el data frame de formato ancho a largo.

  • La función unstack() al contrario.

Ejemplos

1
2
wide_a_long <- stack(wide, select=c(p_hidrógeno, p_disulfuro))
long_a_wide <- unstack(long, cantidad~interaccion_puentes)

Existen otros paquetes que facilitan la manipulación de formatos de un modo más avanzado. El más extendido es reshape2, cuyas funciones melt() y dcast() llevan a cabo la transformación a formato largo y ancho, respectivamente.

Ejemplos

1
2
3
4
install.packages("reshape2")
library(reshape2)
wide_a_long_reshape2 <- melt(wide)
long_a_wide_reshape2 <- dcast(long, aa~interaccion_puentes)

Si bien, tidyverse contiene el paquete tidyr, que permite realizar dichas transformaciones mediante las funciones gather() y spread(), que cambian el formato ancho y largo, de forma respectiva. Realmente, crean un nuevo objeto característico de esta librería, denominado tibble, el cual es similar a un data frame, al cual se le aportan ciertas características.

Ejemplos

1
2
3
library(tidyr)
wide_a_long_tidyr <- gather(wide, key = "interaccion", value = "cantidad", 3:4)
long_a_wide_tidyr <- spread(long,key="interaccion_puentes",value = "cantidad", 3:4)

El paquete tidyr va más allá y ofrece diversas funciones de manipulación de data frames, las cuales requieren de pipes para llamar al objeto al que se le aplicarán. El pipe es una herramienta procedente del paquete magrittr de tidyverse que posibilita llevar a cabo múltiples operaciones consecutivas. Se indican con la siguiente combinación de símbolos: %>%.

De hecho, gather() y spread() pueden ser sustituidos por las funciones pivot_longer() y pivot_wider(), respectivamente, si se utiliza el pipe para conectar con el objeto.

Ejemplos

1
2
wide_a_long_pipe <- wide %>% pivot_longer(3:4, names_to="interaccion", values_to="cantidad")
long_a_wide_pipe <- long %>% pivot_wider(1:4, names_from="interaccion_puentes", values_from="cantidad")

Las funciones de tidyr separate() y unite() permiten separar o unir columnas, respectivamente, de acuerdo a la posición de un carácter separador.

Ejemplos

1
2
df <- df %>% unite(clase_nota, Clase, Notas_medias)
df <- df_unite %>% separate(clase_nota, into=c("Clase", "Notas_medias"))

Tratamiento de datos con plyr y dplyr

Estos paquetes pertenecen a la biblioteca tidyverse y facilitan el acceso y manipulación de los datos de los data frames. En primer lugar, plyr es similar a la función de R base apply(), ya que permite realizar una función al conjunto de datos señalado. Dependiendo del tipo de objeto que se quiera recibir como output de la función, se aplicará un tipo de función posible de plyr. Entre otras funciones destacan ddply() y dlply(), cuyas letras iniciales hacen referencia al objeto de entrada y de salida, respectivamente, siendo d por data frame y l a lista. Los argumentos básicos son el objeto de entrada, la variable y la función deseada.

Ejemplos

1
2
3
library(plyr)
df_medias <- ddply(.data = df, .variables = "Clase", .fun = function(x) mean(x$Notas_medias))
df_list_max <- dlply(.data = df, .variables = "Clase", .fun = function(x) max(x$Notas_medias))

Por otro lado, dplyr ofrece diversas funciones que, en su gran mayoría, requieren de pipes. Una de ellas es filter(), la cual filtra el data frame por las columnas y observaciones deseadas. Además, esta función puede combinarse con otras mediante un nuevo pipe, como la función select(), que agudiza la búsqueda de los datos deseados.

Ejemplo

1
2
3
library(dplyr)
df_clase1 <- df %>% filter(Clase=="1") %>% select(Notas_medias)
df_clase2 <- df %>% filter(Clase=="2") %>% select(Notas_medias)

Las funciones de dplyr mutate() y transmute() permiten añadir nuevas variables (columnas) a partir de las ya existentes. Esta última función mantiene solamente la variable creada.

Ejemplos

1
2
long_mutate <- long %>% mutate(porcentaje = cantidad / 5 * 100)
long_transmute <- long %>% transmute(porcentaje = cantidad / 5 * 100)

Ejercicio complementario

Ejercicio resumen

El archivo df_resumen.Rmd contiene dos ejercicios de manipulación de data frame sobre los ficheros test1.xlsx, test2.xlsx y dominios.txt los cuales proceden de la realización de un proyecto durante el curso Aspectos Físico-Químicos de Interacciones en Biomoléculas. De este modo se pretende resumir de forma explicativa lo estudiado en este apartado, por lo que requiere la instalación de las librerías tidyverse y reshape2.