Problema

Se requiere seleccionar algunos elementos de un vector de acuerdo con un patrón repetitivo. Como ejemplo, se quiere seleccionar el tercero y cuarto elementos de cada diez elementos en secuencia.

Para ilustrar el problema, supongamos que se tiene un vector que consiste en 55 numeros, empezando con el 101, como sigue:

(v <- 101:155)
##  [1] 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
## [18] 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
## [35] 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
## [52] 152 153 154 155

De ahí se quieren seleccionar, como se dijo, el tercer y cuarto elementos de cada diez elementos en la secuencia, de modo que se produzca una salida como la que se muestra a continuación:

##  [1] 103 104 113 114 123 124 133 134 143 144 153 154

Solución

En R, los vectores de lógicos se pueden utilizar para indexar otro vector, a manera de una máscara que prende o apaga los elementos del vector que se seleccionan a la salida. Así, por ejemplo, si queremos seleccionar los elementos impares en el vector v, se puede hacer como se muestra:

# Los elementos de v que no son divisibles por 2:
(ii <- v %% 2) # operación módulo
##  [1] 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
## [36] 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
# Convertimos ii a lógico
ii <- as.logical(ii)
# Y los impares son:
v[ii]
##  [1] 101 103 105 107 109 111 113 115 117 119 121 123 125 127 129 131 133
## [18] 135 137 139 141 143 145 147 149 151 153 155

Cuando el vector indexador de otro vector en R es lógico, y es de un tamaño menor al vector indexado, R lo recicla, o sea, repite la secuencia y esto es algo de lo que podemos sacar ventaja para resolver nuestro problema original; pero antes, veamos que la salida anterior, si, como es el caso, v es una secuencia de números enteros conocida, se puede producir de manera muy simple, como sigue:

v[c(TRUE, FALSE)]
##  [1] 101 103 105 107 109 111 113 115 117 119 121 123 125 127 129 131 133
## [18] 135 137 139 141 143 145 147 149 151 153 155

Si usamos este mismo comportamiento, podemos producir la máscara repetitiva del patrón, de la manera siguiente:

# Un vector lógico de 10 elementos inicializados como FALSE
ii <- logical(10)
# "Prendemos" los elementos 3 y 4 de la máscara
ii[c(3,4)] <- TRUE
# La "máscara"" es:
ii
##  [1] FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE

Ahora, simplemente se usa esa máscara como un índice del vector original v:

v[ii]
##  [1] 103 104 113 114 123 124 133 134 143 144 153 154

Y el problema ha quedado resuelto!

Notemos que no hay restricción en la clase de elementos de vector que se indexa. Hagamos, por ejemplo, un vector de 55 letras seleccionadas aleatoreamente:

(aa <- sample(letters, 55, replace=TRUE))
##  [1] "t" "u" "g" "v" "k" "f" "h" "d" "t" "s" "d" "u" "d" "s" "p" "y" "g"
## [18] "q" "c" "l" "q" "f" "a" "k" "s" "j" "y" "m" "v" "n" "e" "h" "l" "f"
## [35] "v" "i" "l" "j" "z" "t" "c" "r" "s" "s" "s" "g" "h" "y" "c" "x" "l"
## [52] "d" "e" "a" "w"

Seleccionemos de ese vector, igual, el tercero y cuarto elementos de cada diez; para ello, podemos utilizar la misma máscara generada previamente (ii):

aa[ii]
##  [1] "g" "v" "d" "s" "a" "k" "l" "f" "s" "s" "e" "a"