Subconjunto de Datos
Resumen
Enseñando: 25 min
Ejercicios: 10 minPreguntas
¿Cómo puedo trabajar con subconjuntos de datos en R?
Objectivos
Para poder obtener subconjunos de vectores y data frames
Para poder extraer un elemento individual o multiples elementos: por índice, por nombre, usando operadores de comparación
Para poder saltear y eliminar elementos de varias estructuras de datos.
R tiene muchos operadores poderosos para crear subconjuntos. Dominarlos te permitirá realizar operaciones complejas de manera sencilla en cualquier tipo de dataset.
Hay 6 formas diferentes que podemos obtener subconjuntos de cualquier tipo de objeto, y tres diferentes operadores de subconjunto para las diferentes estructuras de datos.
Empezaremos con el caballito de batalla de R: un vector numérico simple.
x <- c(5.4, 6.2, 7.1, 4.8, 7.5)
names(x) <- c('a', 'b', 'c', 'd', 'e')
x
a b c d e
5.4 6.2 7.1 4.8 7.5
Vectores atómicos
En R, los vectores simples que contienen cadenas de caracteres, números, o valores lógicos se llaman vectores atómicos porque no pueden simplificarse más.
Entonces ahora que hemos creado un vector ficticio para jugar, ¿cómo accedemos a su contenido?
Acceder a elementos usando sus índices
Para extraer elementos de un vector podemos dar su correspondiente índice, empezando desde uno:
x[1]
a
5.4
x[4]
d
4.8
Puede parecer distinto, pero el operador corchete es una función. Para vectores (y matrices), significa “dame el n-ésimo elemento”.
Podemos pedir múltiples elementos de una vez:
x[c(1, 3)]
a c
5.4 7.1
O porciones del vector:
x[1:4]
a b c d
5.4 6.2 7.1 4.8
el operador :
crea una secuencia de números desde el elemento de la izquierda hasta el de la derecha.
1:4
[1] 1 2 3 4
c(1, 2, 3, 4)
[1] 1 2 3 4
Podemos pedir el mismo elemento muchas veces:
x[c(1, 1, 3)]
a a c
5.4 5.4 7.1
Si pedimos un índice mayor a la longitud del vector, R devolverá un valor faltante:
x[6]
<NA>
NA
Este es un vector de longitud uno que contiene un NA
, cuyo nombre es también NA
.
Si pedimos el 0-ésimo elemento, obtendremos un vector vacío:
x[0]
named numeric(0)
La numeración de vectores en R empieza en 1
En muchos lenguajes de programación (C y Python, por ejemplo), el primer elemento de un vector tiene índice 0. En R, el primer elemento es 1.
Salteando y eliminando elementos
Si en un vector usamos un número negativo como índice, R devolverá todos los elementos excepto el número de elemento especificado:
x[-2]
a c d e
5.4 7.1 4.8 7.5
Podemos saltear múltiples elementos:
x[c(-1, -5)] # or x[-c(1,5)]
b c d
6.2 7.1 4.8
Consejo: Orden de operaciones
Un error común en las personas novatass occurre cuando quieren saltear porciones de un vector. Es natural tratar negando una secuencia como esto:
x[-1:3]
Eso devuelve un error incomprensible:
Error in x[-1:3]: only 0's may be mixed with negative subscripts
Pero recuerda el orden de operaciones.
:
es en realidad una función. Toma como primer argumento un -1, y como segundo el 3, por lo cual genera la secuencia de números:c(-1, 0, 1, 2, 3)
.La solución correcta sería envolver la función y sus argumentos con un paréntesis, para que el operador
-
se aplique al resultado:x[-(1:3)]
d e 4.8 7.5
Para eliminar elementos de un vector, necesitamos asignar el resultado a la misma variable:
x <- x[-4]
x
a b c e
5.4 6.2 7.1 7.5
Desafío 1
Dado el siguiente código :
x <- c(5.4, 6.2, 7.1, 4.8, 7.5) names(x) <- c('a', 'b', 'c', 'd', 'e') print(x)
a b c d e 5.4 6.2 7.1 4.8 7.5
Escribe por lo menos 3 comandos distintos que produzcan la siguiente salida:
b c d 6.2 7.1 4.8
Después que hayas encontrado 3 comandos distintos, compara tus notas con tu vecino. Tuvieron diferentes estrategias?
Solución al desafío 1
x[2:4]
b c d 6.2 7.1 4.8
x[-c(1,5)]
b c d 6.2 7.1 4.8
x[c("b", "c", "d")]
b c d 6.2 7.1 4.8
x[c(2,3,4)]
b c d 6.2 7.1 4.8
subconjunto por nombre
Podemos extraer elementos usando su nombre, en vez de extraerlos usando su índice.
x <- c(a = 5.4, b = 6.2, c = 7.1, d = 4.8, e = 7.5) # podemos nombrar un vector sobre la marcha
x[c("a", "c")]
a c
5.4 7.1
Normalmente esta es una manera mucho más fiable de crear subconjuntos: la posición de varios elementos a menudo puede cambiar cuando se encadenan operadores para crear subconjuntos, pero los nombres siempre permanecen igual!
Haciendo subconjuntos usando otros operadores lógicos
También podemos usar cualquier otro vector de tipo logical para crear subconjuntos:
x[c(FALSE, FALSE, TRUE, FALSE, TRUE)]
c e
7.1 7.5
Dado que los operadores de comparación (e.g. >
,<
,==
) evalúan vectores lógicos,
también podemos usarlos para crear subconjuntos de vectores: la siguiente
declaración da el mismo resultado que la anterior.
x[x > 7]
c e
7.1 7.5
Analizándolo, esta declaración primero evalúa x>7
, generando
un vector de tipo logical c(FALSE, FALSE, TRUE, FALSE, TRUE)
, y después
selecciona los elementos de x
que corresponden a los valores TRUE
.
Podemos usar ==
para imitar el método previo de indexar por nombre
(recuerda que tiene que usar ==
en vez de =
para comparaciones):
x[names(x) == "a"]
a
5.4
Sugerencia: Combinando condiciones lógicas
A menudo queremos combinar múltiples criterios lógicos. Por ejemplo, podríamos querer encontrar todos los países que están en Asia or Europa and tienen expectativa de vida dentro de un cierto rango. Existen varias operaciones para combinar vectores lógicos en R:
&
, el operador “logical AND”: retornaTRUE
si ambos la izquierda y la derecha sonTRUE
.|
, el operador “logical OR”: retornaTRUE
, si cualquiera la izquierda o la derecha (o ambos) sonTRUE
.A veces puedes ver
&&
y||
en vez de&
y|
. Estos operadores de dos caracteres sólo miran al primer elemento de cada vector e ignoran el resto de elementos restantes. En general deberías no usar los operadores de dos caracteres en análisis de datos; resérvalos para programar, i.e. decidir si ejecutar una declaración o no.
- Operadores
!
, y “logical NOT”: conviertenTRUE
enFALSE
yFALSE
enTRUE
. Puede negar una condición lógica (e.g.!TRUE
ser convierte enFALSE
), o un vector entero de condiciones(e.g.!c(TRUE, FALSE)
se convierte enc(FALSE, TRUE)
).Además, puedes comparar los elementos dentro de un único vector usando la función
all
(retornaTRUE
si cada elemento del vector esTRUE
) y la funciónany
(retornaTRUE
si uno o más elementos del vector sonTRUE
).
Desafío 2
Dado el siguiente código :
x <- c(5.4, 6.2, 7.1, 4.8, 7.5) names(x) <- c('a', 'b', 'c', 'd', 'e') print(x)
a b c d e 5.4 6.2 7.1 4.8 7.5
Escribe un comando de hacer subconjuntos que retorne los valores de x que son mayores que 4 y menores que 7.
Solución al desafío 2
x_subset <- x[x<7 & x>4] print(x_subset)
a b d 5.4 6.2 4.8
Sugerencia: Obteniendo ayuda para los operadores
Recuerda que puedes obtener ayuda para los operadores empaquetándolos entre comillas:
help("%in%")
or?"%in%"
.
Manejando valores especiales
En algún momento encontraremos funciones en R que no pueden manejar valores faltantes, infinito o datos indefinidos.
Existen algunas funciones especiales que puedes usar para filtrar estos datos:
is.na
regresa todas las posiciones de un vector, matriz. o data frame que contenganNA
(oNaN
)- de la misma manera,
is.nan
, yis.infinite
hacen los mismo paraNaN
yInf
.is.finite
regresa todas las posiciones de un vector, matriz, o data frame que no contenganNA
,NaN
oInf
.na.omit
filtra todos los valores faltantes de un vector
Data frames
Recordemos que las data frames son listas, por lo que aplican reglas similares. Sin embargo estos también son objetos de dos dimensiones:
[
con un argumento funcionará de la misma manera que para las listas, donde cada elemento
de la lista corresponde a una columna. El objecto devuelto será un data frame:
head(gapminder[3])
pop
1 8425333
2 9240934
3 10267083
4 11537966
5 13079460
6 14880372
Similarmente, [[
extraerá una sola columna:
head(gapminder[["lifeExp"]])
[1] 28.801 30.332 31.997 34.020 36.088 38.438
Y $
proporciona atajo para extraer columnas por nombre:
head(gapminder$year)
[1] 1952 1957 1962 1967 1972 1977
Para seleccionar filas y/o columnas específicas, puedes proporcionar dos argumentos a [
gapminder[1:3, ]
country year pop continent lifeExp gdpPercap
1 Afghanistan 1952 8425333 Asia 28.801 779.4453
2 Afghanistan 1957 9240934 Asia 30.332 820.8530
3 Afghanistan 1962 10267083 Asia 31.997 853.1007
Si nuestro subconjunto es una sola fila, el resultado será una data frame (porque los elementos son de distintos tipos):
gapminder[3, ]
country year pop continent lifeExp gdpPercap
3 Afghanistan 1962 10267083 Asia 31.997 853.1007
Pero para una sola columna el resultado será un vector (esto puede cambiarse con
el tercer argumento, drop = FALSE
).
Desafío 3
Corrige cada uno de los siguientes errores para hacer subconjuntos de data frames:
Extraer observaciones colectadas en el año 1957
gapminder[gapminder$year = 1957, ]
Extraer todas las columnas excepto de la 1 a la 4
gapminder[, -1:4]
Extraer las filas donde la esperanza de vida es mayor de 80 años
gapminder[gapminder$lifeExp > 80]
Extraer la primera fila, y la cuarta y quinta columna (
lifeExp
andgdpPercap
).gapminder[1, 4, 5]
Avanzado: extraer las filas que contienen información para los años 2002 y 2007
gapminder[gapminder$year == 2002 | 2007,]
Solución al desafío 3
Corrige cada uno de los siguientes errores para hacer subconjuntos de data frames:
Extraer observaciones colectadas en el año 1957
# gapminder[gapminder$year = 1957, ] gapminder[gapminder$year == 1957, ]
Extraer todas las columnas excepto de la 1 a la 4
# gapminder[, -1:4] gapminder[,-c(1:4)]
Extraer las filas donde la esperanza de vida es mayor de 80 años
# gapminder[gapminder$lifeExp > 80] gapminder[gapminder$lifeExp > 80,]
Extraer la primera fila, y la cuarta y quinta columna (
lifeExp
andgdpPercap
).# gapminder[1, 4, 5] gapminder[1, c(4, 5)]
Avanzado: extraer las filas que contienen información para los años 2002 and 2007
# gapminder[gapminder$year == 2002 | 2007,] gapminder[gapminder$year == 2002 | gapminder$year == 2007,] gapminder[gapminder$year %in% c(2002, 2007),]
Desafío 4
¿Por qué
gapminder[1:20]
regresa un error? ¿En qué difiere degapminder[1:20, ]
?Crea un
data.frame
nuevo llamadogapminder_small
que sólo contenga las filas de la 1 a la 9 y de la 19 a la 23. Puedes hacerlo en uno o dos pasos.Solución al desafío 4
gapminder
es un data frame por lo que para hacer un subconjunto necesita dos dimensiones.gapminder[1:20, ]
genera un subconjunto de los datos de las primeras 20 filas y todas las columnas.2.
gapminder_small <- gapminder[c(1:9, 19:23),]
Puntos Clave
El indexado en R empieza en 1, no en 0.
Accedes a valores individuales por ubicación utilizando
[]
.Accedes a porciones de datos utilizando
[bajo:alto]
.Accedes a conjuntos de datos arbitrarios utilizando
[c(...)]
.Usas operaciones lógicas y vectores lógicos para acceder a subconjuntos de datos.