Tema 5 Tipos de datos: cadenas de caracteres, vectores y factores

En este tema y el siguiente se estudian los principales tipos de datos de R. Todo dato tiene que tener asociado un tipo. Según el tipo del dato se utilizará una determinada representación para almacenar el dato en el ordenador. El tipo de un dato también determina qué operaciones es posible realizar con él. Por ejemplo, es posible sumar números o matrices numéricas, pero no secuencias de caracteres. En este tema vamos a estudiar los tipos de datos: cadena de caracteres, vector y factor.

5.1 Cadenas de caracteres

En temas previos ya hemos trabajado con tipos de datos básicos como números y valores lógicos. Las cadenas de caracteres también son un tipo de dato básico. Consisten en una secuencia de caracteres y sirven para representar información de tipo texto, como el nombre de una persona, el nombre de una calle, una matrícula de un coche, etcétera.

En R una cadena de caracteres se representa como una serie de caracteres encerradas entre comillas dobles o simples:

nombre <- "Diego"        # usando comillas dobles
matricula <- '1234 ABC'  # usando comillas simples

Independientemente de que usemos comillas dobles o simples, R nos mostrará la cadena en la consola con comillas dobles o sin ningún tipo de entrecomillado, pero nunca con comillas simples.

Si es necesario usar un tipo de comillas en una cadena de caracteres, podemos usar el otro tipo de comillas para delimitar la cadena:

'Me dijo: "detente"'
## [1] "Me dijo: \"detente\""
"Me dijo: 'detente'"
## [1] "Me dijo: 'detente'"

Otra posibilidad es usar una secuencia de escape con el carácter de escape \:

"Me dijo: \"detente\""
## [1] "Me dijo: \"detente\""

Otras secuencias de escape muy utilizas son: \\ (barra invertida), \n (salto de línea) y \t (tabulador).

Existen funciones como paste, paste0 o substr que permiten trabajar con cadenas de caracteres, aunque no las vamos a estudiar aquí. Estas funciones son muy versátiles y, dependiendo de cómo se invoquen, son capaces de realizar distintos procesamientos. Por ejemplo, con paste se puede obtener una cadena de caracteres mezclando información de tipo texto con numérica, trabajando de una forma parecida a cat.

ang <- 0
cadena <- paste("El coseno de", ang, "vale", cos(ang))
cadena
## [1] "El coseno de 0 vale 1"

5.2 Vectores

Un vector es una colección ordenada de datos del mismo tipo. Es posible acceder a los elementos de un vector individual o parcialmente. Los vectores son uno de los tipos de datos más importantes de R y de la mayoría de los lenguajes de programación.

Los vectores se implementan como ilustra la Figura 5.1. En la figura se observa cómo se almacena en la memoria del ordenador los elementos del vector \([6, 20, 15, \ldots]\), apareciendo las direcciones de memoria a la izquierda de los valores. Los elementos de un vector se almacenan en posiciones contiguas de memoria. Como todos los elementos de un vector tienen que ser del mismo tipo ocupan el mismo tamaño en la memoria y, por lo tanto, guardando la dirección de inicio del vector es fácil y eficiente acceder a cualquiera de sus elementos dado su índice. Por ejemplo, en la figura se ilustra cómo se accede al elemento de índice 5. En general para acceder a la dirección de memoria del elemento de índice i habrá que realizar el cálculo: \(direccion\_inicio\_vector + (i-1)*tama\_direccion\).

Implementación de un vector.
Implementación de un vector.

5.2.1 Creación de vectores

En R es posible crear vectores de un gran número de formas. Una de las más utilizadas es usando la función c, que toma como parámetros un número arbitrario de elementos. La función c devuelve un vector con la concatenación de dichos elementos.

v <- c(2, 8.3, 5.4) # vector numérico formado por 3 números
v
## [1] 2.0 8.3 5.4

La función c admite vectores como parámetros:

v1 <- c(1, 3)
v2 <- c(7, 9)
v <- c(v1, 5, v2)
v
## [1] 1 3 5 7 9

Los elementos de un vector pueden ser de cualquier tipo base:

dedos <- c('Pulgar', 'Índice', 'Corazón', 'Anular', 'Meñique')
dedos
## [1] "Pulgar"  "Índice"  "Corazón" "Anular"  "Meñique"
(v <- c(TRUE, FALSE, FALSE)) # vector de valores lógicos
## [1]  TRUE FALSE FALSE

5.2.1.1 Generación de secuencias regulares

El operador : permite generar un vector que almacena una progresión aritmética con valores separados por una unidad. Por ejemplo 1:5 equivale a c(1, 2, 3, 4, 5). También es posible generar secuencias decrecientes:

1:10
##  [1]  1  2  3  4  5  6  7  8  9 10
9:2
## [1] 9 8 7 6 5 4 3 2

El operador : tiene una prioridad alta, mayor que la de algunos operadores aritméticos:

n <- 10
5:n-1   # equivale a (5:n)-1
## [1] 4 5 6 7 8 9
5:(n-1) # 5:9
## [1] 5 6 7 8 9

La función seq también permite generar progresiones aritméticas. seq(1, 10) equivale a 1:10. Sin embargo, seq tiene parámetros con nombre que permiten generar otro tipo de secuencias. Por ejemplo, by especifica la distancia entre los elementos de la progresión aritmética:

seq(10, 12, by = .2)
##  [1] 10.0 10.2 10.4 10.6 10.8 11.0 11.2 11.4 11.6 11.8 12.0
seq(from = 11, to = 9, by = -.5)
## [1] 11.0 10.5 10.0  9.5  9.0

El parámetro con nombre length.out también es muy usado. Indica la longitud de la secuencia:

seq(0, pi, length.out = 10)
##  [1] 0.0000000 0.3490659 0.6981317 1.0471976 1.3962634 1.7453293 2.0943951
##  [8] 2.4434610 2.7925268 3.1415927

Esta última invocación genera 10 números equidistantes en el intervalo \([0, \pi]\) (los extremos del intervalo se incluyen en la secuencia). Otro uso interesante de seq combina sus parámetros from, by y length.out:

seq(0, by = 2, length.out = 10)
##  [1]  0  2  4  6  8 10 12 14 16 18

Otra función muy útil es rep, que sirve para replicar valores de un vector. Veamos algunos ejemplos:

rep(c(2, 1, 3), times = 4)
##  [1] 2 1 3 2 1 3 2 1 3 2 1 3
rep(c(2, 1, 3), each = 4)
##  [1] 2 2 2 2 1 1 1 1 3 3 3 3
rep(c("a", "b", "c"), times = c(2, 1, 5))
## [1] "a" "a" "b" "c" "c" "c" "c" "c"

5.2.1.2 Vector vacío

A veces se necesita generar un vector vacío, es decir, sin datos. A continuación se ilustra una forma de hacerlo:

v <- numeric()
length(v)
## [1] 0

La función length, aplicada a un vector, devuelve cuántos elementos tiene. El ejemplo anterior sirve para un vector de datos reales, para datos de distintos tipos básicos habría que cambiar numeric por:

  • integer (enteros)
  • character (cadenas de caracteres)
  • logical (valores lógicos)
  • complex (números complejos)

Otra posibilidad es usar la función vector (consulta su ayuda si estás interesado en ver las distintas opciones):

v <- vector()
length(v)
## [1] 0

5.2.1.3 Generación de números aleatorios

Existen muchas funciones que devuelven como resultado un vector. Entre ellas se encuentran las funciones generadoras de números aleatorios, como runif o rnorm. Por ejemplo:

runif(10)
##  [1] 0.11659336 0.85240534 0.16414016 0.04945534 0.21357398 0.12361920
##  [7] 0.98069999 0.25565891 0.97463474 0.24254497
rnorm(5)
## [1] -0.4635491  0.5278014 -0.6334026  0.5447587 -0.5546772

La primera genera una muestra aleatoria de tamaño 10 de variables independientes de una \(U(0, 1)\) y la segunda una muestra de tamaño 5 de una \(\mathcal{N}(0, 1)\). Por supuesto, se puede especificar los parámetros de la distribución (usa la ayuda de estas funciones para ver cómo se hace). Nota: una \(U(0, 1)\) es una distribución uniforme de extremos 0 y 1, una variable aleatoria perteneciente a dicha distribución puede tomar cualquier valor en el rango \((0, 1)\) con igual probabilidad.

La generación de números aleatorios juega un papel crucial en el desarrollo de simulaciones con ordenador. Sin embargo, la aleatoriedad de los números generados hace que distintas ejecuciones de una simulación produzcan distintos resultados. Aunque esto es lo deseable, algunas veces puede dificultar la realización de un programa que implementa una simulación. Puesto que los números aleatorios generados son realmente pseudoaleatorios (generan una secuencia determinista a partir de una semilla), en la fase de desarrollo de una simulación podemos establecer la semilla para obtener siempre los mismos resultados. La función set.seed permite especificar la semilla. Veamos un ejemplo:

runif(5) # 5 números U(0, 1)
## [1] 0.22001495 0.96992986 0.08472204 0.60965870 0.65542190
runif(5) # 5 números U(0, 1)
## [1] 0.8678395 0.7507620 0.1298208 0.7140594 0.7063484
set.seed(8)
runif(5) # muestra de 5 U(0, 1) a partir de semilla 8
## [1] 0.4662952 0.2078233 0.7996580 0.6518713 0.3215092
set.seed(8)
runif(5) # La misma muestra que antes
## [1] 0.4662952 0.2078233 0.7996580 0.6518713 0.3215092

Ejemplo. Queremos realizar un experimento aleatorio que puede resultar con éxito con probabilidad \(p \in [0, 1]\). Por ejemplo, \(p = 0.7\), ¿cómo podríamos simular dicho experimento?

p <- 0.7
(experimento <- runif(1))
## [1] 0.7189275
experimento <= p # ¿Ha habido éxito?
## [1] FALSE

La solución sería el código previo. Se genera un valor aleatorio de una uniforme \((0, 1)\). La probabilidad de que el valor generado sea menor o igual que p es p.

5.2.1.4 Muestras aleatorias

Relacionada también con la aleatoriedad tenemos a la función sample, que obtiene una muestra aleatoria de un vector de elementos. Por defecto, la muestra es sin reemplazo y todos los elementos tienen la misma probabilidad de salir, pero hay parámetros para modificar este comportamiento por defecto.

sample(1:10, 5) # muestra (sin reemplazo) de tamaño 5 de números del 1 al 10
## [1]  7 10  6  1  5
sample(c("a", "b", "c"), 5, replace = TRUE) # con reemplazo
## [1] "b" "c" "c" "b" "b"

sample(n) genera una permutación aleatoria de los valores en el vector 1:n.

sample(5) # primera permutación
## [1] 4 3 2 1 5
sample(5) # segunda permutación
## [1] 4 2 3 5 1

sample(n) equivale a sample(1:n, size = n). Puedes consultar la ayuda de la función para ver todas las posibilidades.

Veamos ahora un ejemplo de uso de sample en el que los distintos elementos tienen distintas probabilidades de formar parte de la muestra:

sample(1:3, size = 10, replace = TRUE, prob = c(.1, .1, .8))
##  [1] 2 3 3 1 3 3 3 1 1 3
sample(c("a", "b"), size = 10, replace = TRUE, prob = c(2, 4))
##  [1] "a" "a" "b" "b" "a" "b" "b" "b" "b" "a"

En el primer ejemplo, el 1 y el 2 tienen probabilidad 0.1, mientras que el 3 tiene probabilidad 0.8. En el segundo ejemplo podemos ver que la suma del vector de probabilidades no tiene por qué ser 1. En este caso la "a" tendrá una probabilidad de \(\frac{2}{6}\) y la "b" de \(\frac{4}{6}\).

Ejercicio. Vamos a volver a realizar el experimento aleatorio que puede resultar con éxito con probabilidad \(p \in [0, 1]\). Por ejemplo, \(p = 0.7\). Esta vez lo solucionaremos usando sample.

sample(c(FALSE, TRUE), size = 1, prob = c(0.3, 0.7))
## [1] TRUE

Para comprobar que los resultados son consistentes repetimos el experimento 1000 veces y vemos cuántas veces hay fracaso y éxito (la función table se estudiará más adelante), se espera que el número de éxitos sea próximo a 700:

m <- sample(c(FALSE, TRUE), size = 1e3, replace = TRUE, prob = c(0.3, 0.7))
table(m)
## m
## FALSE  TRUE 
##   298   702

5.2.1.5 Lectura de datos desde el teclado

La función scan permite leer una serie de valores almacenados en un archivo o, en su defecto, provenientes del teclado. scan tiene muchas opciones para controlar la lectura. Usada sin parámetros lee del teclado números separados por espacios en blancos y/o saltos de línea. La lectura termina cuando se introduce una línea en blanco y los número leídos se devuelven en un vector:

v <- scan() # prueba a ejecutarlo en la consola

5.2.2 Tipo de un vector

Se puede obtener el tipo de un vector (de sus elementos) con la función typeof:

v1 <- c(1, 2.8, -3.5)
typeof(v1)
## [1] "double"
v2 <- c(2L, 20L)
typeof(v2)
## [1] "integer"
v3 <- c(TRUE, FALSE, FALSE)
typeof(v3)
## [1] "logical"
v4 <- c("1234 ABC", "2222 JKF")
typeof(v4)
## [1] "character"

Un vector puede almacenar elementos de tipo double (real), integer (entero), logical (lógico), character (cadena de caracteres), complex (complejo) y raw. Los dos últimos tipos no se usan demasiado, especialmente raw, y no los utilizaremos en estos apuntes.

Se puede comprobar si un vector es de un tipo concreto con las funciones is.double, is.integer, is.logical, is.character, is.complex e is.raw:

is.logical(v4)
## [1] FALSE
is.character(v4)
## [1] TRUE

Todos los elementos de un vector deben ser del mismo tipo. Si se intenta crear un vector con elementos de distinto tipo, todos los elementos se convierten al tipo con mayor rango de representación. El rango de representación de menor a mayor es: lógico, entero, real, carácter. Veamos algún ejemplo:

c(TRUE, 9)      # se convierten todos a real
## [1] 1 9
c(5.4, "diez")  # se convierten todos a cadena
## [1] "5.4"  "diez"

Cuando los valores lógicos se convierten a números FALSE se convierte en 0 y TRUE en 1. Se puede forzar la conversión de un vector de un tipo a otro con las funciones as.TIPO:

v <- c(TRUE, FALSE, TRUE)
as.integer(v)
## [1] 1 0 1
as.integer(c("1", "1.5", "a"))
## Warning: NAs introducidos por coerción
## [1]  1  1 NA

En la última conversión as.integer no sabe cómo convertir "a" a entero, por lo que genera el valor NA y muestra una advertencia.

Como ejercicio, intenta predecir qué producirán las siguientes expresiones: c(1, FALSE), c("a", 7) y c(TRUE, 1L). Escríbelas en la consola y comprueba si has acertado.

5.2.3 Aritmética de vectores

Una de las ventajas de R frente a otros lenguajes de programación es que en R se puede aplicar los operadores aritméticos (+, -, *, etcétera) a los vectores (los vectores deberán ser de algún tipo numérico o de tipo lógico):

v1 <- c(-5, 2, 8.1)
v2 <- c(4, -3, 9)
v1 + v2
## [1] -1.0 -1.0 17.1

En caso de que los vectores no tengan la misma longitud, el resultado será de la longitud del vector más largo y los vectores más pequeños se reciclan para que encajen con la longitud del vector más largo.

v1 <- c(-5, 2, 8.1)
v2 <- 1:2
v1 + v2  # v2 se recicla a c(1, 2, 1)
## Warning in v1 + v2: longitud de objeto mayor no es múltiplo de la longitud de
## uno menor
## [1] -4.0  4.0  9.1

Aunque el código previo es correcto, R nos avisa porque la longitud de v1 no es un múltiplo de la de v2. En el siguiente ejemplo R no avisa:

v1 <- c(-5, 2, 8.1, 2)
v2 <- 1:2
v1 + v2  # v2 se recicla a c(1, 2, 1, 2)
## [1] -4.0  4.0  9.1  4.0

Es interesante saber que en R cuando escribimos un valor literal, como 7, realmente se trata como un vector de un elemento. Es decir,7 es una forma abreviada de escribir c(7). Por lo tanto, lo siguiente es válido:

x <- 1:10
2 * x  - 3
##  [1] -1  1  3  5  7  9 11 13 15 17

Realmente 2 es un vector de longitud uno que se recicla para que tenga la longitud de x (es decir, se recicla a un vector con 10 doses), y lo mismo ocurre con 3. El efecto del código previo es equivalente a:

x <- 1:10
rep(2, times = length(x)) * x - rep(3, times = length(x))
##  [1] -1  1  3  5  7  9 11 13 15 17

Es decir, se evalúa la función \(2x -3\) para los valores del 1 al 10.

Las funciones como sqrt, log, exp, cos, sin, abs, round, … están escritas para trabajar con vectores:

exp(seq(1, 7, by = 2) / 2)
## [1]  1.648721  4.481689 12.182494 33.115452

produce el vector c(\(e^{1/2}\), \(e^{3/2}\), \(e^{5/2}\), \(e^{7/2}\)).

La combinación de aritmética de vectores con funciones gráficas, como plot, que estudiaremos más adelante, permite visualizar de una forma sencilla funciones matemáticas:

# Función x^2 + 2 en el intervalo [-10, 10]
x <- seq(-10, 10, by = .1)
plot(x, x^2 + 2, type = "l")

5.2.4 Funciones aplicables a vectores

Aparte de las funciones vistas anteriormente, como exp, que aplican una operación a los distintos elementos de un vector, hay otras funciones que realizan un procesamiento sobre los elementos de un vector en conjunto. La lista es muy grande, por lo que vamos a citar sólo algunas:

  • mean, median, var y sd: calculan la media, mediana, varianza muestral y desviación típica muestral respectivamente de una muestra de valores.
  • max y min: el máximo y mínimo repectivamente.
  • range: produce el vector c(min(v), max(v)), donde v es el vector al que se aplica.
  • sum y prod: calculan la sumatoria y el productorio de los elementos de un vector respectivamente.
  • cumsum y cumprod: suma y producto acumulado respectivamente.
  • sort: ordena los elementos (por defecto, en orden creciente).
  • rev: devuelve el vector en orden inverso.

Veamos algunos ejemplos:

x <- c(2, 9, 5, 2.3)
median(x)
## [1] 3.65
max(x)
## [1] 9
sum(x)
## [1] 18.3
cumsum(x)
## [1]  2.0 11.0 16.0 18.3
sort(x)
## [1] 2.0 2.3 5.0 9.0
rev(x)
## [1] 2.3 5.0 9.0 2.0
cumprod(1:5) # factoriales de los números del 1 al 5
## [1]   1   2   6  24 120

La aritmética de vectores, junto con el hecho de que gran parte de las funciones se puedan aplicar a vectores permite expresar cálculos complejos de una forma sencilla. Por ejemplo, la función sd calcula la desviación típica de una muestra x formada por \(n\) números según la fórmula:

\[ \sigma = \sqrt{\frac{1}{n-1} \sum_{i=1}^n (x_{i}- \overline{x})^{2}} \]

En caso de que no existiera la función sd, se podría escribir de una forma relativamente sencilla usando aritmética de vectores:

v <- runif(1000, max = 6) # muestra de tamaño 1000 de una U(0, 6)
sd(v)                     # desviación estándar usando sd
## [1] 1.730926
suma <- sum((v - mean(v)) ^ 2) # sumatorio
sigma <- sqrt(suma/(length(v) - 1))
sigma
## [1] 1.730926

5.2.5 Vectores lógicos

Un vector lógico es aquel cuyos elementos son valores lógicos, por ejemplo:

v <- c(TRUE, TRUE, FALSE)
v
## [1]  TRUE  TRUE FALSE

Los operadores relacionales (<, >, <=, >=, ==, !=) se aplican de forma natural a los vectores, produciendo como resultado un vector lógico:

(v <- rnorm(5))
## [1] 0.8890187 0.9535617 0.3606410 0.4474049 2.7091723
v > 0
## [1] TRUE TRUE TRUE TRUE TRUE
"casa" == c("barco", "casa", "pez")
## [1] FALSE  TRUE FALSE

Observa que en las expresiones previas 0 y casa se reciclan para coincidir con las longitudes de los distintos vectores. En el siguiente caso, los dos vectores tienen la misma longitud:

(v1 <- runif(4))
## [1] 0.3948128 0.5136268 0.8479917 0.5274398
(v2 <- runif(4))
## [1] 0.002748603 0.058694025 0.309743033 0.107500788
v1 >= v2
## [1] TRUE TRUE TRUE TRUE

Cuando un vector lógico es aplicado en una operación aritmética, los valores FALSE se convierten a 0 y los TRUE a 1. Esto permite aplicar sum y mean a vectores lógicos para calcular cuántos elementos de un vector y qué proporción, respectivamente, verifican una condición:

x <- c(-2, 3, 4, -1, 4.2)
(condicion <- x > 0)
## [1] FALSE  TRUE  TRUE FALSE  TRUE
sum(condicion) # ¿Cuántos elementos son mayores que cero?
## [1] 3
sum(x > 0)  # En una única expresión
## [1] 3
mean(x > 0) # Proporción de elementos mayores que cero
## [1] 0.6

Ejercicio. Vamos a simular el lanzamiento de una moneda no cargada un millón de veces y a contar cuántas caras y cruces han salido:

experimento <- sample(c("cara", "cruz"), 1e6, replace = TRUE) 
sum(experimento == "cara")
## [1] 499866
sum(experimento == "cruz")
## [1] 500134

Ejercicio: Simulación. A veces se desconoce la probabilidad de ocurrencia de un evento. Esta probabilidad equivale a la proporción de veces (frecuencia relativa) en las que, si se realiza infinitamente un experimento aleatorio, ocurre el evento. Por lo tanto, se puede usar el ordenador para simular múltiples veces un experimento aleatorio y calcular la proporción de las veces en las que ocurre el evento. Esta proporción es una estimación puntual de la probabilidad del evento. Cuántas más veces se simule el experimento mayor certeza se tiene de la estimación puntual obtenida está cerca de la probabilidad real de ocurrencia del evento. Como ejemplo supongamos que lanzamos un dado negro y otro verde, ¿cuál es la probabilidad de que el dado verde sea mayor que el negro? Esta probabilidad se puede calcular fácilmente como \(\frac{15}{36}\). Sin embargo, vamos a realizar una simulación para obtener una estimación puntual de esta probabilidad. Para ello lanzamos un millón de veces 2 dados y calculamos la proporción de veces en las que un dado es mayor que el otro:

15/36
## [1] 0.4166667
verde <- sample(6, size = 1e6, replace = TRUE)
negro <- sample(6, size = 1e6, replace = TRUE)
mean(verde > negro)
## [1] 0.417818

Al ser el número de experimentos grande (un millón) se tiene bastante certeza de que el estimador obtenido será próximo al valor real de la probabilidad.

5.2.5.1 Operadores lógicos

En un tema previo vimos los operadores lógicos: Y (&&), O (||) y NO (!). Los operadores lógicos se pueden aplicar a vectores lógicos. Cuando se aplica a vectores lógicos, el operador lógico Y cambia de && a &. El operador O cambia de || a |. Estos operadores se aplican elemento a elemento. Por ejemplo:

v1 <- c(TRUE, FALSE, TRUE, FALSE)
v2 <- c(TRUE, TRUE, FALSE, FALSE)
v1 & v2
## [1]  TRUE FALSE FALSE FALSE
v1 | v2
## [1]  TRUE  TRUE  TRUE FALSE
!v1
## [1] FALSE  TRUE FALSE  TRUE

Como veremos más adelante, las expresiones lógicas combinadas con la indexación lógica, resultan muy útiles para trabajar con vectores. Veamos algún otro ejemplo de expresiones lógicas:

v <- c(2, 5, 9, 4, 6)
v >= 5 & v <= 10       # ¿v en el rango [5, 10]?
## [1] FALSE  TRUE  TRUE FALSE  TRUE
sum(v >= 5 & v <= 10)  # Cantidad de valores en [5, 10]
## [1] 3
mean(v >= 5 & v <= 10) # Proporción de valores en [5, 10]
## [1] 0.6

Existen dos funciones muy útiles para trabajar con vectores lógicos. Se trata de all, que indica si todos los elementos de un vector lógico son verdaderos y any que indica si al menos uno es verdadero.

v <- c(2, 4, 8, 10, 11)
v %% 2 == 0      # Calcula si los elementos de v son pares o no
## [1]  TRUE  TRUE  TRUE  TRUE FALSE
all(v %% 2 == 0) # ¿Todos los elementos de v son pares?
## [1] FALSE
any(v %% 2 == 0) # ¿Algún elemento de v es par?
## [1] TRUE
all(v > 0)       # ¿Son todos positivos?
## [1] TRUE

Otra función relacionada con vectores lógicos es which. Esta función devuelve los índices de un vector lógico con valores a verdadero:

(v <- sample(10))
##  [1]  9  1  5  7  2  3  4 10  6  8
which(v > 5) # índices de v con valores mayores que 5
## [1]  1  4  8  9 10
which(v == max(v)) # índice del máximo en v
## [1] 8
n <- 20
which(n %% 1:n == 0) # divisores del número n
## [1]  1  2  4  5 10 20

Por último, la función xor calcula la función O exclusiva. Esta función lógica indica si sólo uno de sus dos operandos es verdadero.

v1 <- c(TRUE, FALSE, TRUE, FALSE)
v2 <- c(TRUE, TRUE, FALSE, FALSE)
xor(v1, v2)
## [1] FALSE  TRUE  TRUE FALSE

No existe un operador O exclusivo, porque la operación xor se puede obtener mediante los operadores básicos: O, Y, NO. Piensa un poco e intenta expresar xor mediante estos operadores. La solución es la siguiente:

v1 <- c(TRUE, FALSE, TRUE, FALSE)
v2 <- c(TRUE, TRUE, FALSE, FALSE)
(v1 & !v2) | (!v1 & v2)
## [1] FALSE  TRUE  TRUE FALSE

5.2.6 Indexación de un vector

A veces es útil trabajar con una parte de los elementos de un vector, ya sea para consultar sus valores o para modificarlos. La indexación permite seleccionar una parte de los elementos de un vector. Los vectores de R admiten cuatro tipos de indexación, que describimos en las siguientes subsecciones. El operador de indexación es []. Para indexar hay que especificar un vector de índices encerrado entre [].

5.2.6.1 Mediante un vector de enteros positivos

En este caso los valores del vector de índices deben pertenecer al conjunto \(\{1, 2, ..., length(v)\}\), donde \(v\) es el nombre del vector que se indexa. Por ejemplo:

v <- c(1, 4, 9, 16, 25)
v[c(2, 5)] # índices 2 y 5
## [1]  4 25
v[1:3]     # 3 primeros elementos (índices del 1 al 3)
## [1] 1 4 9
v[c(1, 2, 2, 4)] # se pueden repetir valores
## [1]  1  4  4 16

Observa que el primer índice de un vector en R es 1, en otros lenguajes de programación es 0. Cuando sólo se quiere acceder a un elemento de un vector se puede usar la siguiente sintaxis:

v <- c(1, 4, 9, 16, 25)
v[3]  # tercer elemento, equivale a v[c(3)]
## [1] 9

v[3] equivale a v[c(3)] porque realmente 3 equivale a c(3).

Cuando solo se indexa un elemento se puede usar el operador [[]] en lugar del operador []:

v <- c("a", "b", "c")
v[2]   # segundo elemento
## [1] "b"
v[[2]] # equivale al anterior
## [1] "b"

En los ejemplos anteriores hemos utilizado la indexación para consultar los elementos de un vector, pero también puede usarse para modificar sus elementos:

v <- c(1, 4, 9, 16, 25)
v[3] <- 0
v
## [1]  1  4  0 16 25
v[1:2] <- 0  # aquí 0 se recicla a c(0, 0)
v
## [1]  0  0  0 16 25
v[1:3] <- c(4, 10, -1)
v
## [1]  4 10 -1 16 25

Ejercicio. Crea un vector aleatorio de 10 elementos y selecciona aquellos elementos del vector que ocupan índices impares. Usa seq para expresar el vector de índices impares.

(v <- sample(10))
##  [1]  7  1  8  5  3 10  4  2  6  9
v[seq(1, length(v), by = 2)]
## [1] 7 8 3 4 6

5.2.6.2 Mediante un vector de enteros negativos

Es similar a lo visto en el apartado anterior, pero los valores del vector de índices son negativos e indican los índices a excluir, en lugar de los índices a incluir:

v <- c("a", "e", "i", "o", "u")
v[-c(2,3)] # todos los índices, salvo el 2 y el 3
## [1] "a" "o" "u"
v[c(-2, -3)] # igual al anterior
## [1] "a" "o" "u"
v[-length(v)] # todos salvo el último
## [1] "a" "e" "i" "o"

5.2.6.3 Mediante un vector de valores lógicos

En este caso el vector contiene valores lógicos. Los índices correspondientes a valores verdaderos en el vector lógico son seleccionados, los que son falsos no se seleccionan.

v <- c("Juan", "Pascal", "Julio")
soltero <- c(FALSE, TRUE, TRUE)
v[soltero]
## [1] "Pascal" "Julio"

En el caso de que la longitud del vector lógico sea inferior a la del vector indexado, el vector lógico es reciclado:

v <- (1:7) ^ 2
v
## [1]  1  4  9 16 25 36 49
v[c(TRUE, FALSE)] # posiciones impares del vector
## [1]  1  9 25 49

El último ejemplo usa el reciclado para seleccionar los elementos del vector que ocupan índices impares.

Se puede usar el indexado lógico para seleccionar los elementos de un vector que verifican una condición. Esta operación es muy útil y habitual y a veces es conocida como filtrado:

v <- rnorm(10)
v
##  [1] -0.69344101  0.80718587 -0.09931044  0.90467478 -0.64957217  0.42901828
##  [7]  0.48631070  0.59375000  0.99638417 -1.75199061
positivos <- v[v > 0]
positivos
## [1] 0.8071859 0.9046748 0.4290183 0.4863107 0.5937500 0.9963842
v2 <- v[v >= -1.5 & v <= 1.5] # valores en el rango [-1.5, 1.5]
v2
## [1] -0.69344101  0.80718587 -0.09931044  0.90467478 -0.64957217  0.42901828
## [7]  0.48631070  0.59375000  0.99638417
v[v < 0] <- -v[v < 0] # convierte en positivos los negativos
v
##  [1] 0.69344101 0.80718587 0.09931044 0.90467478 0.64957217 0.42901828
##  [7] 0.48631070 0.59375000 0.99638417 1.75199061

El último procesamiento también se puede hacer con la instrucción v <- abs(v).

5.2.6.4 Mediante un vector de cadenas de caracteres

Para usar esta posibilidad el vector debe poseer un atributo names que permita identificar a sus componentes. Vamos a ver cómo se especifica este atributo:

edades <- c(18, 17, 18, 19)
names(edades) <- c("Ana", "Sara", "Juan", "Julia")
edades
##   Ana  Sara  Juan Julia 
##    18    17    18    19

El indexado con cadenas es similar al indexado con valores enteros positivos, pero usando un vector de cadenas de caracteres:

edades[c("Ana", "Julia")]
##   Ana Julia 
##    18    19
edades["Ana"] <- edades["Ana"] + 1 # incrementa la edad

Es posible crear un vector con nombres usando la función c:

edades <- c(Ana = 18, Sara = 17, "Juan Pedro" = 18, Luis = 19)
edades
##        Ana       Sara Juan Pedro       Luis 
##         18         17         18         19

5.2.7 Valores perdidos

Un valor perdido (missing value) es un valor no disponible. Esto ocurre con frecuencia en estadística porque se desconoce el valor de una variable, por ejemplo, la edad de una persona en una encuesta (esto podría ocurrir porque el encuestado no la introdujo o porque no se entiende lo que escribió). En R se utiliza la palabra reservada NA (Not available) para indicar un valor perdido. Hay que tener en cuenta que la mayoría de operaciones que implican un valor perdido producen un valor perdido. Por ejemplo:

pesos <- c(77, 68.2, 90.5, NA, 61.5) # pesos en kilogramos
pesos_en_libras <- pesos * 2.205
pesos_en_libras
## [1] 169.7850 150.3810 199.5525       NA 135.6075
mean(pesos)
## [1] NA

Esto es lógico, porque, por ejemplo, no podemos saber la media de un conjunto de valores si se desconoce el valor de algún elemento.

Si queremos eliminar los valores perdidos podemos usar la función is.na, que aplicada a un vector produce un vector lógico indicando si los elementos del vector son valores perdidos:

is.na(pesos)
## [1] FALSE FALSE FALSE  TRUE FALSE

Ahora la media de los pesos conocidos puede calcularse como:

mean(pesos[!is.na(pesos)])
## [1] 74.3

Algunas funciones como mean o sd tienen un parámetro con nombre para eliminar los valores perdidos del cómputo:

mean(pesos, na.rm = TRUE)
## [1] 74.3

Es tentador usar pesos == NA en lugar de is.na(pesos), pero la expresión pesos == NA produce c(NA, NA, NA, NA, NA). Esto es correcto, aunque sorprenda, porque no puedes saber si un valor no disponible coincide con otro valor (disponible o no).

Hay que tener en cuenta que hay un segundo tipo de valor que es considerado como un valor perdido por la función is.na, se trata del valor NaN (Not a Number). Este valor se genera al realizar ciertas operaciones aritméticas indefinidas:

0 / 0
## [1] NaN
Inf - Inf # Inf significa infinito
## [1] NaN

Para distinguir entre NA y NaN ten en cuenta que is.na es cierto para ambos valores, pero is.nan es válido sólo para NaN.

Ejercicio: Dado el vector especificado más abajo, calcula los índices de dicho vector con valores NA.

set.seed(10)
(v <- sample(c(NA, NaN, 1), size = 6, replace = TRUE))
## [1]   1  NA NaN   1 NaN   1
# Solución:
which(is.na(v) & !is.nan(v))
## [1] 2

5.2.8 Crecimiento dinámico de un vector

La mayoría de las veces un vector se creará con un tamaño y éste no se modificará. Sin embargo, un vector puede crecer o decrecer. Vamos a verlo con un ejemplo:

(v <- c(3, 2))
## [1] 3 2
v[5] <- 11     # v crece de tamaño 2 a 5
v              # los valores indefinidos valen NA
## [1]  3  2 NA NA 11
length(v) <- 3 # ahora el vector decrece
v
## [1]  3  2 NA

En concreto, para añadir un elemento al final de un vector tenemos varias posibilidades:

v <- 1:3
v <- c(v, 20)          # forma 1: añade 20 al final del vector
v[length(v) + 1] <- 30 # forma 2: añade 30 al final del vector
v
## [1]  1  2  3 20 30

5.2.9 Operaciones con conjuntos

Un vector sin repetidos permite representar el concepto matemático de un conjunto (una colección de elementos sin repetidos y sin un orden determinado). R tiene implementadas las operaciones básicas entre conjuntos, como unión, intersección, etcétera.

x <- c(1, 2, 5)
y <- c(5, 6, 1, 3)
union(x, y)      # unión
## [1] 1 2 5 6 3
intersect(x, y)  # intersección
## [1] 1 5
setdiff(x, y)    # diferencia: elementos de x que no están en y
## [1] 2
setdiff(y, x)
## [1] 6 3
setequal(x, y)   # igualdad
## [1] FALSE
setequal(x, c(5, 2, 1))
## [1] TRUE

Puedes observar que setequal no tiene en cuenta el orden de los elementos, puesto que, por definición de conjunto, los elementos de un conjunto no tienen un orden definido.

Para comprobar si un conjunto contiene un elemento se puede utilizar el operador %in% o la función is.element:

2 %in% x
## [1] TRUE
c(2, 4) %in% x # comprobamos dos elementos
## [1]  TRUE FALSE
is.element(2, x)
## [1] TRUE
is.element(c(2, 4), x)
## [1]  TRUE FALSE

Ejercicio. Vamos a comprobar que el vector d sólo contiene días de la semana.

d <- c("martes", "jueves")
dias <- c("lunes", "martes", "miércoles", "jueves", "viernes",
          "sábado", "domingo")
all(d %in% dias)
## [1] TRUE
d <- c("lunes", "enero")
all(d %in% dias)
## [1] FALSE
length(setdiff(d, dias)) == 0 # otra alternativa
## [1] FALSE

Ejercicio. Dados dos vectores con los identificadores de los alumnos matriculados en las asignaturas de estadística e informática vamos a calcular cuántos alumnos están matriculadas en ambas asignaturas.

estadistica <- c("11111111A", "22222222B", "33333333C")
informatica <- c("44444444D", "22222222B", "11111111A")
length(intersect(estadistica, informatica))
## [1] 2
sum(estadistica %in% informatica) # otra forma
## [1] 2

5.3 Factores

Un factor es un vector utilizado para especificar una clasificación discreta (agrupamiento) de los componentes de otros vectores de la misma longitud. Es decir, los factores sirven para representar datos categóricos. En principio, esta información se puede guardar con cadenas de caracteres, con enteros o valores lógicos (dependiento del tipo de la información), pero usar factores tiene alguna ventaja. Como ejemplo, vamos a suponer que tenemos un vector con las notas de un examen de prácticas. El grupo de prácticas de los alumnos se guarda en otro vector:

notas <- c(10, 7, 6, 8)
grupo <- c("g1", "g2", "g2", "g2") # dato categórico

Es decir, el primer alumno sacó un 10 y pertenece al grupo 1, el segundo sacó un 7 y pertenece al grupo 2, etcétera. En este ejemplo el grupo de un alumno es un dato categórico. Un pequeño problema de la representación del dato categórico con un vector de cadenas de caracteres es que no sabemos cuántas categorías hay. Viendo el vector se observan dos grupos, pero ¿y si hay un grupo en el que nadie se ha presentado al examen? Los factores permiten especificar todos los valores posibles de la categoría:

notas <- c(10, 7, 6, 8)
grupo <- c("g1", "g2", "g2", "g2")
grupo2 <- factor(c("g1", "g2", "g2", "g2"), levels = c("g1", "g2", "g3"))
grupo2
## [1] g1 g2 g2 g2
## Levels: g1 g2 g3

Además, al visualizar el factor se puede ver todos los posibles valores o niveles de la categoría.

La función table se aplica a un factor y cuenta ocurrencias de cada categoría (tabla de frecuencias):

table(grupo)
## grupo
## g1 g2 
##  1  3
table(grupo2)
## grupo2
## g1 g2 g3 
##  1  3  0

Si no se usan factores no es posible especificar una cuenta de cero (como para el grupo 3), porque table no puede deducir la existencia de niveles sin ocurrencias.

La función prop.table produce las frecuencias relativas:

prop.table(table(grupo))
## grupo
##   g1   g2 
## 0.25 0.75
prop.table(table(grupo2))
## grupo2
##   g1   g2   g3 
## 0.25 0.75 0.00

En general, table permite contar las ocurrencias de los distintos elementos de un vector:

(v <- (sample(6, size = 10, replace = TRUE))) # lanzamos un dado 10 veces
##  [1] 3 2 2 2 5 6 6 3 6 2
table(v)
## v
## 2 3 5 6 
## 4 2 1 3

Se puede consultar información relativa a los niveles de un factor:

nlevels(grupo2)  # cantidad de niveles
## [1] 3
levels(grupo2)   # niveles
## [1] "g1" "g2" "g3"

Internamente los factores se almacenan como un vector de enteros para ahorrar espacio:

typeof(grupo)
## [1] "character"
typeof(grupo2)
## [1] "integer"
as.integer(grupo2)
## [1] 1 2 2 2

La función tapply permite aplicar una función a un vector, agrupando sus datos por categorías. Por ejemplo, veamos la nota media del examen y la nota media por grupo:

mean(notas)                 # media de las notas
## [1] 7.75
tapply(notas, grupo2, mean) # media de las notas por grupo
## g1 g2 g3 
## 10  7 NA

En esta invocación tapply selecciona las notas del grupo g1 (el vector c(10)) y pasa dicho vector a la función mean, y lo mismo con las notas de los otros dos grupos (para el grupo g2 el vector es c(7, 6, 8)).

Si las categorías tienen un orden natural se puede usar la función ordered en lugar de factor para crear el factor:

nombres <- c("Ana", "Simón", "Nuria")
notas <- ordered(c("Notable", "Aprobado", "Sobresaliente"),
                 levels = c("Suspenso", "Aprobado", "Notable",
                            "Sobresaliente"))
notas
## [1] Notable       Aprobado      Sobresaliente
## Levels: Suspenso < Aprobado < Notable < Sobresaliente

Por lo demás, un factor ordenado se comporta igual que uno en el que no existe un orden de las categorías.

Para poder introducir un valor en un factor, este debe pertenecer a los niveles del factor:

notas[1] <- "Sobresaliente" # se modifica la nota
notas
## [1] Sobresaliente Aprobado      Sobresaliente
## Levels: Suspenso < Aprobado < Notable < Sobresaliente
notas[1] <- "Excelente"
## Warning in `[<-.factor`(`*tmp*`, 1, value = "Excelente"): invalid factor level,
## NA generated
notas
## [1] <NA>          Aprobado      Sobresaliente
## Levels: Suspenso < Aprobado < Notable < Sobresaliente

La función cut sirve para discretizar una variable real y convertirla en un factor. Vamos a ver un ejemplo (usa ?cut para ver más posibilidades):

(notas <- runif(9, min = 0, max = 10))
## [1] 3.5589774 5.3559704 0.9308813 1.6980304 8.9983245 4.2263761 7.4774647
## [8] 8.2265258 9.5465365
n2 <- cut(notas, c(0, 5, 7, 9, 10))
n2
## [1] (0,5]  (5,7]  (0,5]  (0,5]  (7,9]  (0,5]  (7,9]  (7,9]  (9,10]
## Levels: (0,5] (5,7] (7,9] (9,10]
table(n2)
## n2
##  (0,5]  (5,7]  (7,9] (9,10] 
##      4      1      3      1
n3 <- cut(notas, 
          c(0, 5, 7, 9, 10), 
          labels = c("Suspenso", "Aprobado", "Notable", "Sob"))
n3
## [1] Suspenso Aprobado Suspenso Suspenso Notable  Suspenso Notable  Notable 
## [9] Sob     
## Levels: Suspenso Aprobado Notable Sob
table(n3)
## n3
## Suspenso Aprobado  Notable      Sob 
##        4        1        3        1

El primer parámetro de cut es un vector con los valores reales y el segundo un vector que define los intervalos usados para discretizar. Por ejemplo, si el segundo vector se llama s, por defecto, el primer intervalo será (s[0], s[1]], el segundo (s[1], s[2]] y así sucesivamente.

5.4 Números complejos

Aunque en estos apuntes no los vamos a utilizar, pues en estadística rara vez son necesarios, R permite trabajar con números complejos:

n <- -4 + 0i
sqrt(n)
## [1] 0+2i

5.5 Ejercicios

  1. Crea un vector formado por 15 ocurrencias del valor 6.

  2. Supón que quieres jugar al bingo. Escribe una expresión que sirva para simular la extracción de las 90 bolas de la urna.

  3. Escribe una expresión que simule el lanzamiento de una moneda 10 veces. Obtén como resultado de la expresión un vector de valores "cara" y "cruz". Cuenta las ocurrencias de cara y cruz, y la proporción de cada valor.

  4. Una urna tiene 6 bolas rojas y 5 verdes. Simula la extracción aleatoria de una muestra de tamaño 3.

  5. La probabilidad de que una variable \(X \sim \mathcal{N}(0, 1)\) sea mayor que 3 es pnorm(3, lower.tail = FALSE). Obtén una estimación de dicho valor generando un vector con un millón de instancias de una \(\mathcal{N}(0, 1)\) y calculando qué proproción de ellas son mayores que 3.

  6. Crea un vector aleatorio de 10 elementos y selecciona aquellos elementos del vector que ocupan índices impares. Usa seq para expresar el vector de índices impares.

  7. Existen muchos métodos numéricos capaces de proporcionar aproximaciones a \(\pi\). Usa la siguiente fórmula para calcular una aproximación (el número de términos de la sumatoria se leerá de teclado):

    \[ \pi = \sqrt{\sum_{i=1}^{\infty} \frac{6}{i^{2}}} \]

  8. Dadas dos muestras emparejadas:

    x <- iris$Petal.Length
    y <- iris$Petal.Width

    calcula su coeficiente de correlación lineal muestral de Pearson, según la siguiente fórmula, donde \(n\) es el tamaño de ambas muestras (puedes usar sd):

    \[ \frac{\sum_{i=1}^n (x_{i}- \overline{x})(y_{i}- \overline{y})}{(n-1)\sigma_x\sigma_y} \]

  9. Crea un vector aleatorio con sample(100, size = 10). Extrae aquellos elementos del vector que elevados al cuadrado sean menores que 625.

  10. Escribe una expresión lógica que permita comprobar si todos los elementos de un vector son iguales. Sugerencia: puedes comprobar si todos los elementos son iguales que el primero.

  11. Escribe una expresión lógica que permita comprobar si un vector está ordenado en orden creciente. Sugerencia: comprobar si todos los elementos coinciden uno a uno con la versión ordenada del vector (usar sort y all)

  12. Escribe una expresión lógica que permita comprobar si un vector contiene exactamente los números del 1 al 20 sin repetidos (en cualquier orden).

  13. Muestra un vector en orden inverso sin usar la función rev. Sugerencia: indexa con los índices en orden inverso.

  14. Ejecuta:

    v <- c(2, NA, 7)
    all(v > 0)
    ## [1] NA

    ¿Tiene sentido la salida? Consulta la ayuda de all y escribe una expresión que compruebe si todos los elementos conocidos de un vector son mayores que cero.

  15. Casi todas las operaciones con NA producen NA. Pero hay excepciones. Piensa en qué puede producir: NA ^ 0, NA || TRUE y NA && FALSE. Ejecuta las expresiones y comprueba si has acertado.

  16. Compara la creación de las siguientes variables que almacena un valor categórico:

    v1 <- c("Hombre", "Mujer", "Mujer", "hombre")
    v2 <- factor(c("Hombre", "Mujer", "Mujer", "hombre"), 
                 levels = c("Mujer", "Hombre"))

    Ejecútalo y piensa por qué producen valores distintos.

  17. El siguiente código guarda la longitud de pétalo y el tipo de 150 flores en los vectores longitud y tipo:

    longitud <- iris$Petal.Length
    tipo <- iris$Species 

    El tipo es un factor. Calcula cuántas flores de cada tipo hay. Calcula la media de la longitud de pétalo por tipo de flor y la máxima longitud de pétalo para cada tipo de flor.

5.6 Soluciones

# Crear un vector formado por 15 ocurrencias de 6
rep(6, times = 15)
##  [1] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
# Bingo
sample(90)
##  [1] 33  7 26 50 30 68 51 54 59 32 11 79 90 42 77 13 78 72 16 88 48 23 15 62 24
## [26] 61  4 35 14 74 63 10 82 39 73 85 31 58 37 84 52 45 47 57 25 18  3 22 76 53
## [51] 55 75 71 67 28 34 64 20 83 29 44 69 17 56 65 43 86  9 27 46 81 40 36 41 89
## [76] 38  8 19 60 66 80 49 12  6  2  1 70  5 21 87
# Lanzamiento de una moneda 10 veces
(experimento <- sample(c("cruz", "cara"), size = 10, replace = TRUE))
##  [1] "cara" "cara" "cruz" "cara" "cruz" "cara" "cara" "cruz" "cara" "cruz"
table(experimento)
## experimento
## cara cruz 
##    6    4
cat("Proporción caras:", mean(experimento == "cara"), "\n")
## Proporción caras: 0.6
cat("Proporción cruces:", mean(experimento == "cruz"))
## Proporción cruces: 0.4
# Extracción de 3 bolas de una urna con 6 bolas rojas y 5 verdes
sample(rep(c("roja", "verde"), times = c(6, 5)), size = 3)
## [1] "verde" "roja"  "verde"
# Valores mayores que 3 de una N(0, 1)
pnorm(3, lower.tail = FALSE) # valor teórico
## [1] 0.001349898
v <- rnorm(1e6)
mean(v > 3)
## [1] 0.001308
# Elementos que ocupan un índice impar
v <- sample(1:10, 10)
v
##  [1] 10  4  5  3  1  2  7  8  6  9
v[seq(1, length(v), by = 2)]
## [1] 10  5  1  7  6
# Aproximación a pi
n <- as.integer(readline("Número de términos: "))
print(sqrt(sum(6 / (1:n) ^ 2)))
# Coeficiente de correlación de Pearson
x <- iris$Petal.Length
y <- iris$Petal.Width
cor(x, y)                # usando la función cor
## [1] 0.9628654
numerador   <- sum((x - mean(x)) * (y - mean(y)))
denominador <- (length(x) - 1) * sd(x) * sd(y)
numerador / denominador
## [1] 0.9628654
# Elementos elevados al cuadrado menores que 625
(v <- sample(100, size = 10))
##  [1] 59 18 57 94 52 90 29 71 47 51
v[v * v < 625]
## [1] 18
# Comprobar que todos los elementos de un vector son iguales
v1 <- rep(10, 5)
all(v1[1] == v1)
## [1] TRUE
v2 <- c(rep(10, 3), 4, rep(10, 3))
all(v2[1] == v2)
## [1] FALSE
length(unique(v1)) == 1 # menos eficiente
## [1] TRUE
# Comprobar que un vector está ordeando en orden creciente
v <- 1:10
all(v == sort(v))
## [1] TRUE
v <- c(1:10, 8)
all(v == sort(v))
## [1] FALSE
# Vector con valores del 1 al 20
sol = 1:20
v <- sample(1:20, size = 20)
length(v) == length(sol) && all(sort(v) == sol)
## [1] TRUE
v <- sample(1:20, size = 20, replace = TRUE)
length(v) == length(sol) && all(sort(v) == sol)
## [1] FALSE
v = 1:30
length(v) == length(sol) && all(sort(v) == sol)
## [1] FALSE
# Invertir un vector sin usar rev
(v <- c(1, 9, -2, 8))
## [1]  1  9 -2  8
v[length(v):1]
## [1]  8 -2  9  1
# Ejercicio sobre all
v = c(2, NA, 7)
all(v > 0)
## [1] NA
all(v > 0, na.rm = TRUE)
## [1] TRUE
# Expresiones con NA
NA ^ 0
## [1] 1
NA || TRUE
## [1] TRUE
NA && FALSE
## [1] FALSE
# Factor con valores Hombre y Mujer
(v1 <- c("Hombre", "Mujer", "Mujer", "hombre"))
## [1] "Hombre" "Mujer"  "Mujer"  "hombre"
(v2 <- factor(c("Hombre", "Mujer", "Mujer", "hombre"), 
               levels = c("Mujer", "Hombre")))
## [1] Hombre Mujer  Mujer  <NA>  
## Levels: Mujer Hombre
# Lo que ocurre es que nos hemos equivocado al teclear hombre con una h inicial en minúscula. Usando factor te das cuenta antes, porque al no corresponderse con un nivel ha puesto el valor a NA
# Flores
longitud <- iris$Petal.Length
tipo <- iris$Species
table(tipo) # Cuenta ocurrencias de cada tipo de flor
## tipo
##     setosa versicolor  virginica 
##         50         50         50
tapply(longitud, tipo, mean) # media de la longitud de pétalo por tipo
##     setosa versicolor  virginica 
##      1.462      4.260      5.552
tapply(longitud, tipo, max) # máximo de la longitud de pétalo por tipo
##     setosa versicolor  virginica 
##        1.9        5.1        6.9