Curso básico de R

Lunes 18 de Octubre

1 Operaciones básicas sobre vectores

CC

DataIntelligence
date:18-10-2021

1 Instrucción para realizar la tarea

Será enviada la tarea todos los días a las 10 am hora de Chile dividida en tres partes la cual se espera sea resuelta en la jornada diaria. Cada parte debe ser enviada a las 1 pm, 4 pm y 7 pm hora de Chile para ser evaluada en conjunto en unos 15 minutos. Las respuestas se requieren en formato Rpubs, que deberá quedar registrado en la hora indicada en nuestro grupo Data Science DI de Skype, en el que está incluído Patricio para que pueda darle rápido seguimiento a la evolución del proceso de aprendizaje.

Al desarrollar la tarea, y después de consultar brevemente google y no encontrar respuesta, contactarse de inmediato conmigo por favor para no perder tiempo y aprender lo más rápido posible.

2 Teoría


2.1 Vectores

Existen dos tipos de estructuras de una dimensión en R: vectores y listas. Los primeros son los clásicos vectores de las matemáticas: admiten sólo un tipo de dato; los segundos múltiples. Las columnas de una tabla (dataframe) son vectores.

R posee una serie de dataframes de prueba con los que se puede ejercitar. En éste Rpubs utilizaremos algunos.

Puromycin: Velocidad de reacción de una reacción enzimática a la puromicina, un antibiótico.

Despleguemos los primeros 5 registros:

head(Puromycin,5) 
##   conc rate   state
## 1 0.02   76 treated
## 2 0.02   47 treated
## 3 0.06   97 treated
## 4 0.06  107 treated
## 5 0.11  123 treated

2.1.1 Creación de vectores

El código siguiente crea dos vectores, uno numérico y otro categórico de tipo factor. Un factor es una lista con dos valores, generalmente un número y un string. Es útil su uso cuando trabajamos asignándole un código a una categoría.

x <- 1:10
y <- Puromycin$state

Los desplegamos simplemente llamándolos:

x
##  [1]  1  2  3  4  5  6  7  8  9 10
y
##  [1] treated   treated   treated   treated   treated   treated   treated  
##  [8] treated   treated   treated   treated   treated   untreated untreated
## [15] untreated untreated untreated untreated untreated untreated untreated
## [22] untreated untreated
## Levels: treated untreated

Para construir vectores arbitrarios usamos la función de concatenación o los dos puntos:

1:5
## [1] 1 2 3 4 5

Al revés:

5:1
## [1] 5 4 3 2 1

En dos partes:

c(1:5, 5:1)
##  [1] 1 2 3 4 5 5 4 3 2 1

En forma individual:

c(1, 5, -1, 4)
## [1]  1  5 -1  4

Como strings:

c("uno", "dos", "tres")
## [1] "uno"  "dos"  "tres"

Si un elemento no es asignado a un objeto, se muestra en pantalla.

2.1.1.1 Secuencias y repeticiones

Construyamos una secuencia del 1 al 4:

seq(1, 4)
## [1] 1 2 3 4

Que se repita 4 veces:

rep(1:4, 4)
##  [1] 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4

Ahora que una secuencia del 1 al 4 se despliegue en orden:

rep(1:4, each = 4)
##  [1] 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4

Del 1 al 4 2 veces:

rep(1:4, 2)
## [1] 1 2 3 4 1 2 3 4

Del 1 al 4 repitiendo cada uno dos veces primero:

rep(1:4, each = 2)
## [1] 1 1 2 2 3 3 4 4

Del 1 al 4 cada vez 2 veces:

rep(1:4, c(2,2,2,2))
## [1] 1 1 2 2 3 3 4 4

Del 1 al 4 en veces descendentes:

rep(1:4, times = 4:1)
##  [1] 1 1 1 1 2 2 2 3 3 4

Del 1 al 4 segun una orden de concatenacion:

rep(1:4, c(2,1,2,1))
## [1] 1 1 2 3 3 4

Del 1 al 4, con saltos cada 2 pero solo hasta la vez cuarta:

rep(1:4, each = 2, len = 4)
## [1] 1 1 2 2
rep(1:4, each = 2, len = 10)
##  [1] 1 1 2 2 3 3 4 4 1 1

Del 1 al 4 que se repita dos veces tres veces:

rep(1:4, each = 2, times = 3)
##  [1] 1 1 2 2 3 3 4 4 1 1 2 2 3 3 4 4 1 1 2 2 3 3 4 4

2.1.2 Inspección de vectores

Graficamos nuestra base de datos:

plot(Puromycin)

length cuenta columnas:

length(Puromycin)
## [1] 3

La función table cuenta los elementos de un vector por valor. Es una función sumamente importante para examinar vectores categóricos:

table(Puromycin) # ¡muy importante!
## , , state = treated
## 
##       rate
## conc   47 51 67 76 84 86 97 98 107 115 123 124 131 139 144 152 158 159 160 191
##   0.02  1  0  0  1  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0   0
##   0.06  0  0  0  0  0  0  1  0   1   0   0   0   0   0   0   0   0   0   0   0
##   0.11  0  0  0  0  0  0  0  0   0   0   1   0   0   1   0   0   0   0   0   0
##   0.22  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   1   0   1   0   0
##   0.56  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0   1
##   1.1   0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0   0
##       rate
## conc   200 201 207
##   0.02   0   0   0
##   0.06   0   0   0
##   0.11   0   0   0
##   0.22   0   0   0
##   0.56   0   1   0
##   1.1    1   0   1
## 
## , , state = untreated
## 
##       rate
## conc   47 51 67 76 84 86 97 98 107 115 123 124 131 139 144 152 158 159 160 191
##   0.02  0  1  1  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0   0
##   0.06  0  0  0  0  1  1  0  0   0   0   0   0   0   0   0   0   0   0   0   0
##   0.11  0  0  0  0  0  0  0  1   0   1   0   0   0   0   0   0   0   0   0   0
##   0.22  0  0  0  0  0  0  0  0   0   0   0   1   1   0   0   0   0   0   0   0
##   0.56  0  0  0  0  0  0  0  0   0   0   0   0   0   0   1   0   1   0   0   0
##   1.1   0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   1   0
##       rate
## conc   200 201 207
##   0.02   0   0   0
##   0.06   0   0   0
##   0.11   0   0   0
##   0.22   0   0   0
##   0.56   0   0   0
##   1.1    0   0   0

summary ofrece un pequeño resumen del contenido de un vector. De hecho, cuando aplicábamos summary a una tabla, obteníamos el summary de cada una de sus columnas:

summary(Puromycin)
##       conc             rate             state   
##  Min.   :0.0200   Min.   : 47.0   treated  :12  
##  1st Qu.:0.0600   1st Qu.: 91.5   untreated:11  
##  Median :0.1100   Median :124.0                 
##  Mean   :0.3122   Mean   :126.8                 
##  3rd Qu.:0.5600   3rd Qu.:158.5                 
##  Max.   :1.1000   Max.   :207.0

Desplegamos los primeros seis registros:

head(Puromycin)
##   conc rate   state
## 1 0.02   76 treated
## 2 0.02   47 treated
## 3 0.06   97 treated
## 4 0.06  107 treated
## 5 0.11  123 treated
## 6 0.11  139 treated

Desplegamos los últimos seis registros:

tail(Puromycin)
##    conc rate     state
## 18 0.11  115 untreated
## 19 0.22  131 untreated
## 20 0.22  124 untreated
## 21 0.56  144 untreated
## 22 0.56  158 untreated
## 23 1.10  160 untreated

Repitamos: La función table cuenta los elementos de un vector por valor. Es una función sumamente importante para examinar vectores categóricos:

table(Puromycin$state)
## 
##   treated untreated 
##        12        11

Repitamos: summary ofrece un pequeño resumen del contenido de un vector. De hecho, cuando aplicábamos summary a una tabla, obteníamos el summary de cada una de sus columnas.

2.1.3 Selecciones

Para seleccionar elementos de un vector se usa el corchete []. Pero, a diferencia de lo que ocurre con los dataframes, como los vectores son objetos unidimensionales, no se utiliza la coma para separar entre filas y columnas: no se utiliza la coma. Obviamente, el corchete sigue admitiendo no sólo los índices de los elementos que se quieren extraer, sino que además permite utilizar condiciones lógicas, etc.

Veamos algunos ejemplos:

Elevamos al cuadrado:

x <- 6
x <- x^2
x
## [1] 36

Seleccionamos los primeros tres elementos:

x <- seq(1,3,1)
y <- x[1:3]
y
## [1] 1 2 3

Tomamos el elemento primero y tercero:

x <- seq(1,3,1)
x[c(1,3)]
## [1] 1 3

Seleccionamos los mayores a 25:

x <- seq(1,30,1)
x[x > 25]
## [1] 26 27 28 29 30

Extraemos a la inversa los tres primeros elementos:

x <- seq(1,30,1)
x[3:1]
## [1] 3 2 1

Eliminamos los dos primeros valores:

x <- seq(1,30,1)
x[-(1:2)]
##  [1]  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
## [26] 28 29 30

Eliminamos el último valor:

x <- seq(1,30,1)
x[-length(x)]
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
## [26] 26 27 28 29

El corchete también permite seleccionar elementos de un vector por nombre. En efecto, en R se pueden asociar nombres a los elementos de un vector. Lo hace automáticamente, por ejemplo, table (para poder saber a qué etiqueta corresponde cada conteo):

z <- table(Puromycin$state)
z["untreated"]
## untreated 
##        11
z[c("treated", "untreated")]
## 
##   treated untreated 
##        12        11

Una propiedad muy importante del corchete es que permite, además de seleccionar, cambiar el contenido de los elementos seleccionados de un vector. Por ejemplo:

z <- 1:10
z[z < 5] <- 100
z
##  [1] 100 100 100 100   5   6   7   8   9  10

Reemplazar subselecciones es muy útil: permitirá, por ejemplo, cambiar las edades negativas por un valor con sentido, sustituir los nulos por un determinado valor por defecto, reemplazar los valores que excedan un tope por dicho tope, etc. El nombre de las columnas de una tabla también es un vector. Por eso, para cambiar el nombre de una columna podemos hacer lo siguiente:

mi.Puromycin <- Puromycin # una copia de iris
colnames(mi.Puromycin)[2] <- "Especie"
mi.Puromycin
##    conc Especie     state
## 1  0.02      76   treated
## 2  0.02      47   treated
## 3  0.06      97   treated
## 4  0.06     107   treated
## 5  0.11     123   treated
## 6  0.11     139   treated
## 7  0.22     159   treated
## 8  0.22     152   treated
## 9  0.56     191   treated
## 10 0.56     201   treated
## 11 1.10     207   treated
## 12 1.10     200   treated
## 13 0.02      67 untreated
## 14 0.02      51 untreated
## 15 0.06      84 untreated
## 16 0.06      86 untreated
## 17 0.11      98 untreated
## 18 0.11     115 untreated
## 19 0.22     131 untreated
## 20 0.22     124 untreated
## 21 0.56     144 untreated
## 22 0.56     158 untreated
## 23 1.10     160 untreated

Lo mismo ocurre con los nombres de un vector, aunque en este caso, la función correspondiente es names:

z <- table(mi.Puromycin$Especie)
names(z)
##  [1] "47"  "51"  "67"  "76"  "84"  "86"  "97"  "98"  "107" "115" "123" "124"
## [13] "131" "139" "144" "152" "158" "159" "160" "191" "200" "201" "207"
names(z)[1] <- "A"
names(z)
##  [1] "A"   "51"  "67"  "76"  "84"  "86"  "97"  "98"  "107" "115" "123" "124"
## [13] "131" "139" "144" "152" "158" "159" "160" "191" "200" "201" "207"

Frecuentemente se quiere muestrear un vector, es decir, obtener una serie de elementos al azar dentro de dicho vector. Para ello se utiliza la función sample:

sample(x, 4)
## [1] 26 24 20 29
sample(x, 100, replace = TRUE) # manera correcta
##   [1]  2  9  7 21 30 23 24  9  6 13 19 20 27 10 30  2 16  8  3  5 17  4 22 19 19
##  [26] 12  8 16 30  9  3 24 15 12  4  7 10 15  2 29 18  8 29 26  2 13 21 30 19 30
##  [51] 28  8 29  6  2 26 27  8  1 20 17 10  8 23 11 12  9 21 23 30 18 20  7 22  2
##  [76] 28  8 12 28  6  5  4 28 28  3 26  4 11  6 30 18 29  7 12 22 23 18 25 21 17

La función sample trata el vector como una urna y a sus elementos como bolas contenidas en ella que va extrayendo al azar. Obviamente, es incapaz de extraer más elementos de los que contiene la urna. Pero existe el la opción de que el muestreo se realice con reemplazamiento, i.e., de modo que cada vez que sample extraiga una bola, la reintroduzca en la urna.

El muestreo de vectores es fundamental en diversos ámbitos.

sample(x, 100) # ¡falla!

2.1.4 Orden

Existen tres funciones fundamentales relacionadas con la ordenación de vectores: order, sort y rank. sort ordena los elementos de un vector, i.e., crea una copia de dicho vector con sus elementos ordenados.

x <- c(4, 5, 3, 2, 1, 2)
sort(x)
## [1] 1 2 2 3 4 5

La función order, que ya vimos cuando ordenamos tablas, es tal que sort(x) es lo mismo que x[order(x)]. Es decir, devuelve los índices de los elementos del vector de menor a mayor:

x
## [1] 4 5 3 2 1 2
order(x)
## [1] 5 4 6 3 1 2
x[order(x)]
## [1] 1 2 2 3 4 5

El código anterior muestra cómo para ordernar x hay que tomar primero el elemento quinto elemento de x; luego, el cuarto; después, el sexto, etc. La función rank indica la posición de los elementos de un vector: el primero, el segundo, etc.

rank(x)
## [1] 5.0 6.0 4.0 2.5 1.0 2.5
rank(x, ties = "first")
## [1] 5 6 4 2 1 3

Si x contuviese los tiempos de los velocistas en los 100 metros lisos, rank(x) nos indicaría quién es el primero en llegar a la meta, quién es el segundo, etc.

rank(x) es una transformación no lineal de x que puede ser útil para normalizar datos en algunos contextos.

2.1.5 Operaciones matemáticas y vectorización

R puede ser usado como una calculadora:

2+2
## [1] 4
x <- 4*(3+5)^2
x / 10
## [1] 25.6

En R se puede operar sobre vectores igual que se opera sobre números. De hecho, en R, un número es un vector numérico de longitud 1:

c(length(2), length(x))
## [1] 1 1

Así que se pueden hacer cosas tales como

x <- 1:10
2*x
##  [1]  2  4  6  8 10 12 14 16 18 20
2*x + 1
##  [1]  3  5  7  9 11 13 15 17 19 21
x^2
##  [1]   1   4   9  16  25  36  49  64  81 100
x*x
##  [1]   1   4   9  16  25  36  49  64  81 100

Operaciones como las anteriores están vectorizadas, i.e., admiten un vector como argumento y operan sobre cada uno de los elementos. Generalmente, las operaciones vectorizadas son muy rápidas en R. Muchos problemas de rendimiento en R se resuelven, de hecho, utilizando versiones vectorizadas del código ineficiente.

La operación a la que se refiere el ejercicio anterior se denomina reciclado de vectores. Cuando se opera con dos vectores (por ejemplo, para multiplicarlos) con longitudes distintas, el más corto se recicla (es decir, se repite) tantas veces como sea necesario hasta alcanzar la longitud del más largo. Si la longitud del más corto no divide exactamente la del más largo (p.e., uno tiene longitud 10 y otro, longitud 3), R recorta la parte reciclada sobrante y lanza un warning. El lector está invitado a consultar cómo construir con R una calculadora de hipotecas, que ilustra el uso de la vectorización en un problema menos trivial que los anteriores, en el capítulo dedicado a ejemplos de uso.

3 Tareas

Tarea 1.1.1

Crea el vector que numera las filas de iris (es decir, que contenga los números del 1 hasta el número de filas de iris).

Tarea 1.1.2

Crea el patrón 1, 1.1, 1.2,…, 2. Existen varias maneras de hacerlo. Una de ellas es utilizar el argumento by de seq.

Tarea 1.1.3

Selecciona las columnas 1, 2 y 5 de iris

Tarea 1.1.4

Selecciona las filas 1:4 y 100:104 de iris.

Tarea 1.1.5

Usa un vector de texto para seleccionar las columnas Wind y Temp de airquality.

Tarea 1.1.6

Crea una tabla que sea la primera fila de iris repetida 100 veces.

Tarea 1.1.7

En CO2, cuenta cuántas filas corresponden a cada tipo de planta.

Tarea 1.1.8

Ejecuta e interpreta table(table(CO2$conc)). Nota: table(table(x)) es una operación muy frecuente y útil.

Tarea 1.1.9

Selecciona todos los elementos de un vector menos menos los dos últimos.

Tarea 1.1.10

Implementa la función diff (las diferencias entre cada valor de un vector y el que lo precede) a mano. Nota: la función diff existe en R; pruébala en caso de duda.


Tarea 1.1.11

Cambia (en una sola expresión) los nombres de las dos primeras columnas de mi.iris por su traducción al español.

Tarea 1.1.12

Muestrea iris, es decir, extrae (p.e., 30) filas al azar de dicha tabla. Pista: recuerda que ordenar era seleccionar ordenadamente; de igual manera, en una tabla, muestrear será…

Tarea 1.1.13

Parte iris en dos partes iguales (75 observaciones cada uno) con las filas elegidas al azar (¡y complementarias!).

Tarea 1.1.14

Si x contuviese el número de puntos obtenidos en la liga de fútbol por los distintos equipos, ¿cómo usarías rank para determinar cuál es el campeón?

Tarea 1.1.15

¿Qué otros tipos de ties existen? ¿Qué hacen?

Tarea 1.1.16

Comprueba que rank(x, ties = ‘first’) es equivalente a order(order(x)).

Tarea 1.1.17

Comprueba que order(order(order(x))) es equivalente a order(x).

Tarea 1.1.18

Ejecuta e interpreta tail(sort(table(CO2$uptake))). ¿Qué utilidad le ves a la expresión anterior?

Tarea 1.1.19

Comprueba que log es una función vectorizada aplicándosela a x.

Tarea 1.1.20

Calcula el valor medio de la longitud de los pétalos de iris usando mean.


Tarea 1.1.21

Repite el ejercicio anterior usando sum y length.

Si x <- 1:10 e y <- 1:2, ¿cuánto vale x * y? ¿Qué pasa si y <- 1:3?