3.1 Manipulación de datos

En los siguientes apartados veremos cómo resolver con R algunas tareas de manipulación de datos que van a aparecer frecuentemente al utilizar la herramienta.

3.1.1 Tratamiento de valores desconocidos

En ocasiones es posible que no sepamos cuál es el valor concreto de un determinado elemento de una estructura de datos (vector, lista, etc.). Para hacer frente a esta situación, R nos ofrece la posibilidad de utilizar un valor reservado, denominado NA (del inglés Not Available). Así por ejemplo:

v<-c(2.3, -1.2, 2.4, NA, 0.7) 
v 
# [1]  2.3 -1.2  2.4   NA  0.7 

Nótese que NA se representa sin comillas (no es una cadena de caracteres). Al realizar cualquier operación que involucre a un valor NA, el resultado será necesariamente un NA:

v<-c(2.3, -1.2, 2.4, NA, 0.7) 
2*v 
# [1]  4.6 -2.4  4.8   NA  1.4 

A través de la función is.na podemos comprobar si un determinado valor es o no desconocido:

v<-c(2.3, -1.2, 2.4, NA, 0.7) 
is.na(v) 
# [1] FALSE FALSE FALSE  TRUE FALSE 

También podemos eliminar los valores desconocidos de una estructura de datos (vector, data frame) utilizando la función na.omit:

r<-c(na.omit(v)) 
r 
# [1]  2.3 -1.2  2.4  0.7 

3.1.2 Conversión de tipos

Como vimos en el tema anterior, existe una amplia variedad de tipos y estructuras de datos que podemos utilizar para manejar información en R. En ocasiones nos interesará poder convertir información de uno a otro tipo (por ejemplo, un número a una cadena de caracteres). Para facilitar esta tarea, existe toda una familia de funciones en R (cuyo nombre tiene la forma as.tipo, como por ejemplo, as.numeric) que podemos utilizar. Podemos ver a continuación algunos ejemplos de uso de estas funciones:

as.numeric('12.3') 
# [1] 12.3 

# Definir el data frame tabla
Nombre <- c("Mario","Anton","Ana")
Edad <- c(36, 23, 36)
Peso <- c(78.5, 83.9, 65.4)
Sexo <- c("M","M","F")
tabla <- data.frame(Nombre,Edad,Peso,Sexo)

tabla
# Un data frame previamente definido 
#   Nombre Edad Peso Sexo
# 1  Mario   36 78.5    M
# 2  Anton   23 83.9    M
# 3  Ana     36 65.4    F
 
as.matrix(tabla) 
#      Nombre  Edad Peso   Sexo
# [1,] "Mario" "36" "78.5" "M"
# [2,] "Antón" "23" "83.9" "M"
# [3,] "Ana"   "36" "65.4" "F" 

Se puede ver en este último ejemplo que, dado que las matrices tienen que tener todos sus valores del mismo tipo, se convierten automáticamente todas las entradas del data frame a un tipo común (en este caso, cadena de caracteres).

Otra función que puede ser de utilidad a la hora de convertir tipos es la función unlist, que devuelve un vector conteniendo los elementos de una lista.

lista<-list(2, 1+3i, "Hola") 
unlist(lista) 
# [1] "2"    "1+3i" "Hola" 

Donde de nuevo se puede ver que se ha llevado a cabo una conversión automática de los valores de la lista en cadenas de caracteres, puesto que los elementos de un vector deben ser todos del mismo tipo.

3.1.3 Ordenación de datos

R nos ofrece funciones de librería para poder llevar a cabo la ordenación de los datos incluidos en una estructura. Ahora bien, la función a utilizar dependerá de la estructura concreta de datos con la que vayamos a trabajar:

  • La función sort se emplea cuando queremos ordenar vectores. Por defecto la ordenación es ascendente, aunque se puede configurar mediante el parámetro decreasing:
v<-c(2,1,5,-2,3,0) 
sort(v) 
# [1] -2  0  1  2  3  5 

sort(v, decreasing=T) 
# [1]  5  3  2  1  0 -2 

La función order se utiliza fundamentalmente con data frames y nos va a permitir ordenar la tabla en base a una columna o columnas de la misma. Podemos utilizar también el parámetro decreasing para indicar si el orden es o no decreciente.

tabla   # Un data frame previamente creado 
#   Nombre Edad Peso Sexo 
# 1  Mario   36     78.5    M 
# 2  Antón   23     83.9    M 
# 3    Ana   36     65.4    F 

tabla[order(tabla$Edad,tabla$Peso),]  
#   Nombre Edad Peso Sexo 
# 2  Antón   23    83.9    M 
# 3    Ana   36    65.4    F 
# 1  Mario   36    78.5    M 

3.1.4 Búsqueda de datos

En el tema anterior vimos cómo podíamos seleccionar ciertos datos de una estructura de datos concreta (utilizando los operadores de corchete [] y corchete doble. La función which, de R está relacionada con estos operadores, ya que nos permite buscar los elemento de una determinada estructura de datos que cumplan cierta condición, devolviéndonos la posición (o posiciones) de los elementos que cumplen la condición:

v<-c(2,1,5,-2,3,0) 
v[v<0]  # Selección 
# [1] -2 

which(v<0)  # Buscar el índice dónde se cumple la condición 
# [1] 4 

tabla   # Un data frame previamente creado 
#   Nombre Edad Peso Sexo 
# 1  Mario   36     78.5    M 
# 2  Antón   23     83.9    M 
# 3    Ana   36     65.4    F 

tabla[(tabla$Peso>70)&(tabla$Edad<30),]  # Selección 
#   Nombre Edad Peso Sexo 
# 2  Antón   23 83.9    M 

which((tabla$Peso>70)&(tabla$Edad<30))  # Búsqueda de índices 
# [1] 2 

3.1.5 Manipulación de cadenas de caracteres

Como indicamos en el tema anterior, la manipulación de cadenas de caracteres suele llevarse a cabo por medio de funciones, no operadores (por ejemplo, no podemos sumar cadenas de caracteres). Algunas de las funciones de manipulación de cadenas de caracteres más utilizadas son:

  • La función substr que permite extraer (o reemplazar) una subcadena dentro de una cadena.

  • La función grep que permite la búsqueda de patrones en una cadena, bien indicados mediante una expresión regular o bien patrones fijos (para lo que usaremos el parámetro fixed con valor TRUE en la llamada a la función).

  • La función strsplit permite trocear una cadena de caracteres mediante un delimitador dado.

  • La función paste permite unir cadenas utilizando un separador dado entre ellas, que se establece mediante el parámetro sep. Cuando los argumentos contienen múltiples elementos (por ejemplo, son vectores) se puede hacer que se concatenen todos ellos con un separador dado en el parámetro collapse.

Podemos ver a continuación algunos ejemplos de uso de estas funciones:

cad<-"Hola Mundo" 
substr(cad, 2, 4) 
# [1] "ola" 

substr(cad, 2, 4)<-"OLA" 
cad 
# [1] "HOLA Mundo" 

grep(".ab.", c("Ejemplo","Cabeza","Abecedario","C.ab.o")) 
# [1] 2 4 

grep(".ab.", c("Ejemplo","Cabeza","Abecedario","C.ab.o"), fixed=T) 
# [1] 4 

strsplit("En un lugar de la Mancha", " ") 
[[1]] 
# [1] "En"     "un"     "lugar"  "de"     "la"     "Mancha" 

paste("Hola", "Mundo", sep="_") 
# [1] "Hola_Mundo" 

paste(seq(1,5), "a", sep="+") 
# [1] "1+a" "2+a" "3+a" "4+a" "5+a" 

paste(seq(1,5), seq(5,1), sep="*", collapse="-") 
# [1] "1*5-2*4-3*3-4*2-5*1" 

3.1.6 Importar/exportar datos desde/a fichero

Aunque en los ejemplos que hemos visto hasta ahora hemos introducido la información a analizar directamente en la consola de R, el caso más habitual es que esta se encuentre en un fichero, y que, por tanto, tengamos que importar los datos antes de proceder a su análisis. Aunque existen paquetes de R que nos permiten interactuar con formatos diversos (por ejemplo, XML, Excel, formatos de otro software estadístico, como SPSS o SAS, etc.) el caso más habitual (y el que trataremos en esta sección) es el de leer los datos desde un fichero de texto.

Para poder importar datos desde fichero al entorno de R usaremos fundamentalmente una de las dos siguientes opciones:

  • La función read.table que nos permite leer datos en formato tabular (y que se utiliza para leer data frames). Los principales argumentos de esta función son:

    • file: representa el fichero del que queremos leer los datos.

    • header: un valor lógico que nos indica si la primera línea debe ser tratada como la cabecera (nombre de las columnas de datos).

    • sep: por defecto se usan como delimitadores los espacios en blanco (espacios, tabuladores, fines de línea). Si ese no es nuestro caso, se puede indicar expresamente el delimitador que separa los valores con este parámetro.

    • fileEncoding: indica cómo se representa la información almacenada en el fichero (con qué estándar de codificación de caracteres, como UTF-8, ASCII, etc).

Por ejemplo, si tenemos un fichero cuya ruta es /path/to/datos.dat y cuyo contenido (en codificación UTF-8) es:

Nombre,Edad,Peso,Sexo 
Mario,36,78.5,M 
Antón,23,83.9,M 
Ana,36,65.4,F 

Podemos leer esos datos en un data frame de R ejecutando en la consola:

tabla<-read.table("/path/to/datos.dat", sep=",", header=TRUE, fileEncoding="UTF-8") 

Si no conocemos la ruta del fichero donde se encuentran los datos puede ser de utilidad la función file.choose que abre una ventana del explorador de ficheros para permitir elegir interactivamente dicha ruta.

tabla<-read.table(file.choose(), sep=",", header=TRUE, fileEncoding="UTF-8") 
  • La función scan que se suele utilizar cuando lo que queremos leer son vectores. Además de los argumentos file, sep y fileEncoding, que ya hemos visto en read.table, otros argumentos relevantes son:

    • what: indica qué tipo de datos vamos a leer del fichero (logical, numeric, complex, etc).

    • n: número máximo de elementos que queremos leer del fichero (si hay más, se descartan).

Por ejemplo, si tenemos un fichero de texto /path/to/lista.dat con el siguiente contenido:

1,2,3,4,5,6,7,8,9,10 

Podemos leer sus 8 primeros datos como un vector numérico de R haciendo:

vec<-scan("/path/to/lista.dat", what=numeric(), n=8, sep=",") 

También es posible exportar la información a un fichero de texto. Dos de las funciones más utilizadas con este fin son:

  • La función write.table que permite volcar a fichero una tabla (data frame). Si consultamos la ayuda de R, veremos que sus principales argumentos son:

    • x: el data frame que queremos volcar a fichero.

    • file: el fichero de destino.

    • sep: separador de los distintos datos.

    • fileEncoding: codificación de caracteres a utilizar.

  • La función write que se suele utilizar para exportar vectores y que tiene tres argumentos principales:

    • x: datos a exportar.

    • file: fichero de destino.

    • sep: separador de los distintos datos.

Por ejemplo, podemos volcar a fichero el data frame tabla y el vector vec leídos en los ejemplos anteriores haciendo:

write.table(tabla, file="/path/to/tabla.data") 
write(vec, file="/path/to/vector.data")