Capítulo 6 Vectores

Hemos visto como poder almacenar elementos individuales: la edad de una persona, su estado civil con una variable lógica, su nombre, su fecha de nacimiento… ¿Y si en lugar de querer almacenar un solo elemento, por ejemplo edad <- 32, tenemos una colección de elementos (las edades de toda nuestra familia, por ejemplo)?

En este capítulo vamos a ver un clásico de cualquier lenguaje de programación: los vectores o arrays, que no son más que una concatenación de elementos del mismo tipo. De hecho un número individual (por ejemplo, x <- 1) es en realidad un vector de longitud uno (un solo elemento).

Un vector es lo que solemos representar como \(\overrightarrow{x} = \left[1, 2, 3 \right]\) en matemáticas, pero no te preocupes si nunca has visto esta forma de representarlos. Vamos a empezar de cero.

6.1 Vectores numéricos

La forma más sencilla de crear un vector en R es con el comando c() (de concatenar elementos), y basta con introducir sus elementos entre paréntesis, y separados por comas. Voy a crear el vector con las 4 edades de los miembros de mi familia.

edades <- c(32, 27, 60, 61)
edades
## [1] 32 27 60 61

Como ves ahora en el environment (entorno, arriba a la derecha) tenemos una colección de elementos guardada, con cuatro en concreto, guardados en una misma variable edades.

Vector en el enviroment

Imagen/gráfica 6.1: Vector en el enviroment

La longitud de un vector se puede calcular con el comando length() (nos devolverá el número de elementos de la variable que le pasemos como argumento).

length(edades)
## [1] 4

Además podemos concatenar a su vez vectores (uno tras otro): vamos a concatenar el vector edades consigo mismo, y añadiéndole al final un 8.

c(edades, edades, 8)
## [1] 32 27 60 61 32 27 60 61  8

Esta última concatenación lo que nos ha dado son, primero, los cuatro elementos que ya teníamos en edades, después de nuevo los cuatro elementos, y por último un 8.

6.2 Secuencias numéricas con un patrón

Muchas veces nos gustaría crear vectores de una forma mucho más rápida. Supongamos que queremos un vector de identificadores de números, desde el 1 hasta el 21. Si construyéramos el vector como antes, tendríamos que ejecutar el comando c(1, 2, 3, 4, 5, ...) hasta llegar al número 21. ¿Un poco largo, no?

Hay un atajo: el comando seq() nos permite crear una secuencia desde un elemento inicial hasta un elemento final, avanzando de uno en uno.

seq(1, 21) # secuencia desde 1 hasta 21 de uno en uno
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21

Es importante que no perdamos el foco: programar es similar a escribir en un idioma, por lo que si hay algo que se puede decir de una forma más limpia y que se entienda mejor, ¿por qué no usarlo? Siempre que queramos definir secuencias entre dos números naturales (por ejemplo, entre 1 y un valor n), cuya distancia entre elementos consecutivos sea uno, el comando 1:n nos devuelve lo mismo que la orden seq(1, n). Además, si el elemento inicial es mayor que el final, R entenderá solo que la secuencia la queremos decreciente.

n <- 21
1:n # secuencia desde 1 hasta n (21) de uno en uno
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21
n:1 # secuencia decreciente
##  [1] 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1

 

También podemos definir otro tipo de distancia entre dos elementos consecutivos (distancia conocida como paso de discretización), por ejemplo de 0.5 en 0.5, o de 1.7 en 1.7

seq(1, 10, by = 0.5) # secuencia desde 1 a 10 de 0.5 en 0.5
##  [1]  1.0  1.5  2.0  2.5  3.0  3.5  4.0  4.5  5.0  5.5  6.0  6.5  7.0  7.5  8.0
## [16]  8.5  9.0  9.5 10.0
seq(1, 21, by = 1.7) # secuencia desde 1 a 21 de 1.7 en 1.7
##  [1]  1.0  2.7  4.4  6.1  7.8  9.5 11.2 12.9 14.6 16.3 18.0 19.7

Otras veces nos interesará definir una secuencia entre un valor inicial y un valor final, pero nos dará igual la distancia entre cada elemento: solo nos importa que tenga un número concreto de elementos (y que sea R el que decida la distancia entre elementos consecutivos para conseguirlo).

seq(1, 50, l = 11) # secuencia desde 1 a 50 de longitud 11
##  [1]  1.0  5.9 10.8 15.7 20.6 25.5 30.4 35.3 40.2 45.1 50.0
seq(1, 50, l = 8) # secuencia desde 1 a 50 de longitud 8
## [1]  1  8 15 22 29 36 43 50

 

Otro atajo que podemos usar para definir secuencias de números con un patrón es definir vectores de elementos repetidos, por ejemplo un vector lleno de ceros. La función rep() nos permite repetir un elemento un número fijado de veces.

rep(0, 7) # vector de 7 ceros
## [1] 0 0 0 0 0 0 0

No solo podemos repetir un número sino que podemos repetir vectores enteros.

rep(c(0, 1, 2), 4) # repetimos el vector c(0, 1, 2) 4 veces
##  [1] 0 1 2 0 1 2 0 1 2 0 1 2

Esa repetición además podemos definirla también de forma intercalada: en lugar de repetir c(0, 1, 2) cuatro veces seguidas, queremos cuatro 0, después cuatro 1, y después cuatro 2.

rep(c(0, 1, 2), each = 4) # cuatro 0, luego cuatro 1, luego cuatro 2
##  [1] 0 0 0 0 1 1 1 1 2 2 2 2

6.3 Vectores de caracteres (texto)

Un error común es asociar el concepto de vectores solo a números: un vector es una colección o concatenación de elementos del mismo tipo pero no tienen porque ser necesariamente números. Vamos a crear una frase de ejemplo, un vector de 4 elementos de tipo texto (en R se llaman char): "Mi", "nombre", "es" "Javier".

Como antes, las variables de tipo char o character van entre comillas dobles, ya que es un cadena de texto.

mi_nombre <- c("Mi", "nombre", "es", "Javier")
mi_nombre
## [1] "Mi"     "nombre" "es"     "Javier"

Ya tenemos nuestro primer vector de texto de longitud 4. Cuando usamos la función paste() con variables diferentes, usábamos sep = ... para decidir el caracter con el que pegamos dichas cadenas texto. Cuando la función paste() la aplicamos a un vector de caracteres, decidiremos que caracter queremos que vaya entre palabra con el argumento collapse =.

paste(mi_nombre, collapse = "") # todo junto
## [1] "MinombreesJavier"
paste(mi_nombre, collapse = " ") # separados por un espacio
## [1] "Mi nombre es Javier"
paste(mi_nombre, collapse = ".") # separados por un punto .
## [1] "Mi.nombre.es.Javier"
paste0(mi_nombre) # todo junto sin nada separando
## [1] "Mi"     "nombre" "es"     "Javier"

Ahora que sabemos lo que es un vector de números, por ejemplo el vector 1:7 (el conjunto de naturales desde el 1 hasta el 7), podemos definir cadenas de texto que compartan por ejemplo un prefijo (persona_1, persona_2, …)

paste0("persona", 1:7) # a la palabra «persona» le pegamos los números del 1 al 7
## [1] "persona1" "persona2" "persona3" "persona4" "persona5" "persona6" "persona7"
paste("persona", 1:7, sep = "_") # separado por una barra baja
## [1] "persona_1" "persona_2" "persona_3" "persona_4" "persona_5" "persona_6"
## [7] "persona_7"

De igual manera podemos hacer uso del ya conocido paquete glue, combinando cadenas de texto y vectores numéricos, obteniendo vectores de frases.

library(glue)
edad <- 10:13 # edades
glue("La edad es de {edad} años")
## La edad es de 10 años
## La edad es de 11 años
## La edad es de 12 años
## La edad es de 13 años
# Otra forma sin definir variables a priori
glue("La edad es de {10:13} años")
## La edad es de 10 años
## La edad es de 11 años
## La edad es de 12 años
## La edad es de 13 años

¿Y si queremos pasar todo a mayúscula o todo a minúscula? ¿Y si queremos sustituir un caracter (por ejemplo, .) por otro en todos los elementos?

R también nos proporciona algunas funciones muy sencillas (del paquete {base}) de usar para dichas tareas. Aquí un ejemplo de algunas de ellas.

texto <- c("Hola.", "qué", "ase?", "todo", "bien.", "y yo",
           "que", "ME", "ALEGRO")
toupper(texto) # todo a mayúscula
## [1] "HOLA."  "QUÉ"    "ASE?"   "TODO"   "BIEN."  "Y YO"   "QUE"    "ME"    
## [9] "ALEGRO"
tolower(texto) # todo a minúscula
## [1] "hola."  "qué"    "ase?"   "todo"   "bien."  "y yo"   "que"    "me"    
## [9] "alegro"

El paquete {base} también nos permite buscar y reemplazar patrones concretos en cadenas de texto (por ejemplo, sustituir toda letra «o» por el caracter «*»), con la función gsub().

gsub("o", "*", texto) # toda "o" en el texto será sustituida por *
## [1] "H*la."  "qué"    "ase?"   "t*d*"   "bien."  "y y*"   "que"    "ME"    
## [9] "ALEGRO"

 

6.4 Vectores lógicos (TRUE/FALSE)

Antes hemos comentado que las variables lógicas suelen aparecer como resultado de comparaciones de elementos. Por ejemplo, imaginemos ahora que definimos un vector de números x <- c(1.5, -1, 2, 4, 3, -4). ¿Qué numeros de x son menores que 2? Basta con que ejecutemos la orden x < 2, que nos devolverá TRUE/FALSE en cada hueco, en función de si cumple (TRUE) o no (FALSE) la condición pedida.

x <- c(1.5, -1, 2, 4, 3, -4)
x < 2
## [1]  TRUE  TRUE FALSE FALSE FALSE  TRUE

El primer, segundo y sexto elemento del vector son los únicos elementos (estrictamente) menores que 2, de ahí que en el primer, segundo y sexto elemento aparezca un TRUE y en el resto un FALSE. Es importante recordar que al evaluar una condición lógica sobre un vector de longitud n, la salida sigue siendo un vector de longitud n pero con valores lógicos.

Dicha condición lógica puede hacerse con otros operadores como <=, > o >=.

x <= 2
## [1]  TRUE  TRUE  TRUE FALSE FALSE  TRUE
x > 2
## [1] FALSE FALSE FALSE  TRUE  TRUE FALSE
x >= 2
## [1] FALSE FALSE  TRUE  TRUE  TRUE FALSE
x == 2
## [1] FALSE FALSE  TRUE FALSE FALSE FALSE
x != 2
## [1]  TRUE  TRUE FALSE  TRUE  TRUE  TRUE

 

Al igual que antes, las condiciones pueden ser combinadas. Por ejemplo, vamos a calcular qué elementos del vector c(1.5, -1, 2, 4, 3, -4) sean menores que 3 y además mayores que 0.

x <- c(1.5, -1, 2, 4, 3, -4)
x < 3 & x > 0 # Solo los que cumplen ambas condiciones
## [1]  TRUE FALSE  TRUE FALSE FALSE FALSE

De la misma manera podemos comprobar los elementos menores que 2 o mayores que 3 (basta con se que cumple alguna de las condiciones)

x < 2 | x > 3 # Los cumplen al menos una de ellas
## [1]  TRUE  TRUE FALSE  TRUE FALSE  TRUE

6.5 Datos ausentes: NA y NaN

La vida no siempre es perfecta así que en muchas ocasiones nos encontraremos con lo que llamamos en estadística un dato ausente o missing value, un valor que no tenemos en nuestra variable, y un ejemplo práctico lo tenemos con los datos de vacunación de covid del Ministerio de Sanidad. Cada día se publicaba un PDF con los datos de vacunación PERO…no se publicabann datos los fines de semana: en dichas fechas hay datos que no tenemos, y en R se representan por NA (significa not available).

6.5.1 NA: not available

Vamos a crear un vector de números con datos ausentes con la orden x <- c(1, NA, 3, NA, NA, 5, 6): el vector tendrá longitud 7 pero en el segundo, cuarto y quinto elemento tendremos datos faltantes, un lugar que no tenemos relleno (pero que no eliminamos).

x <- c(1, NA, 3, NA, NA, 5, 6) # Vector numérico con datos faltante
length(x) # longitud del vector
## [1] 7
x
## [1]  1 NA  3 NA NA  5  6

¿Puedes aventurar qué sucede cuando multiplicamos ese vector por una constante (por 2, por ejemplo)?

2 * x # operación aritmética con un vector con NA
## [1]  2 NA  6 NA NA 10 12

Un dato que no tenemos, multiplicado por 2, sigue siendo un dato ausente. Es muy importante para evitar resultados erróneos que entendamos que un dato ausente no computa en una operación aritmética, es un hueco vacío. Si hacemos la suma del vector, estamos sumando números más datos ausentes, por lo que el resultado final será también un dato ausente. Si tenemos algún dato ausente en nuestro vector, la suma final está a su vez ausente, ¡no podemos saber cuánto vale!

1 + NA + 3
## [1] NA

 

Una manera de localizar que elementos están ausentes en nuestrps vectores es con la función is.na(), una función que nos devuelve un vector de valores lógico: TRUE si el elemento está ausente y FALSE si no lo está.

is.na(x) # TRUE si está ausente (NA), FALSE si no lo está.
## [1] FALSE  TRUE FALSE  TRUE  TRUE FALSE FALSE

Dichos datos ausentes se pueden eliminar con la función na.omit() (aunque a veces lo que nos interesa es que no sea ausente, introduciendo el punto medio entre su valor anterior y su valor posterior, por ejemplo).

## [1] 1 3 5 6
## attr(,"na.action")
## [1] 2 4 5
## attr(,"class")
## [1] "omit"

6.5.2 NaN: not a number

Hay un tipo de dato, como resultado de operaciones no permitidas o cuyo resultado es indeterminado, que en R lo veremos como NaN: not a number, un resultado fruto de una indeterminación, como por ejemplo la operación 0/0 (cuyo límite no está definido). Importante saber que también existe una forma de denotar al infinito como Inf, siendo el resultado de algunas operaciones como 1/0.

1/0
## [1] Inf
0/0
## [1] NaN

De la misma manera que podemos localizar valores NA, tenemos a nuestra disposición las funciones is.infinte() y is.nan() para detectar que elementos de nuestro vector son Inf o NaN, respectivamente.

x <- c(1, NA, 3, 4, Inf, 6, 7, Inf, NaN, NA)
is.na(x)
##  [1] FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE
##  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE
##  [1] FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE

6.6 Consejos

CONSEJOS

 

Expresiones regulares

Dentro del entorno de paquetes tidyverse, el paquete stringr permite un manejo más complejo de cadenas de texo (como el uso de expresiones regulares).

Paquete stringr para manejar cadenas de texto más complejas

Imagen/gráfica 6.2: Paquete stringr para manejar cadenas de texto más complejas

 

6.7 📝 Ejercicios

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: modifica el código para crear un vector de nombre vector_num que contenga los números 1, 5 y -7.

# Vector de números
vector_num <- c(1)
vector_num

  • Solución:
# Vector de números
vector_num <- c(1, 5, -7)
vector_num
## [1]  1  5 -7

 

📝Ejercicio 2: define un vector que contenga los números 1, 10, -1 y 2, y guárdalo en una variable llamada vector_num.

  • Solución:
# Vector de números
vector_num <- c(1, 10, -1, 2)
vector_num
## [1]  1 10 -1  2

 

📝Ejercicio 3: obtén la longitud del vector anterior vector_num.

  • Solución:
# Longitud del vector
length(vector_num)
## [1] 4

 

📝Ejercicio 4: crea un vector con las palabras “Hola”, “me”, “llamo” (y tu nombre y apellidos), y pega luego sus elementos de forma que la frase esté correctamente escrita en castellano. Tras hacerlo, añade “y tengo 30 años”.

  • Solución:
# Definiendo el vector
vector_char <- c("Hola", "me", "llamo", "Javier",
                 "Álvarez", "Liébana")

# Pegamos
frase <- paste(vector_char, collapse = " ")
frase
## [1] "Hola me llamo Javier Álvarez Liébana"
# Añadimos frase
glue("{frase} y tengo 30 años.")
## Hola me llamo Javier Álvarez Liébana y tengo 30 años.
# Otra forma
paste0(frase, " y tengo 30 años.")
## [1] "Hola me llamo Javier Álvarez Liébana y tengo 30 años."
# Otra forma
paste(frase, "y tengo 30 años.")
## [1] "Hola me llamo Javier Álvarez Liébana y tengo 30 años."

 

📝Ejercicio 5: el código inferior crea una secuencia de números, que empieza en -1, que acaba en 32, y que va saltando de 2 en 2. Modíficalo para que haga el salto de 3 en 3 y guárdalo en una variable llamada secuencia

seq(-1, 32, by = 2)

  • Solución:
secuencia <- seq(-1, 32, by = 3)
secuencia
##  [1] -1  2  5  8 11 14 17 20 23 26 29 32
length(secuencia) # longitud de la secuencia
## [1] 12

 

📝Ejercicio 6: crea una secuencia de números, que empiece en -1, que acabe en 32, y que tenga longitud 12.

  • Solución:
secuencia <- seq(-1, 32, l = 12)
secuencia
##  [1] -1  2  5  8 11 14 17 20 23 26 29 32
length(secuencia) # longitud de la secuencia
## [1] 12

 

📝Ejercicio 7: crea una secuencia que empiece en 1 y recorra todos los naturales hasta el 10. Después crea otra secuencia de longitud 7 que todos los números sean 3.

  • Solución:
1:10
##  [1]  1  2  3  4  5  6  7  8  9 10
rep(3, 7) # secuencia repetida
## [1] 3 3 3 3 3 3 3

 

📝Ejercicio 8: crea una secuencia que repita 5 veces el patrón 1, 2, 3. Después crea otra que repita dicho patrón pero de forma intercalada, con 5 veces 1, después 5 veces 2 y después 5 veces 3.

  • Solución:
rep(c(1, 2, 3), 5) # repetimos patrón (1, 2, 3) 5 veces
##  [1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
rep(c(1, 2, 3), each = 5) # repetimos patrón alternado
##  [1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3

 

📝Ejercicio 9: crea un vector con las edades de cuatro conocidos o familiares. Tras ello, determina cuáles de ellos tienen menos de 20 años, 30 años o más, menos de 40 años y más de 65 años.

  • Solución:
edades <- c(27, 32, 60, 61) # en mi caso, por ejemplo
edades < 20 # menos de 20 años
## [1] FALSE FALSE FALSE FALSE
edades >= 30 # 30 años o más
## [1] FALSE  TRUE  TRUE  TRUE
edades < 40 # menos de 40 años
## [1]  TRUE  TRUE FALSE FALSE
edades > 65 # más de 65 años
## [1] FALSE FALSE FALSE FALSE