Vectores

Como ya hemos comentado anteriormente en R podemos realizar agrupaciones de datos. En concreto, tenemos los vectores, una secuencia ordenada de datos que comparten el mismo tipo. En este capítulo aprenderemos a construirlos y a usarlos. Este conocimiento nos permitirá usar estructuras más avanzadas:

Creación

La sintaxis para crear un vector con una colección de números emplea la función c (concantenar), por ejemplo para crear un vector que contenga los siguientes números en este orden 5,4,2,5,3,7,2,8 es la siguiente:

> x=c(5, 4, 2, 5, 3, 7, 2, 8)
> x
[1] 5,4,2,5,3,7,2,8

Podemos crear vectores de cualquier tipo de datos básico, por ejemplo, podemos crear un vector de strings de la siguiente manera:

> strs = c("Palma", "Inca", "Manacor", "Alcudia", "Sineu")
> strs
[1] "Palma" "Inca" "Manacor" "Alcudia" "Sineu"

NOTA: Debemos fijarnos en que la diferencia entre declarar una variable y un string es el uso del las dobles comillas ".

Si intentamos crear un vector con datos de diferentes tipos, R automáticamente los convertirá a un tipo que pueda ser común a todos ellos. El orden de conversión entre los tipos es el siguiente: character > complex > numeric > integer > logical. Así, cuando algún elemento de un vector es de tipo strings, R considera el resto de sus elementos son strings.

La función c que hemos usado para crear vectores en realidad concatena sus argumentos en un vector. Si la aplicamos a vectores, esta construye un nuevo vector concatenando sus elementos. Podemos mezclar vectores y datos en su argumento:

> v = c(1, 2, 3, 4)
> v2 = c(5, 6, 7)
> v3 = c(v, v2, 8, 9)
> v3
[1] 1 2 3 4 5 6 7 8 9

Cargar datos de un fichero

El uso habitual de los vectores implica el manejo de colecciones de datos las cuales no nos interesará introducir a mano, sino que las tendremos guardados en algún archivo en nuestro ordenador o estará disponible en internet. La función scan se puede usar para copiar en un vector el contenido de un fichero de texto situado en el directorio de trabajo, o del que conozcamos su dirección en Internet. La manera de hacerlo es aplicando scan al nombre del fichero o a su url, escritos entre comillas.

Vamos a leer un fichero que se encuentra en internet y que contiene la temperatura media de cada mes en Mallorca durante el año 2021:

temperatura = scan("https://raw.githubusercontent.com/bmalcover/TxADM/main/notebooks/Part1/01_R/data/info.txt")

Creación de vectores con patrones

R permite crear vectores de manera dinámica usando diferentes funciones:

La función rep

Para definir un vector constante podemos usar la función rep(a, b), que genera un vector que contiene el valor a repetido b veces:

> rep(33, 5)
[1] 33 33 33 33 33
> rep("Palma", 5)
[1] "Palma" "Palma" "Palma" "Palma" "Palma"

Esta función también nos permite repetir vectores. En concreto tiene dos modos de repetición, para especificar el tipo de repetición tenemos que usar el parámetro adecuado en el argumento de rep: si usamos el parámetro times, repetiremos el vector en bloque, y si, en cambio, usamos el parámetro each repetiremos cada valor del vector de manera independiente.

Veamos un ejemplo de uso para entender mejor su funcionamiento:

> rep(c(1, 2, 3, 4), times=5)
[1] 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
> rep(c(1, 2, 3, 4), each=5)
[1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4

La función seq

Las progresiones aritméticas se pueden especificar de manera compacta usando la función seq. Una primera manera de hacerlo es mediante la instrucción seq(a, b, by=p), que especifica la progresión aritmética de paso p que empieza en a: a, a + p, a + 2p, . . . , hasta llegar a b.

La instrucción seq con paso ±1 se puede abreviar con el símbolo :. La instrucción a:b define la secuencia de números consecutivos entre dos números a y b, es decir, la secuencia a, a + 1, a + 2, . . . hasta llegar a b.

> my_vector = 5:10
> my_vector
[1]  5  6  7  8  9 10
> d_vector = 20:10
> d_vector
 [1] 20 19 18 17 16 15 14 13 12 11 10

La función seq sirve para definir progresiones aritméticas de otros dos tipos:

  • seq(a, b, length.out=n): define la progresión aritmética de longitud n que va de a a b, por lo tanto, p = (b a)/(n 1).

  • seq(a, by=p, length.out=n): define la progresión aritmética a, a + p, a + 2p, . . . , a + (n 1)p de longitud n y paso p que empieza en a.

Operaciones

Usar vectores con R tiene una propiedad muy útil: podemos aplicar una función a todos los miembros de un vector en un solo paso. Básicamente, podemos aplicar a un vector cualquier operación que se pueda usar en los elementos individuales de este.

> x=seq (2, 30, by=3)
> x
[1] 2 5 8 11 14 17 20 23 26 29
> x + 2.5
[1] 4.5 7.5 10.5 13.5 16.5 19.5 22.5 25.5 28.5 31.5

Además, R dispone de muchas funciones para aplicar a vectores, relacionadas principalmente con la estadística. Veamos algunas que nos pueden ser útiles por el momento, y ya iremos viendo otras a medida que avance el curso:

  • length: calcula la longitud del vector.

  • max y min: calculan sus valores máximo y mínimo, respectivamente.

  • sum: calcula la suma de sus entradas.

  • prod: calcula el producto de sus entradas.

  • mean: calcula la media aritmética de sus entradas.

  • diff: calcula el vector formado por las diferencias sucesivas entre entradas del vector original.

  • cumsum: calcula el vector formado por las sumas acumuladas de las entradas del vector original: cada entrada de cumsum(x) es la suma de las entradas de x hasta su posición.

  • sort: ordena el vector en el orden natural de los objetos que lo forman: el orden numérico creciente, el orden alfabético, etc. Si lo queremos ordenar en orden decreciente, podemos incluir en su argumento el parámetro dec=TRUE que invierte el orden de los elementos del vector.

  • unique: devuelve el vector sin elementos repetidos.

Aplicando funciones propias

La función sapply(vector, FUN=función) aplica la función FUN a todas las entradas del vector sin tener que usar estructuras repetitivas como bucles.

vector_strings <- c("Hola", "Mundo", "en", "R")

# Definir una función personalizada para convertir a mayúsculas
to_mayus <- function(cadena) {
  return(toupper(cadena))
}

# Usar sapply() para aplicar la función personalizada
mayusculas <- sapply(vector_strings, to_mayus)

Selección de elementos

Se puede acceder a elementos individuales de un vector especificando su posición, también llamada índice, entre corchetes.

> x = seq(2, 50, by=1.5)
> x [3] # La tercera entrada del vector
[1] 5
> x [length(x)] # La última entrada del vector
[1] 50
> x [length(x)-5] # La sexta entrada del vector empezando por el final
[1] 42.5

También podemos obtener partes de un vector. Una primera manera de obtener una parte de un vector es especificando los índices de las entradas que lo han de formar:

  • vector[y]: donde vector e y son vectores, crea un nuevo vector con las entradas del vector original cuyos índices pertenecen a y.

  • vector[a:b]: si a y b son dos números naturales, crea un nuevo vector con las entradas del vector original que van del índice a-ésimo a la b-ésimo.

  • vector[-y], donde y es un vector (de índices), obtendremos el complementario de vector[y] sus entradas son las del vector original cuyos índices no pertenecen a y.

  • vector[-i] borra la entrada i-ésima del vector original.

Modificación de los elementos de un vector

Podemos modificar una o varias posiciones de un vector usando el operador de asignación (=) y la operación de selección de elementos.

> x = 1:10
> x[3] = 15 # En la posición 3 escribimos 15
> x[11] = 25 # Hacemos crecer el vector, añadimos un 25 a la posición 11
> x
[1] 1 2 15 4 5 6 7 8 9 10 25
> x[c(2,3,4)] = x[c(2,3,4)] + 10 # Sumamos 10 a las posiciones en las posiciones 2 , 3 y 4
> x
[1] 1 12 25 14 5 6 7 8 9 10 25
> x[(length(x)-2):length(x)] = 0 # Igualamos las últimas tres posiciones a 0

Selección lógica

También podemos extraer las entradas de un vector (o sus índices) que satisfagan alguna condición. Para ello podemos usar los siguientes operadores:

Operador

Símbolo

Igual

=

Diferente

!=

Mayor

>

Menor

<

Mayor o igual

>=

Menor o igual

<=

Negación lógica

!

Y lógica

&

O lógica

|

> x=c(1, 5, 6, 2, 5, 7 , 8, 3, 5, 2, 1, 0)
> x[x > 3] # Elementos mayores que 3
[1] 5 6 5 7 8 5
> x[x > 2 & x <= 5] # Elementos mayores que 2 y menores o iguales que 5
[1] 5 5 3 5
> x[x != 2 & x != 5] # Elementos diferentes de 2 y de 5
[1] 1 6 7 8 3 1 0
> x[x > 5 | x <= 2] # Elementos mayores que 5 o menores o iguales que 2
[1] 1 6 2 7 8 2 1 0
> x[x >= 4] # Elementos mayores o iguales que 4
[1] 5 6 5 7 8 5
> x[!x < 4] # Esta condición es equivalente a la anterior
[1] 5 6 5 7 8 5
> x[x %% 4 == 0] # Elementos múltiplos de 4
[1] 8 0

Esta construcción también permite extraer los valores de un vector cuyos índices sean los de las entradas de otro vector que satisfagan una condición lógica. Por ejemplo:

x = c (1, 5, 6, 2, 5, 7, 8, 3, 5, 2, 1, 0)
> y = c (2, -3 ,0 ,1 ,2, -1, 4, -1, -2, 3, 5, 1)
> x [y > 0] # Entradas de x correspondientes a entradas positivas de y
[1] 1 2 5 8 2 1 0

La función which

Para obtener los índices de las entradas del vector que satisfacen una condición dada, podemos usar la función which. En realidad, esta función, aplicada a un vector de valores lógicos, proporciona los índices de las posiciones que contienen un valor TRUE. Así, para saber los índices de las entradas de x que son mayores que 3, usaremos which(x>3), ya que la función which nos dará los índices de las entradas TRUE del vector x>3.

> x = c(1, 5, 6, 2, 5, 7, 8, 3, 5, 2, 1)
> x
[1] 1 5 6 2 5 7 8 3 5 2 1
> x [x > 3] # Elementos mayores que 3
[1] 5 6 5 7 8 5
> which(x > 3) # Índices de los elementos mayores que 3
[1] 2 3 5 6 7 9
> which(x > 2 & x <= 5) # Índices de los elementos > 2 y <= 5
[1] 2 5 8 9
> which( x != 2 & x != 5) # Índices de los elementos diferentes de 2 y 5
[1] 1 3 6 7 8 11
> which(x > 5 | x <= 2) # Índices de los elementos > 5 o <= 2
[1] 1 3 4 6 7 10 11
> which(x%%2b == 0) # Índices de los elementos pares del vector
[1] 3 4 7 10

Las instrucciones which.min(x) y which.max(x) nos dan la primera posición en la que el vector toma su valor mínimo o máximo, respectivamente.

NA (Not Available)

Si realizamos la siguiente operación:

> x =1:10
> x [length(x)+3]=2
> x
[1] 1 2 3 4 5 6 7 8 9 10 NA NA 2

Podemos observar que en las posiciones 12 y 13 ha escrito NA antes de añadir en la posición 14 el número 2. Estos NA, indican que las entradas correspondientes del vector no existen, no tienen ningún valor.

Los valores NA serán muy importantes cuando usemos vectores en estadística descriptiva, donde podrán representar valores que no conocemos, medidas que han dado error, etc. Serán importantes porque son molestos, puesto que, por norma general, una función aplicada a un vector que contenga algún NA da como resultado NA.

Veamos un ejemplo:

> x
[1] 1 2 3 4 5 6 7 8 9 10  NA NA 2
> sum(x)
[1] NA

Afortunadamente, muchas de las funciones para vectores admiten un parámetro na.rm al que si le asignamos el valor TRUE, provoca que la función solo tenga en cuenta las entradas definidas.

> sum (x , na.rm=TRUE)
[1] 80
> mean (x , na.rm=TRUE)
[1] 6.666667

Para obtener los valores no definidos (NA) del vector x no podemos usar la condición lógica x==NA, sino que debemos usar la función is.na(x).

Ejercicios con vectores

  1. Cargar los datos contenidos en crimenUSA.txt. Que se encuentra en el siguiente enlace

  2. ¿Cuántos valores tiene? Muestra por pantalla los 5 primeros. Ahora muestra los 5 últimos.

  3. ¿Cuál es el valor medio de este vector? ¿Y su desviación estándar? 4.¿Cuál es el máximo valor en estos datos? ¿Se repite alguna vez? ¿Cuántas?

  4. ¿Qué porcentaje de estados tienen más de 4810 crímenes?

  5. Ejecuta la sentencia que tienes a continuación, esta descargará un vector con los nombres de los estados de USA en la variable states. Verifica que se ha cargado correctamente mostrando su contenido en la consola.

    states = scan("https://iamattila.com/wp-content/uploads/2021/07/usa-state-codes-abbreviations-names.csv", what=character(), sep="\n", skip = 1)
    
  6. Crea un nuevo vector que contenga los nombres de los estados con más crímenes que la media. Muéstralo en la consola.

  7. ¿Cuál es el estado con menor criminalidad?

  8. Da el valor de \(n\) en el que la secuencia \((2*3^n−4*2.5n)\) \(n=0,…,100\) toma su valor mínimo.

  9. Haz un programa que diga SI o NO, si la secuencia \((4^n−3*2^n)\) \(n=0,…,200\) es creciente o no.

Factores

En R, los factores se utilizan para trabajar con variables categóricas, variables que tienen un conjunto fijo y conocido de valores posibles. Pueden almacenar tanto strings como valores enteros. Son útiles en el análisis de datos para el modelado estadístico. Los factores se crean mediante la función factor y reciben un vector como parámetro. Los factores nos serán muy útiles cuando tengamos conjuntos de datos con varias características.

Veamos un ejemplo:

> datos <- c("East","West","East","North","North","East","West","West","West","East","North") # Creamos un vector
> factor_data <- factor(datos) # Lo transformamos en un factor
> print(factor_data) # Vemos su estructura
 [1] East  West  East  North North East  West  West  West  East  North
Levels: East North West

Vemos que la estructura factor_data tiene el atributo Levels además de la información del vector, en el futuro esto nos posibilitará hacer análisis categóricos.

Para crear un factor, hemos de definir un vector y transformarlo en factor por medio de una de las funciones factor o as.factor. La diferencia entre estas funciones es que as.factor convierte el vector en un factor, y toma como sus niveles los diferentes valores que aparecen en el vector, mientras que factor define un factor a partir del vector, y dispone de algunos parámetros que permiten modificar el factor que se crea, tales como:

  • levels: que permite especificar los niveles e incluso añadir niveles que no aparecen en el vector.

  • labels: que permite cambiar los nombres de los niveles.

De esta manera, con as.factor o con factor sin especificar levels, el factor tendrá como niveles los diferentes valores que toman las entradas del vector, y además aparecerán en su lista de niveles, Levels, ordenados en orden alfabético. Si especificamos el parámetro levels en la función factor, los niveles aparecerán en dicha lista en el orden en el que los entremos en él:

S=c("M","M","F","M","F","F","F","M","M","F")

Sex= factor(S, levels=c("M","F","I"), labels=c("Masc.","Fem.","Indet."))
Sex
#>  [1] Masc. Masc. Fem.  Masc. Fem.  Fem.  Fem.  Masc. Masc. Fem.
#> Levels: Masc. Fem. Indet
  1. Realizad una instrucción que defina un factor llamado F01 a partir del vector c(0, 1, 0, 0, 1, 0), asignando al 0 y al 1 los niveles No y Yes, respectivamente.