Operadores de subconjuntos

En muchas ocasiones, cuando se trabaja con grandes conjuntos de información, solo se está interesado en una pequeña parte de éste conjunto del análisis. Y es por ello que los operadores de subconjuntos permiten acceder, seleccionar o excluir datos que se encuentren dentro de estructuras de datos especificas.

El empleo de subconjuntos puede ser algo difícil de aprender, debido a que para poder dominar tal aspecto, es necesario tener en cuenta otro conjunto de conceptos interrelacionados:

  • El lenguaje de programación que se emplea, debido a que cada lenguaje puede tener características diferentes para el manejo de subconjuntos.
  • Las diferentes operaciones para seleccionar subconjuntos que pueden haber.
  • Los diferentes tipos de subconjuntos.
  • El uso de subconjuntos en conjunción con la asignación.

Para dominar los operadores de subconjuntos en R, el objetivo inicialmente es aprender a dominar el operador más simple para la selección de subconjuntos en vectores atómicos, el cual se logra mediante el empleo de los corchetes []. Posteriormente se buscará generalizar dichos resultados a dimensiones más altas, tales como matrices, marcos de datos, arreglos y listas, mediante el empleo de operadores tales como [[]], $ o la combinación de estos.

Vectores atómicos

Tal como se señaló, para la manipular información dentro de vectores, pueden emplearse el operador de subconjuntos dado por [], los cuales sirven para seleccionar, ordenar, filtrar, eliminar información dentro de un vector.

  • Seleccionar: Al emplear enteros positivos dentro de [], lo que se hace es seleccionar valores a los objetos que se encuentren en la posición del entero seleccionado.

Selección en vectores

Supongamos un vector \(x\) dado por los números \(3.1, 7.8, 8.9, 10.5, 2.7, 5.7\), entonces si se desea seleccionar los valores \(8.9\) y \(2.7\) del vector, notamos que estos números se encuentran en la posición \(3\) y \(5\), respectivamente, y por tanto, podemos emplear la notación \[\begin{align*} x[c(3,5)] \end{align*}\] tal que

# Creamos vector numérico
x <- c(3.1, 7.8, 8.9, 10.5, 2.7, 5.7)
# Empleamos operador de subconjuntos para seleccionar los valores 8.9 y 2.7
# los cuales se encuentran en la posición 3 y 5
x[c(3, 5)]
[1] 8.9 2.7
  • Duplicar: Al emplear repetidas veces los mismos enteros positivos dentro de [], lo que se hace es duplicar valores a los objetos que se encuentren en la posición del entero seleccionado.

Duplicar en vectores

También es posible seleccionar dos veces un mismo valor con el fin de duplicarlo, por ejemplo, deseamos seleccionar el valor \(3.1\) y duplicar el valor \(10.5\), entonces como el valor \(3.1\) está en la posición \(1\) y el valor \(10.5\) está en la posición \(4\), podemos emplear la notación \[\begin{align*} x[c(1, 4, 4)] \end{align*}\] en donde se nota que escribimos dos veces el valor \(4\), tal que

# Empleamos operador de subconjuntos para seleccionar los valores 3.1 y
# duplicar el valor 10.5, los cuales se encuentran en la posición 1 y 4
x[c(1, 4, 4)]
[1]  3.1 10.5 10.5
  • Reemplazar: Al emplear enteros positivos dentro de [], y aplicar posteriormente el operador de asignación <-, lo que se hace es que se reasigna el valores de interés, por un nuevo.

Reemplazar en vectores

Para reasignar valores, podemos llamar la posición de interés, y usar el operador de asignación, para reemplazar dicha posición por el valor de interés. Suponga que del vector \(x\) queremos reemplazar el valor \(5.7\), por un \(1000\), entonces, como el valor \(5.7\) se encuentra en la sexta posición, podemos llamar dicha posición mediante el operador de subconjuntos y el operador de asignación, mediante la notación \[\begin{align*} x[c(6)] <- 1000 \end{align*}\] tal que

# Empleamos operador de subconjuntos para seleccionar el valor 5.7 que se
# encuentra en la posición 6, y asignarle a esta posición el valor 1000
x[c(6)] <- 1000
x
[1]    3.1    7.8    8.9   10.5    2.7 1000.0

  • Eliminar: Al emplear enteros negativos dentro de [], lo que se hace es eliminar los objetos que se encuentren en la posición del entero seleccionado.

Eliminar

Supongamos un vector \(y\) dado por los números \(3.1, NA, 8.9, 10.5, 2.7, 5.7\), entonces si se desea eliminar el valor NA del vector, notamos que este valor se encuentran en la posición \(2\), y por tanto, podemos emplear la notación \[\begin{align*} y[-c(2)] \end{align*}\] dentro del operador de subconjuntos para eliminar dicho valor, tal que

# Creamos vector numérico
y <- c(3.1, NA, 8.9, 10.5, 2.7, 5.7)

# Empleamos operador de subconjuntos para eliminar el valor NA el cual se
# encuentran en la posición 2
y[-c(2)]
[1]  3.1  8.9 10.5  2.7  5.7
  • Vectores lógicos o condicionales: También podemos emplear vectores lógicos o condicionales dentro del operador de subconjuntos [], para seleccionar o filtrar aquellos valores de interés.

Seleccionar con vectores lógicos

Supongamos nuevamente el vector \(x\) dado por los números \(3.1, 7.8, 8.9, 10.5, 2.7, 5.7\), entonces podemos usar un vector de TRUE o FALSE para seleccionar los valores de interés. Supongamos que deseamos seleccionar solo los dos primeros valores del vector \(x\), entonces podemos emplear un vector de la forma \[\begin{align*} x[c(T,T,F,F,F,F)] \end{align*}\] tal que

# Empleamos operador de subconjuntos con un vector lógico para seleccionar
# los dos primeros valores del vector
x[c(T, T, F, F, F, F)]
[1] 3.1 7.8

Filtrar con un condicional

También podemos emplear condicionales para filtrar valores, suponga que se quiere filtrar aquellos valores que sean menores a \(4\) del vector \(x\), entonces podemos usar el condicional \[\begin{align*} x[x < 4] \end{align*}\] tal que

# Empleamos operador de subconjuntos con un condicional para filtrar
# aquellos valores que cumplen la condición de ser menor a 4
x[x < 4]
[1] 3.1 2.7

Filtrar con varios condicionales

Adicionalmente, podemos emplear más de un condicional a la vez, en donde podemos emplear el operador de conjunción | o disyunción &, para agregar varios condicionales. Suponga que queremos filtrar del vector y, los valores que sean mayores o igual a 5 o sean NA. Para ello empleamos la notación \[\begin{align*} y[y >= 5 | is.na(y)] \end{align*}\] tal que

# Empleamos operador de subconjuntos con condicionales para filtrar aquellos
# valores mayores o iguales a 5 o que sean NA
y[y >= 5 | is.na(y)]
[1]   NA  8.9 10.5  5.7
  • Vector de caracteres También puede pasar que los vectores de interés, no sean numéricos si no que sean cadenas de caracteres o en su defecto, que sean numéricos y posean cadenas de caracteres asociados. En dicho caso, podemos emplear los operadores de subconjuntos escribiendo entre comillas aquellos caracteres de interés.

Vector de caracteres

Supongamos un vector \(w\) dado por los caracteres “Daniel”, “Carlos”, “Paola”, “Daniel”, “Juan”, “Ana”, entonces si estamos interesados en aquellos valores que contienen la cadena de caracteres “uno”, entonces podemos emplear la notación \[\begin{align*} x[x == “Daniel”] \end{align*}\] para filtrar dichos valores de interés, tal que

# Creamos vector de caracteres
w <- c("Daniel", "Carlos", "Paola", "Daniel", "Juan", "Ana")

# Empleamos operador de subconjuntos, junto con el operador de igualdad para
# filtrar por caracteres
w[w == "Daniel"]
[1] "Daniel" "Daniel"

Vector con nombres

Similarmente, supongamos un vector numérico \(z\), que posee caracteres asociados a los números, tal que “Daniel” = 4, “Carlos” = 8, “Paola” = 12.4, “Ana” = 2.4, “Juan”= 8, “Ana” = 1. Entonces, si queremos filtrar por “Ana” empleando el operador de subconjuntos, podemos emplear la notación \[\begin{align*} z[\text{names}(z) == “Ana”] \end{align*}\] o la notación numérica \[\begin{align*} z[z == 2.4 | z == 1.0] \end{align*}\] tal que

# Creamos vector numérico con caracteres
z <- c(Daniel = 4, Carlos = 8, Paola = 12.4, Ana = 2.4, Juan = 8, Ana = 1)

# Empleamos operador de subconjuntos, junto con la función names() y el
# operador de igualdad, para filtrar por caracteres
z[names(z) == "Ana"]
Ana Ana 
2.4 1.0 
# Empleamos operador de subconjuntos, junto con el operador de igualdad para
# filtrar por número
z[z == 2.4 | z == 1]
Ana Ana 
2.4 1.0

Matrices y arreglos

El caso de las matrices y arreglos, se tiene que la dimensión de los objetos pueden ser de 2d o más. Por ello podemos emplear el operador de subconjuntos [], separando por coma cada dimensión. Por ejemplo, dado que una matriz es de 2d, entonces podemos emplear el operador de subconjuntos, separando por una coma, [ , ], en donde, el valor antes de la coma indica lo valores de fila de interés, y los valores después de la coma indican los valores de columna de interés.

Similarmente, para el caso de los arreglos, el cual puede ser de más de 2d, entonces podemos emplear el operador de subconjuntos, separando por una coma cada dimensión adicional.

Matrices por entrada

Supongamos una matriz M de dimensión \(2\times3\) dada por

\[\begin{align*} M = \begin{bmatrix}6 & 2 & 3 \\12 & 7 & 9 \end{bmatrix}_{2\times3} \end{align*}\]

Entonces, si deseamos filtrar el valor \(9\) que se encuentra en la posición \(2,3\) (fila \(2\), columna \(3\)), podemos emplear el operador de subconjuntos con la notación \[\begin{align*} M[2,3] \end{align*}\] tal que

# Creamos la matriz
M <- matrix(c(6, 2, 3, 12, 7, 9), nrow = 2, ncol = 3, byrow = T)

# Empleamos operador de subconjuntos, para seleccionar valor 9 de la matriz
# M
M[2, 3]
[1] 9

Matrices por fila o columna

Ahora, si queremos seleccionar solo una fila o columna, entonces podemos emplear el operador de asignación, dejando vacío el valor antes de la coma, si deseamos filtrar por columna, o dejar vacío el valor después de la coma, si deseamos filtrar por fila. Por ejemplo, si queremos filtrar por la columna \(1\) de la matriz M, empleando la notación \[\begin{align*} M[\;,1] \end{align*}\] en donde se puede notar que no hay ningún valor asignado antes de la coma.

# Empleamos operador de subconjuntos, para seleccionar la columna número 1
# de la matriz M
M[, 1]
[1]  6 12

Arreglo por entrada

Funcionan similar a las matrices, pero con la diferencia de éstos pueden tener dimensiones extra. Por ello, es cuestión de agregar las nuevas dimensiones dentro del operador de subconjuntos, separando cada dimensión mediante comas. Por ejemplo se tiene un arreglo \(2\times2\times3\), formado por las tres matrices \(A_1, A_2, A_3\), \(2\times2\) siguientes \[\begin{align*} A_1 = \begin{bmatrix}6 & 2 \\7 & 9 \end{bmatrix}_{2\times2} \qquad A_2 = \begin{bmatrix}3 & 7 \\12 & 8 \end{bmatrix}_{2\times2} \qquad A_3 = \begin{bmatrix}13 & 2 \\3 & 11 \end{bmatrix}_{2\times2} \end{align*}\] Entonces, si deseamos filtrar el valor \(3\) que se encuentra en la posición \(2,1\) (fila \(2\), columna \(1\)) de la tercera matriz, podemos emplear el operador de subconjuntos con la notación \[\begin{align*} A[2,1,3] \end{align*}\] tal que

# Creamos las tres matrices
A1 <- matrix(c(6, 2, 7, 9), nrow = 2, ncol = 2, byrow = T)
A2 <- matrix(c(3, 7, 12, 8), nrow = 2, ncol = 2, byrow = T)
A3 <- matrix(c(13, 2, 3, 11), nrow = 2, ncol = 2, byrow = T)

# Creamos arreglo
A <- array(c(A1, A2, A3), dim = c(2, 2, 3))

# Empleamos operador de subconjuntos, para seleccionar valor 3 de la tercera
# matriz del arreglo A, que se encuentra en la posición 2,1.
A[2, 1, 3]
[1] 3

Arreglo por fila o columna

Ahora, si queremos seleccionar solo una fila o columna, entonces podemos emplear el operador de asignación, dejando vacíos los valores antes de la primera coma y después de la segunda, tercera…. coma (dependiendo de la dimensión del arreglo), si deseamos filtrar por columna, o dejar vacío los valores después la primera, segunda, tercera…. coma (dependiendo de la dimensión del arreglo), si deseamos filtrar por fila. Por ejemplo, si queremos filtrar por la fila \(2\) del arreglo A, podemos emplear la notación \[\begin{align*} A[2,\; ,\; ] \end{align*}\] en donde, solo se usan dos comas debido a que la dimensión del arreglo es de \(3d\).

# Empleamos operador de subconjuntos, para seleccionar la segunda fila de
# cada matriz dentro del arreglo A.
A[2, , ]
     [,1] [,2] [,3]
[1,]    7   12    3
[2,]    9    8   11

Arreglo por dimensiones superiores

Para filtrar por un dimensión superior a \(2d\), es necesario identificar el orden de interés del arreglo, y escribir el valor para la dimensión luego de la coma, asociada a la dimensión en la que se está interesado. Por ejemplo, \(A\) es un arreglo de \(2\times2\times3\), así que si estoy interesado solo en la segunda matriz, entonces puedo escribir un \(2\) luego de la segunda coma, ya que estoy interesado en la tercera dimensión del arreglo. Dicha notación sería \[\begin{align*} A[\;, \; ,2] \end{align*}\] en donde, se observa, que los valores asociados a las filas y las columnas se encuentra vacíos.

# Empleamos operador de subconjuntos, para seleccionar la segunda matriz
# dentro del arreglo A.
A[, , 2]
     [,1] [,2]
[1,]    3    7
[2,]   12    8

Marco de datos

Los marcos de datos poseen un comportamiento similar a los vectores con nombres o matrices, debido a que éstas pueden encontrarse en un conjunto de 1d (cuando posee un solo vector) o 2d (cuando hay dos o más vectores). Por tanto, para manipular los marcos de datos, podemos emplear el operador de subconjuntos [], separando por coma la las filas de las columnas.

Adicionalmente, los marcos de datos, poseen un operador de subconjuntos adicionales, el cual posee el símbolo $, el cual se emplea luego del nombre del dataframe y permite filtrar por el nombre de las columnas del marco de datos.

Marco de datos

Para ilustrar el modo de trabajar un marco de datos como un vector con nombres, supongamos la siguiente base de datos.

DatF <- data.frame(Num = 1:10, Car = letters[1:10], Log = c(rep(T, 3), rep(F, 
    3), rep(T, 4)))
DatF
   Num Car   Log
1    1   a  TRUE
2    2   b  TRUE
3    3   c  TRUE
4    4   d FALSE
5    5   e FALSE
6    6   f FALSE
7    7   g  TRUE
8    8   h  TRUE
9    9   i  TRUE
10  10   j  TRUE

Marco de datos como vectores con nombres

Entonces, suponga que deseamos filtrar columna “Car”, empleando la forma usada en vectores con nombres, podemos usar el operador de subconjuntos, para localizar la columna de interés, mediante la notación

\[\begin{align*} DatF[``Car"] \end{align*}\]

tal que

# Empleamos operador de subconjuntos [], como en el caso de vectores con
# nombres para seleccionar la columna con nombre 'Car'
DatF["Car"]
   Car
1    a
2    b
3    c
4    d
5    e
6    f
7    g
8    h
9    i
10   j

Alternativamente, podemos usar el operador de asignación $ luego del nombre del marco de datos, seguido del nombre de la variable de interés, en donde la notación usada sería de la forma

\[\begin{align*} DatF\$Car \end{align*}\]
# Empleamos operador de subconjuntos $, para seleccionar la columna con
# nombre 'Car'
DatF$Car
 [1] a b c d e f g h i j
Levels: a b c d e f g h i j

Puede apreciarse que el empleo de un método u el otro ofrece resultados diferentes, en donde al usar el primer método se conserva la clase “data.frame”, mientras que, con el segundo método se maneja la clase interna de la columna, que en este caso es tipo factor.

# Observamos la clase del os objetos
class(DatF["Car"])
[1] "data.frame"
class(DatF$Car)
[1] "factor"

Marco de datos como matriz

Si queremos mediante el operador de asignación empleado para matrices, \[ , \], entonces para filtrar por la columna “Car”, podemos emplear la siguiente notación

\[\begin{align*} DatF[\;,2] \quad \text{ ó } \quad DatF[\;,``Car"] \end{align*}\]

en donde, se emplea la segunda columna, ya que la variable “Car”, es la segunda columna del marco de datos.

# Empleamos operador de subconjuntos [], como en el caso de matrices para
# seleccionar la segunda columna 2
DatF[, 2]
 [1] a b c d e f g h i j
Levels: a b c d e f g h i j

De lo anterior, vemos que la salida obtenida, es similar a la obtenida cuando filtramos la columna mediante el operador de asignación $

# Observamos la clase del objeto
class(DatF[, 2])
[1] "factor"

Listas

Para el manejo de listas, es necesario manipular los operadores de asignación anteriormente presentados, debido a que en las listas es posible incluir cualquier tipo de objeto, y adicionalmente, hay que aprender a manipular el operador de subconjuntos [[]], el cual es parecido al operador [], pero con la diferencia de que [[]] extrae el objetos de las listas. Resultado similar puede ser obtenido con el operador de subconjuntos $

Listas

Supongamos que poseemos una lista, la cual contiene un vector con nombres, una matriz, un arreglo, un marco de datos y una función.

# Creamos un marco de datos con objetos creados previamente
Lista <- list(VC = z, MT = M, AR = A, DF = DatF, FU = function(x) class(x))
Lista
$VC
Daniel Carlos  Paola    Ana   Juan    Ana 
   4.0    8.0   12.4    2.4    8.0    1.0 

$MT
     [,1] [,2] [,3]
[1,]    6    2    3
[2,]   12    7    9

$AR
, , 1

     [,1] [,2]
[1,]    6    2
[2,]    7    9

, , 2

     [,1] [,2]
[1,]    3    7
[2,]   12    8

, , 3

     [,1] [,2]
[1,]   13    2
[2,]    3   11


$DF
   Num Car   Log
1    1   a  TRUE
2    2   b  TRUE
3    3   c  TRUE
4    4   d FALSE
5    5   e FALSE
6    6   f FALSE
7    7   g  TRUE
8    8   h  TRUE
9    9   i  TRUE
10  10   j  TRUE

$FU
function(x) class(x)
<environment: 0x000000001d9d5fb0>

Adicionalmente, supongamos que deseamos extraer la matriz que se encuentra dentro de lista. Dado que la matriz es el segundo objeto de la lista, podemos emplear tres alternativas. Usar la posición \(2\) debido a que es el segundo objeto de la lista, usar el nombre que posee dentro de la lista, o usar el operador $ seguido del nombre dentro de la lista \[\begin{align*} Lista[[2]] \quad \text{ ó } \quad Lista[[``MT"]] \quad \text{ ó } \quad Lista\$MT \end{align*}\] Estas tres formas funcionan exactamente igual, puesto que permiten extraen totalmente de la lista, el objeto de interés.

# Empleamos operador de subconjuntos [[]], para extraer el segundo objeto
# guardado en la lista
Lista[[2]]
     [,1] [,2] [,3]
[1,]    6    2    3
[2,]   12    7    9
# Observamos la clase del objeto resultante
class(Lista[[2]])
[1] "matrix"

Caso contrario ocurre cuando realizamos la extracción mediante el otro operador de subconjuntos, en donde se aprecia que el objeto sigue tendiendo la característica de lista.

# Empleamos operador de subconjuntos [], para extraer el segundo objeto
# guardado en la lista
Lista[2]
$MT
     [,1] [,2] [,3]
[1,]    6    2    3
[2,]   12    7    9
# Observamos la clase del objeto resultante
class(Lista[2])
[1] "list"

Una vez extraído el objeto de interés dentro de la lista, pueden emplearse las operaciones descritas previamente para vectores, matrices, etc, etc. Por ejemplo, tenemos la lista, deseamos extraer la segunda matriz del objeto AR, entonces podemos emplear la notación \[\begin{align*} Lista$AR[\;, \;, 2] \end{align*}\] tal que

# Empleamos operador de subconjuntos $, para extraer el arreglo AR guardado
# en la lista, y simultáneamente se extrae la segunda matriz del arreglo
Lista$AR[ , , 2]
     [,1] [,2]
[1,]    3    7
[2,]   12    8

En donde se aprecia, que el objeto AR es un arreglo, y en consecuencia, para extraer la segunda matriz, debe usarse el operador de asignación, con un \(2\) luego de la segunda coma, debido a que estamos interesados en la segunda matriz