Capítulo5 Calculadora sofisticada
Fecha de la última revisión
## [1] "2026-09-09"
Activar los siguientes paquetes
El tema proviene de los siguientes sitios.
English: https://r4ds.had.co.nz/workflow-basics.html
Español: https://es.r4ds.hadley.nz/04-workflow-basics.html
5.2 R como calculadora, y por qué eso importa
Lo primero que hace R es aritmética, y conviene empezar por ahí porque quita el miedo: la consola de R es, entre otras cosas, una calculadora muy buena. Todo lo que escribas en ella se evalúa y se devuelve el resultado.
Pero hay una diferencia importante con la calculadora del teléfono, y es la que
convierte a R en una herramienta de análisis: R no opera sobre números, opera
sobre vectores. Cuando escribes 2 + 2, R no está sumando dos números; está
sumando dos vectores de largo uno. Esa idea, que al principio parece un
tecnicismo, es la que permite escribir edad * 2 y multiplicar de golpe las
edades de mil personas sin escribir un solo ciclo. Casi todo lo que hace R por
debajo es esto.
Los operadores aritméticos son los que uno espera, más dos que casi nadie conoce al principio y que resultan utilísimos:
| Operador | Qué hace | Ejemplo | Resultado |
|---|---|---|---|
+ - * / |
suma, resta, multiplicación, división | 7 / 2 |
3.5 |
^ |
potencia | 2 ^ 10 |
1024 |
%% |
residuo de la división entera | 7 %% 2 |
1 |
%/% |
cociente de la división entera | 7 %/% 2 |
3 |
El residuo %% sirve para preguntas del tipo “¿es par?” (x %% 2 == 0) o
“¿es múltiplo de 5?”, y %/% sirve para partir un número en unidades, por
ejemplo separar 1730 en la hora 17 y los minutos 30. Los dos aparecen en
los capítulos de transformación de datos.
El orden de las operaciones es el de siempre: primero las potencias, después las
multiplicaciones y divisiones, y por último las sumas y restas. Los paréntesis
mandan sobre todo lo demás, y la recomendación es usarlos aunque no hagan falta:
(a + b) / 2 se lee sin pensar, a + b / 2 hay que pensarlo, y además significa
otra cosa.
En RStudio, Ctrl y Enter (Cmd y Enter en Mac) ejecuta la línea donde está
el cursor y salta a la siguiente. Es el atajo que más se usa en todo el curso.
5.2.4 Log natural y a base 10
## [1] 4.60517
## [1] 2
Cuidado con este resultado, porque sorprende a todo el mundo: log(100) no
devuelve 2. En R, log() es el logaritmo natural, en base e, así que
log(100) es 4.605. Para el logaritmo en base 10 hay que usar log10(), y para
base 2, log2(). También se puede escribir log(100, base = 10).
No es un capricho de R: en matemáticas y en estadística “log” significa logaritmo natural, y son las calculadoras de bolsillo las que se apartaron de la convención al usar “log” para base 10. Vale la pena fijarlo ahora, porque en biología los dos se usan mucho y confundirlos cambia los resultados por un factor de 2.3.
Funciones matemáticas de uso común.
sqrt(x): raíz cuadrada.exp(x): la exponencial, la operación inversa delog().log(x): logaritmo natural;log10(x)ylog2(x)para las bases 10 y 2.abs(x): valor absoluto.round(x, n): redondea andecimales.sin(),cos(),tan(): trigonometría, siempre en radianes, no en grados. Por eso el ejemplo de arriba usapi/3y no60.
5.2.5 Asignaciones de variables
Para asignar un valor puedes usar <- o =, pero para comparar dos cosas se usa == (doble igual). Confundir = con == es uno de los errores más comunes al empezar. Encontrarás más errores frecuentes y cómo resolverlos en el capítulo Errores comunes (14).
## [1] 4
## [1] 3
## [1] 1.333333
Las dos flechas funcionan, pero no son equivalentes por convención. La norma
en R, y la que se sigue en todo este libro, es usar <- para asignar y reservar
el = para dar valores a los argumentos dentro de una función, como en
seq(1, 10, by = 2). Escribir las dos cosas con el mismo símbolo hace más difícil
leer el código de un vistazo.
Y hay un tercer símbolo que se parece y no tiene nada que ver: ==, el doble
igual, que pregunta si dos cosas son iguales y devuelve TRUE o FALSE.
## [1] TRUE
## [1] FALSE
Confundir = con == dentro de un filter() es de los errores más frecuentes
del curso, y el mensaje que da R en ese caso no es nada claro.
El atajo de teclado para <- en RStudio es Alt y el signo de menos (Option y
menos en Mac). Aprenderlo el primer día ahorra muchísimo tiempo, porque esa
flecha se escribe cientos de veces.
5.2.6 Variables
- la función “seq” para secuencia
seq(), c(), length(): crear y medir vectores.
c(1, 2, 3): combina valores en un vector;11:20genera una secuencia consecutiva.seq(101, 110): secuencia con más control (inicio, fin, paso).length(x): cuántos elementos tiene un vector.
Un vector es una secuencia de valores del mismo tipo. Esa última parte
importa: si mezclas un número con un texto, R no da error, sino que convierte
todo al tipo más general, que es el texto. c(1, 2, "tres") devuelve
"1" "2" "tres", y de pronto no puedes sumar. Es una fuente de errores
silenciosos cuando se importa una columna de Excel que traía una nota escrita en
medio de los números.
Hay tres maneras de construir una secuencia y conviene distinguirlas:
c(3, 7, 2)combina los valores que le des, en el orden que se los des.11:20genera los consecutivos de 11 a 20, de uno en uno. Es rápido de escribir y no admite paso.seq(101, 110)hace lo mismo, pero admite argumentos:seq(0, 100, by = 5)va de cinco en cinco, yseq(0, 1, length.out = 11)reparte once valores entre 0 y 1.
## [1] 101 102 103 104 105 106 107 108 109 110
- variables asignada
## [1] 11 12 13 14 15 16 17 18 19 20
5.2.7 Unir variables en un data frame
## edad_nd edad_uprh
## 1 101 11
## 2 102 12
## 3 103 13
## 4 104 14
## 5 105 15
## 6 106 16
## 7 107 17
## 8 108 18
## 9 109 19
## 10 110 20
## edad_nd edad_uprh diff
## 1 101 11 90
## 2 102 12 90
## 3 103 13 90
## 4 104 14 90
## 5 105 15 90
## 6 106 16 90
## 7 107 17 90
## 8 108 18 90
## 9 109 19 90
## 10 110 20 90
## edad_nd edad_uprh diff tres
## 1 101 11 90 1331
## 2 102 12 90 1728
## 3 103 13 90 2197
## 4 104 14 90 2744
## 5 105 15 90 3375
## 6 106 16 90 4096
## 7 107 17 90 4913
## 8 108 18 90 5832
## 9 109 19 90 6859
## 10 110 20 90 8000
Aquí pasan dos cosas que vale la pena nombrar. La primera es que
data.frame(edad_nd, edad_uprh) pega dos vectores como columnas, y toma los
nombres de las columnas de los nombres de los objetos. La segunda es que
edad$diff <- edad$edad_nd - edad$edad_uprh hace la resta elemento a
elemento, de la primera fila con la primera, la segunda con la segunda, y así.
No hace falta ningún ciclo. A esto se le llama operación vectorizada, y es la
manera natural de trabajar en R.
Lo mismo pasa con edad$edad_uprh^3: eleva al cubo los diez valores de un tirón.
Esta es la forma de R base, con $ y data.frame(). En los próximos capítulos
haremos exactamente lo mismo con mutate() de dplyr, que se lee mucho mejor:
mutate(edad, diff = edad_nd - edad_uprh). Las dos formas producen el mismo
resultado, y conviene reconocer las dos porque hay muchísimo código antiguo
escrito con $.
5.2.8 Errores cuando a variables no tienen la misma cantidad de entradas
## [1] 101 102 103 104 105 106 107 108 109 110 111
- variables asignada
## [1] 11 12 13 14 15 16 17 18 19 20 NA
5.2.9 Unir variables en un data frame
## edad_nd_1 edad_uprh_1
## 1 101 11
## 2 102 12
## 3 103 13
## 4 104 14
## 5 105 15
## 6 106 16
## 7 107 17
## 8 108 18
## 9 109 19
## 10 110 20
## 11 111 NA
Este es un ejemplo preparado para enseñar algo incómodo. Los dos vectores tienen
once elementos: seq(101, 111) son once números, y c(11:20, NA) son diez
números más un NA. Como coinciden en largo, data.frame() los une sin
protestar.
Si no coincidieran, pasarían dos cosas distintas según los números. Si el largo del mayor es múltiplo exacto del menor, R recicla el corto: lo repite hasta completar, sin decir nada. Si no es múltiplo, da un error. El reciclaje silencioso es una de las trampas clásicas de R: el código corre, no hay advertencia, y los datos quedan mal.
NA significa “no disponible”, un valor que falta. No es un cero ni un espacio
en blanco: es la manera que tiene R de decir “aquí no sé qué hay”. Los NA se
contagian a casi cualquier operación (5 + NA es NA), y tienen su propio
capítulo más adelante.
5.2.10 Cuantos valores hay en una variable
## [1] 10
## [1] 10
## [1] 4
Fíjate bien en las tres respuestas, porque la tercera sorprende. length() sobre
un vector devuelve cuántos elementos tiene: diez en los dos primeros casos.
Pero edad no es un vector, es un data.frame, y un data.frame en R es en
realidad una lista de columnas. Así que length(edad) no devuelve el número
de filas: devuelve el número de columnas.
Para las tablas hay que usar las funciones específicas: nrow() para las filas,
ncol() para las columnas y dim() para las dos. Usar length() con una tabla
esperando el número de filas es un error que puede pasar desapercibido durante
mucho rato, porque devuelve un número perfectamente razonable, solo que el
equivocado.
5.2.11 Seleccionar solamente parte de los datos de un archivo
- Primero visualizar los datos
## # A tibble: 234 × 11
## fabricante modelo cilindrada anio cilindros transmision traccion ciudad
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int>
## 1 audi a4 1.8 1999 4 auto(l5) d 18
## 2 audi a4 1.8 1999 4 manual(m5) d 21
## 3 audi a4 2 2008 4 manual(m6) d 20
## 4 audi a4 2 2008 4 auto(av) d 21
## 5 audi a4 2.8 1999 6 auto(l5) d 16
## 6 audi a4 2.8 1999 6 manual(m5) d 18
## 7 audi a4 3.1 2008 6 auto(av) d 18
## 8 audi a4 quattro 1.8 1999 4 manual(m5) 4 18
## 9 audi a4 quattro 1.8 1999 4 auto(l5) 4 16
## 10 audi a4 quattro 2 2008 4 manual(m6) 4 20
## # ℹ 224 more rows
## # ℹ 3 more variables: autopista <int>, combustible <chr>, clase <chr>
5.2.11.1 Seleccionar los carros que tienen cilindros igual a 8 (solamente)
El pipe %>% lo creó Stefan Milton Bache en el paquete magrittr (2014); su nombre juega con el cuadro de Magritte “Ceci n’est pas une pipe”. Desde 2021, R incluye su propio pipe nativo |>.
La función de Pipe. %>% o |>
El pipe se lee como la palabra “después”. millas |> select(cilindros) se
lee “toma millas, después selecciona cilindros”. Lo que hace es pasar lo
que tiene a la izquierda como primer argumento de la función que está a la
derecha, así que x |> f(y) es exactamente lo mismo que f(x, y).
Parece un detalle de escritura y cambia por completo cómo se lee un análisis. Sin pipe, las operaciones encadenadas se escriben de dentro hacia afuera y hay que leerlas al revés. Con pipe se escriben en el orden en que ocurren, de arriba abajo, como los pasos de una receta. El pipe tiene su propio capítulo más adelante; aquí solo hace falta reconocerlo.
Hay dos versiones, %>% (del paquete magrittr, que viene con el tidyverse) y
|> (de R base, desde 2021). Para lo que hacemos en este curso son
intercambiables. El atajo de teclado en RStudio es Ctrl, Shift y M.
select() y filter() (paquete dplyr): elegir columnas y filas.
select(columna): se queda con las columnas indicadas.filter(condición): se queda con las filas que cumplen una condición (p. ej.cilindros == 8).- El pipe
|>/%>%: encadena pasos, pasando el resultado de uno como entrada del siguiente.
## # A tibble: 234 × 11
## fabricante modelo cilindrada anio cilindros transmision traccion ciudad
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int>
## 1 audi a4 1.8 1999 4 auto(l5) d 18
## 2 audi a4 1.8 1999 4 manual(m5) d 21
## 3 audi a4 2 2008 4 manual(m6) d 20
## 4 audi a4 2 2008 4 auto(av) d 21
## 5 audi a4 2.8 1999 6 auto(l5) d 16
## 6 audi a4 2.8 1999 6 manual(m5) d 18
## 7 audi a4 3.1 2008 6 auto(av) d 18
## 8 audi a4 quattro 1.8 1999 4 manual(m5) 4 18
## 9 audi a4 quattro 1.8 1999 4 auto(l5) 4 16
## 10 audi a4 quattro 2 2008 4 manual(m6) 4 20
## # ℹ 224 more rows
## # ℹ 3 more variables: autopista <int>, combustible <chr>, clase <chr>
## [1] "fabricante" "modelo" "cilindrada" "anio" "cilindros"
## [6] "transmision" "traccion" "ciudad" "autopista" "combustible"
## [11] "clase"
## # A tibble: 70 × 1
## cilindros
## <int>
## 1 8
## 2 8
## 3 8
## 4 8
## 5 8
## 6 8
## 7 8
## 8 8
## 9 8
## 10 8
## # ℹ 60 more rows
Nota el orden: primero select() y después filter(). Funciona, pero solo
porque la columna que se filtra es la única que se conservó. Si hubiéramos
seleccionado únicamente modelo y después intentado filtrar por cilindros, R
daría error, porque esa columna ya no existe en la tabla. La costumbre segura es
filtrar primero y seleccionar después.
Nota también el dplyr:: delante de las dos funciones. No hace falta si el
tidyverse está cargado, pero se pone aquí a propósito, porque filter() es uno de
los nombres más disputados de R: el paquete stats, que viene activado siempre,
tiene su propia filter() para series de tiempo.
5.2.11.2 Seleccionar los diamantes mayor de 3 quilate
## # A tibble: 32 × 1
## quilate
## <dbl>
## 1 3.01
## 2 3.11
## 3 3.01
## 4 3.05
## 5 3.02
## 6 3.01
## 7 3.65
## 8 3.24
## 9 3.22
## 10 3.5
## # ℹ 22 more rows
Vale la pena mirar cuántas filas devuelve esto: de casi 54,000 diamantes, muy pocos pasan de tres quilates. Filtrar es la manera de hacerse esa pregunta, y el número de filas que queda suele ser la primera respuesta interesante de un análisis.
5.2.11.3 Seleccionar los diamantes con igual o mayor de 4000 precio
## # A tibble: 6 × 1
## precio
## <int>
## 1 4000
## 2 4001
## 3 4001
## 4 4001
## 5 4001
## 6 4002
5.2.11.4 Contabiliza cuantos diamantes tienen un valor de $4000 o más
## [1] 19380
nrow() sobre el resultado de un filtro es el patrón más común de todo el curso:
contar cuántos casos cumplen una condición. Es la respuesta a “¿cuántos
diamantes cuestan 4,000 o más?”, “¿cuántos vuelos salieron tarde?”, “¿cuántas
plantas florecieron?”. Si además quieres la proporción, divide entre el total:
nrow(dia_4000) / nrow(diamantes).
Antes de calcular nada sobre una tabla filtrada, mira siempre cuántas filas
quedaron. Si quedan cero, cualquier promedio que calcules va a ser NaN y el
error va a aparecer tres pasos más adelante, donde ya no se entiende. Si quedan
todas, probablemente la condición no filtró nada y hay que revisarla.
5.3 Ejercicios del capítulo
Sobre los ejercicios de este capítulo. Cada ejercicio se entrega con tres
cosas: el script, el resultado (que el bloque corra) y una explicación
en palabras. Los primeros ejercicios trabajan con vectores que construyes tú;
los últimos usan vuelos del paquete datos, no millas ni diamantes, que son
los conjuntos con los que se enseña en el capítulo. La hoja completa para entregar
está en Ejercicios/Ejercicios_Capitulo_05_calculadora.Rmd.
5.3.1 Ejercicio 1. El residuo y el cociente
El vector horas <- c(517, 533, 542, 554, 558, 1730, 2359) guarda horas escritas
como números, al estilo de los horarios de vuelo: 1730 son las 5:30 de la tarde.
Sepáralas en dos vectores, uno con la hora y otro con los minutos, usando
%/% y %%.
Verificación: los dos vectores deben tener 7 elementos. Para 1730 tienes
que obtener hora 17 y minuto 30; para 517, hora 5 y minuto 17.
En palabras: explica en una oración qué hace cada uno de los dos operadores,
y por qué 2359 no se puede convertir a minutos desde medianoche con una simple
división entre 100.
5.3.2 Ejercicio 2. Logaritmos
Calcula el logaritmo de 1000 en base natural, en base 10 y en base 2, de tres
maneras distintas. Después comprueba que exp() deshace el logaritmo natural.
Verificación: en base 10 tiene que dar exactamente 3. El logaritmo natural
tiene que dar un número cercano a 6.9, y exp() de ese número tiene que devolver
1000 (o algo indistinguible de 1000).
En palabras: un compañero calculó log(1000), obtuvo 6.9 y dijo que R estaba
malo porque “el log de mil es tres”. Explícale qué pasó.
5.3.3 Ejercicio 3. Vectores y tipos
Crea tres vectores: uno con los números del 1 al 10, uno con los números pares del
2 al 20 (usando seq(), no escribiéndolos a mano), y uno que mezcle números y
texto, por ejemplo c(1, 2, "tres", 4). Comprueba el tipo de cada uno con
class() y el largo con length().
Verificación: los dos primeros deben tener 10 elementos cada uno. El
tercero debe tener class() igual a "character", no "numeric".
En palabras: ¿por qué el tercer vector es de texto si tres de sus cuatro valores son números? Explica qué problema causaría eso si esa fuera una columna importada de Excel donde alguien escribió “no medido” en una celda.
5.3.4 Ejercicio 4. length() y las tablas
Datos: vuelos. Corre length(vuelos), nrow(vuelos) y ncol(vuelos) y compara
los tres resultados.
Verificación: nrow() tiene que dar 336,776 y ncol() tiene que dar
19. length() tiene que coincidir con uno de los dos.
En palabras: ¿con cuál de los dos coincide length(), y por qué? Usa en tu
respuesta la palabra “lista”.
5.3.5 Ejercicio 5. Filtrar y contar
Datos: vuelos. Cuenta cuántos vuelos salieron con más de dos horas de
retraso (atraso_salida, que está en minutos), y calcula qué proporción del
total representan.
Verificación: el número de filas filtradas tiene que ser mucho menor que
336,776, y la proporción tiene que quedar entre 0 y 1. Comprueba también cuántos
NA hay en atraso_salida antes de filtrar.
En palabras: los vuelos cancelados tienen NA en atraso_salida y
filter() los descarta. ¿Tu proporción está calculada sobre el total de vuelos o
sobre el total de vuelos que sí salieron? ¿Cuál de las dos es la correcta para
contestar “¿qué porcentaje de vuelos sale muy tarde?”?
5.3.6 Ejercicio 6. Una columna nueva
Datos: vuelos. Usando la forma de R base ($ y <-), crea sobre una copia de
la tabla una columna nueva llamada velocidad que sea la distancia dividida
entre el tiempo_vuelo, multiplicada por 60 para que quede en millas por hora.
Después mira el máximo y el mínimo de esa columna.
Verificación: la tabla copiada tiene que tener 20 columnas. El máximo y el
mínimo tienen que ser números, no NA: si te salen NA, usa na.rm = TRUE y
explica por qué hizo falta.
En palabras: el valor máximo probablemente sea absurdo para un avión comercial. Da una explicación posible que no sea “el avión iba a esa velocidad”.
5.3.7 Ejercicio 7 (BONO). El reciclaje silencioso
Crea a <- 1:10 y b <- c(1, 2), y suma a + b. Después crea d <- c(1, 2, 3)
y suma a + d. Corre los dos y observa la diferencia.
Verificación: la primera suma funciona y devuelve 10 valores. La segunda
da una advertencia. Usa warning = TRUE en las opciones del bloque para que
la advertencia se vea en el documento.
En palabras: explica qué hizo R en el primer caso, por qué no avisó, y por qué ese silencio es más peligroso que la advertencia del segundo caso.