Una parte esencial en programación son los operadores relacionales que comparan datos numéricos, de serie de caracteres o lógicos. El resultado de la comparación, ya sea Verdadero (1) o falso (0), puede utilizarse para tomar una decisión referente al flujo del programa.
Los operadores son
<><=>===!=El resultado de la comparación, ya sea Verdadero (1) o falso (0), puede utilizarse para tomar una decisión referente al flujo del programa
# Logico
TRUE == FALSE
## [1] FALSE
TRUE != FALSE
## [1] TRUE
TRUE == 1
## [1] TRUE
TRUE <= FALSE
## [1] FALSE
TRUE > FALSE
## [1] TRUE
# Numerico
-6 * 14 != 17 - 101
## [1] FALSE
3 == (2 + 1)
## [1] TRUE
(1 + 2) > 4
## [1] FALSE
-6 * 5 + 2 >= -10+1
## [1] FALSE
# Strings
"useR" == "user"
## [1] FALSE
"Rchitect" != "rchitect"
## [1] TRUE
"dog" < "Cats"
## [1] FALSE
"raining" <= "raining dogs"
## [1] TRUE
Se puede hacer comparaciones entre vectores. A continuación, se presentan los datos que muestran las visitas diarias a los perfiles de Linkedin y Facebook de una persona
linkedin <- c(16, 9, 13, 5, 2, 17, 14)
facebook <- c(17, 7, 5, 16, 8, 13, 14)
linkedin > 15
## [1] TRUE FALSE FALSE FALSE FALSE TRUE FALSE
linkedin <= 5
## [1] FALSE FALSE FALSE TRUE TRUE FALSE FALSE
linkedin > facebook
## [1] FALSE TRUE TRUE FALSE FALSE TRUE FALSE
También se pueden comparar matrices. Con los vectores anteriores se crea una matriz.
views <- matrix(c(linkedin, facebook),
nrow = 2,
byrow = TRUE)
views
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] 16 9 13 5 2 17 14
## [2,] 17 7 5 16 8 13 14
views == 13
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] FALSE FALSE TRUE FALSE FALSE FALSE FALSE
## [2,] FALSE FALSE FALSE FALSE FALSE TRUE FALSE
views <= 14
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] FALSE TRUE TRUE TRUE TRUE FALSE TRUE
## [2,] FALSE TRUE TRUE FALSE TRUE TRUE TRUE
Los operadores lógicos pueden crear condiciones compuestas en una fórmula, como que se deben cumplir dos o más condiciones para elegir un determinado método de cálculo. Con los operadores lógicos, puede describir estas combinaciones de condiciones mediante
&|!.A continuación se usan los vectores de Linkedin y Facebook, y la
matriz views.
linkedin
## [1] 16 9 13 5 2 17 14
facebook
## [1] 17 7 5 16 8 13 14
views
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] 16 9 13 5 2 17 14
## [2,] 17 7 5 16 8 13 14
red_social <- c("Linkedin", "Facebook")
dias <- c("Lunes","Martes","Miercoles","Jueves","Viernes","Sabado","Domingo")
rownames(views) <- red_social
colnames(views) <- dias
views
## Lunes Martes Miercoles Jueves Viernes Sabado Domingo
## Linkedin 16 9 13 5 2 17 14
## Facebook 17 7 5 16 8 13 14
linkedin > 10 & facebook < 10
## [1] FALSE FALSE TRUE FALSE FALSE FALSE FALSE
linkedin >= 12 | facebook >= 12
## [1] TRUE FALSE TRUE TRUE FALSE TRUE TRUE
views es mayor a 11 y menor o
igual a 14?visits <- views > 11 & views <= 14
visits
## Lunes Martes Miercoles Jueves Viernes Sabado Domingo
## Linkedin FALSE FALSE TRUE FALSE FALSE FALSE TRUE
## Facebook FALSE FALSE FALSE FALSE FALSE TRUE TRUE
sum() con
TRUEsum(visits, na.rm = TRUE)
## [1] 4
sum() con
TRUEsum(visits, na.rm = FALSE)
## [1] 4
Una de las partes más poderosas de R se encuentra en su gran número de funciones cuyo objetivo es agilizar el análisis estadístico, facilitar el manejo de las bases de datos, graficar, crear mapas, etc.
R cuenta con funciones predefinidas dentro de su entorno interno que, aunque elementales, son de lo más útiles.
mean()avg_li <- mean(linkedin)
avg_li
## [1] 10.85714
median()med_li <- median(linkedin)
med_li
## [1] 13
var()var_li <- var(linkedin)
var_li
## [1] 32.47619
sd()sd_li <- sd(linkedin)
sd_li
## [1] 5.698789
Es posible llevar a cabo operaciones y funciones al mismo tiempo.
avg_sum <- mean(linkedin + facebook)
avg_sum
## [1] 22.28571
sd_sum <- sd(linkedin + facebook)
sd_sum
## [1] 8.340949
abs.x <- mean(abs(linkedin - facebook),
na.rm = TRUE)
x
## [1] 4.571429
na.rm específica si se quitan o se dejan los valores
nulos de un vector o una base de datos, por defecto la función está en
FALSE.
Una forma de crear vectores personalizados es a través de la función
seq()
seq(1, 15, by = 1)
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
seq(1, 100, by = 10)
## [1] 1 11 21 31 41 51 61 71 81 91
seq(1, 10, length.out = 5)
## [1] 1.00 3.25 5.50 7.75 10.00
La función rep() permite repetir elementos
rep(2, 10)
## [1] 2 2 2 2 2 2 2 2 2 2
rep("Hola", 4)
## [1] "Hola" "Hola" "Hola" "Hola"
rep(c(1, 2, 3), 2)
## [1] 1 2 3 1 2 3
rep(1:4, each = 3)
## [1] 1 1 1 2 2 2 3 3 3 4 4 4
El problema con estas funciones es que ya están predeterminadas a trabajar con los objetos en cuestión, es decir, los parámetros de la función son constantes y, por ende, solo puede ser usada para los vectores de Linkedin y Facebook.
Si se tuviera un tercer vector, por ejemplo, twitter, y
se imprimiera de nuevo x, el resultado no variaría dado
que, el nuevo vector no forma parte de la función original.
Se podría cambiar la información del vector facebook por
la de twitter, pero esto haría que se perdiera la
información del primer vector en favor del segundo, lo que generalmente
no es recomendable.
También se podría cambiar simplemente facebook por
twitter desde el código original para operar la función,
pero esto puede ser poco práctico cuando se tienen muchos vectores a
sustituir.
Por lo tanto, en muchas ocasiones, será mejor crear funciones propias.
En R es posible declarar una función con la palabra
function() seguida de un par de {} que
contendrán los argumentos de la función. Se puede hacer toda clase de
operaciones y procedimientos mediante una función, pero los resultados
de esta no se mostrarán a menos que la misma sea llamada.
nombre_funcion <- function(){
print("Hola mundo")
}
nombre_funcion()
## [1] "Hola mundo"
Las funciones sin parámetros son aquellas que no
contienen objetos al interior de los paréntesis (), por lo
que básicamente trabajan con constantes.
num_views_f <- 12
num_views_l <- 14
suma_l_f <- function(){#Parentesis vacios
return(num_views_l + num_views_f)
}
suma_l_f()
## [1] 26
Esta función se llama suma_l_f(), cada vez que se le
llama se sumaran de forma automática los objetos que la componen.
div_l_f <- function(){
return(num_views_l / num_views_f)
}
div_l_f()
## [1] 1.166667
Esta función se llama div_l_f(), cada vez que se le
llama se sumaran de forma automática los objetos que la componen.
dado <- function(){
caras <- sample(1:6, size = 1)
caras
}
dado()
## [1] 3
Es posible guardar la función en otro objeto y usarla.
d <- dado()
d
## [1] 3
El objeto d contiene a la función dado, y
cada vez que se le llama se realizara la tarea de simular el lanzamiento
de un dado, pero solamente eso. Si lo que se busca es crear una función
que admite variables es necesario declarar los parámetros de la
función.
a <- 1:50
b <- 2
potencia_a_b <- function(){
return(a^b)
}
potencia_a_b()
## [1] 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225
## [16] 256 289 324 361 400 441 484 529 576 625 676 729 784 841 900
## [31] 961 1024 1089 1156 1225 1296 1369 1444 1521 1600 1681 1764 1849 1936 2025
## [46] 2116 2209 2304 2401 2500
Cuando se declaran los parámetros la función puede recibir variables, al interior de los paréntesis, con las que operar.
pow_two <- function(a){ #Parámetros de entrada de la funcion
a^2 #Cuerpo de la función
}
La función admite un parámetro a y, entre llaves
{}, colocamos el cuerpo de la función que eleva ese
parámetro al cuadrado. Como se ha establecido un parámetro a manera de
variable, cada vez que se llame la función pow_two, esta puede
cambiar.
pow_two(12)
## [1] 144
Es posible colocar más de un parámetro en una función.
suma <- function(x, y){
q <- x + y
return(q)
}
Al interior de ella se encuentra el cuerpo de la misma, es decir, aquello que la función debe realizar y, finalmente,
w <- suma(10, 40)
w
## [1] 50
Una vez que la función ha sido construida puede ser llamada, siempre y cuando se cubra el requisito de llenar todos los parámetros necesarios para operarla. Además, es posible guardar el resultado en un objeto.
Como las variables x y y no fueron declaradas de antemano se puede introducir cualquier tipo de parámetro, siempre y cuando no rompa la lógica de la operación en el cuerpo de la función.
a <- suma(20, 80)
a
## [1] 100
Estas funciones pueden ser combinadas con todas aquellas pertenecientes a las distintas librerías de R.
sum_abs <- function (b,c){
abs(b) + abs(c)
}
sum_abs(-2,3)
## [1] 5
También es posible combinar las funciones con strings para obtener resultados más intuitivos.
pow_two <- function(x) {
y <- x ^ 2
print(paste(x, "elevado al cuadrado es", y))
return(y)
}
pow_two(5)
## [1] "5 elevado al cuadrado es 25"
## [1] 25
Esto mismo aplica para los funciones sin parámetros y las funciones con parámetros por defecto.
Es posible construir una función con parámetros por defecto, es decir, una función que permita indicar los datos de entrada variables y datos de entrada constantes pero modificables. La sintaxis de esta función es:
nombre_funcion <- function(Datos de entrada, Datos de entrada por defecto){
Cuerpo de la función
return(Dato de salida)
}
Para que esta función haga su trabajo se requiere de dos parámetros x y n. El primero de ellos debe ser introducido por el usuario, el segundo puede o no serlo.
raiz <- function(x, n = 2){
p <- x^(1 / n)
return(p)
}
raiz(100)
## [1] 10
De no introducirse el parámetro, entonces, por defecto, el valor de n será el establecido de antemano en la función, es decir, 2 de tal forma obtendremos como resultado la raíz cuadrada del parámetro x.
No obstante, podemos cambiar valor de n con el objetivo de sacar una raíz cúbica, cuadrática, etc.
raiz(100, 3) #Raiz cubica
## [1] 4.641589
potencia <- function(x, n = 2){
w <- x^n
return(w)}
potencia(2)
## [1] 4
potencia(7, 98)
## [1] 6.600972e+82
Es posible hacer un scoping en las funciones, esto implica que las variables definidas al interior de una función no son accesibles fuera de la misma, por ejemplo, en la siguiente función se simula el lanzamiento de dos dados, pero no es posible acceder a dado1 y dado2 desde fuera de la función. Para hacer modificaciones se debe entrar a la función.
dos_dados <- function() {
posibilidades <- 1:6
dado1 <- sample(posibilidades, size = 1)
dado2 <- sample(posibilidades, size = 1)
dado1 + dado2
}
dos_dados()
## [1] 7
La sentencia if se utiliza para comprobar una condición,
si esta es verdadera, entonces, se procesan las sentencias dentro de la
misma. La estructura es la siguiente:
if(Condición){
#Sentencias a realizar si la condición es verdadera
}
x <- 4
if(x < 10){
print("x es menor que 10")
}
## [1] "x es menor que 10"
x <- 12
if(x < 10){
print("x es menor que 10")
}
No ha pasado nada, porque la condición es falsa.
q <- -10
if(q >= -100){
print("q es mayor o igual que -100")
}
## [1] "q es mayor o igual que -100"
Es posible usar strings con los condicionales
nombre <- "JOSE"
if(nombre == "JOSE"){
print("Tu nombre es JOSE")
}
## [1] "Tu nombre es JOSE"
red <- "LinkedIn"
num_visitas <- 14
if (red == "LinkedIn") {
print("Muestra la información de Linkedin")
}
## [1] "Muestra la información de Linkedin"
if (num_visitas > 15) {
print("Eres popular")
}
No ocurre nada porque la condición no se cumple.
La sentencia if-else se utiliza para comprobar una
condición, si esta es verdadera, entonces, se procesan las sentencias
dadas, de lo contrario, se procede a realizar otro conjunto de
sentencias en su lugar. La estructura es la siguiente:
if(Condición){
Sentencias a realizar si la condición es verdadera
}else{
Sentencias a realizar si la condición es falsa
}
if-else que verifique si un
número es menor que 10, de ser así imprima “Menor que 10”, de lo
contrario, “Mayor o igual que 10”x<- 4
if(x < 10){
print("Menor que 10")
}else{
print("Mayor o igual que 10")
}
## [1] "Menor que 10"
if-else que verifique si -10
es mayor o igual que -100, de ser así imprima “Es mayor o igual que
-100”, de lo contrario, “Es menor que -100”q <- -10
if(q >= -100){
print("Es mayor o igual que -100")
}else{
print("Es menor que -100")
}
## [1] "Es mayor o igual que -100"
nombre <- "ALEJANDRO"
if(nombre == "JOSE"){
print("Tu nombre es JOSE")
}else{
print("Tu nombre no es JOSE")
}
## [1] "Tu nombre no es JOSE"
z <- 2
if(z != 2){
print("z es diferente de 2")
}else{
print("z es igual a 2")
}
## [1] "z es igual a 2"
if-else. Si medium es igual a LinkedIn,
entonces, imprime “Muestra la información de Linkedin”, de lo contrario,
imprime “Medium desconocido”if (red == "LinkedIn"){
print("Muestra la información de Linkedin")
}else{
print("Red desconocida")
}
## [1] "Muestra la información de Linkedin"
if (num_visitas > 15){
print("Eres popular")
}else{
print("Intenta ser más visible")
}
## [1] "Intenta ser más visible"
Es posible crear más de un if y un else en
una sentencia.
if (red == "LinkedIn"){
print("Muestra la información de LinkedIn")
}else if(red == "Facebook"){
print("Muestra información de Facebook")}else{
print("Red desconocida")
}
## [1] "Muestra la información de LinkedIn"
if (num_visitas > 15){
print("Eres popular")
}else if(num_visitas <= 15 & num_visitas > 10){
print("Tu número de visitas es promedio")}else{
print("Intenta ser más visible")
}
## [1] "Tu número de visitas es promedio"
Se puede combinar todo con los operadores relacionales. Recuerde que en programación no hay una sola respuesta, se puede llegar al resultado correcto de distintas formas. Lo importante es no romper la lógica de la sintaxis.
Se recomienda utilizar el condiconal ifelse, cuando la
condición en juego tiene más de una expresión, por ejemplo, cuando se
realizan comparaciones con vectores.
Considere el vector que representa las calificaciones finales de la asignatura de álgebra de 8 estudiantes. Después compare para saber quiénes obtuvieron notas por debajo de 70.
nota <- c(50,60,49,87,92,30,90,85)
nota < 70
## [1] TRUE TRUE TRUE FALSE FALSE TRUE FALSE FALSE
Al realizar la comparación retorna un vector de TRUE o
FALSE, así que se tienen muchas expresiones a partir de una
condición.
Por tanto, para condiciones de este tipo se sugiere utilizar el
condicional ifelse, para hacer el resultado más intuitivo.
Su estructura es la siguiente:
ifelse(Condición,
Sentencia si la condición es verdadera; Sentencia si la condición es falsa
)
Por ejemplo, considere el vector anterior e identifique que estudiantes están aprobados o reprobados, teniendo en cuenta que la calificación de aprobación es mayor o igual a 70 puntos.
ifelse(nota >= 70,
"Aprobado", "Reprobado")
## [1] "Reprobado" "Reprobado" "Reprobado" "Aprobado" "Aprobado" "Reprobado"
## [7] "Aprobado" "Aprobado"
Incluso es posible operar al interior de este condicional, por ejemplo, retomando el vector nota, suponga que a todos aquellos que tienen una nota superior a 70 se les darán 10 puntos más, de lo contario se les quitarán 10 puntos.
ifelse(nota >= 70,
nota + 10, nota - 10)
## [1] 40 50 39 97 102 20 100 95
Este tipo de condicional es útil cuando se trabaja con variables categóricas y deben ser convertidas a numéricas.
ifelsez <- c(1,0,0,0,1,0,1,1,1,0,1)
ifelse(z == 1,
"Femenino","Masculino")
## [1] "Femenino" "Masculino" "Masculino" "Masculino" "Femenino" "Masculino"
## [7] "Femenino" "Femenino" "Femenino" "Masculino" "Femenino"
li <- 15
fb <- 9
if(li >= 15 & fb >= 15){
sms <- (li + fb) * 2
}else if(li < 10 & fb < 10){
sms <- (li + fb) * 0.5
}else{
sms <- li + fb
}
sms
## [1] 24
Un loop, también conocido como ciclo o
bucle, es útil cuando se necesita repetir varias veces
una secuencia de acciones. Existen dos tipos de ciclos, los
while y los for.
while es la estructura básica que permite repetir varias
veces una secuencia de operaciones, mientras se cumpla una determina
condición, la estructura es:
while(Condición){
Sentencias que se repiten si la condición es verdadera
}
A continuación, se creará un contador que imprima los números del 1 al 10
i <- 1
while(i <= 10){
print(i)
i <- i + 1
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
Para empezar se crea la variable i (contador) con valor
de 1, después se construye un ciclo que imprima números hasta
que i sea menor o igual que 10.
La lógica de este ejercicio radica en el cuerpo del loop que, en cada ciclo, va sumando i + 1, es decir, en el primer ciclo se imprime el primer i al que asignamos un valor de 1, después a i se le asigna el valor de i + 1, e inicia un nuevo loop.
Las operaciones realizadas en el primer ciclo hacen que i ahora valga 2, este es el nuevo valor de i, a este resultado se le suma de nueva cuenta 1, y así sucesivamente hasta llegar a i <= 10. Llegado este punto el loop se detiene y la función termina.
contador <- 8
while (contador <= 10) {
print(contador)
contador <- contador + 1
}
## [1] 8
## [1] 9
## [1] 10
contador <- 1
suma <- 0
while (contador <= 5) {
suma <- suma + contador
contador <- contador + 1
}
suma
## [1] 15
contador
## [1] 6
velocidad <- 64
tiempo <- 10
while(velocidad > 30){
print("Baja la velocidad")
velocidad <- velocidad - tiempo
}
## [1] "Baja la velocidad"
## [1] "Baja la velocidad"
## [1] "Baja la velocidad"
## [1] "Baja la velocidad"
velocidad
## [1] 24
La segunda vuelta del ciclo dará como resultado 44, por lo que nos volverá a advertir de la velocidad, y así sucesivamente hasta que la velocidad sea de 24km/h y, por ende, menor a 30km/h.
Puedes combinar condicionales y bucles para crear algoritmos más sofisticados.
limite <- 5
valor <- 0
while(valor <= limite) {
if(valor < 5){
print("No alcanza el límite")
}else{
print("Límite alcanzado")
}
valor <- valor + 1
}
## [1] "No alcanza el límite"
## [1] "No alcanza el límite"
## [1] "No alcanza el límite"
## [1] "No alcanza el límite"
## [1] "No alcanza el límite"
## [1] "Límite alcanzado"
Siempre y cuando la velocidad sea mayor que 30 imprime “Tu velocidad es” seguido del valor de la velocidad (en el primer ciclo será = 64).
Si la velocidad es mayor a 48, entonces, imprime “Baja la velocidad por favor”. Después, a la velocidad resta 11 y guarda el resultado en velocidad (el resultado es = 53).
Observa que todo este chunk esta sujeto al primer while,
por lo que, terminando el primer if, regresamos al
while con el nuevo resultado de velocidad, es decir, 53 que
sigue siendo mayor a 30, por lo que inicia un nuevo bucle de
while e inicia de nuevo el if
Ahora inicia el tercer ciclo del while, dado que 42
sigue siendo mayor que 30, pero el if ha terminado, puesto
que la condición para que este se ejecute es que la velocidad deber ser
mayor a 48, todo esto se podría leer como:
Como 36 sigue siendo mayor a 30 el while sigue activo,
por lo que inicia un cuarto ciclo y, ya sin el if pasamos
directamente al else. Esto se lee como
Por lo tanto, como 30 ya no es estrictamente mayor a 30 el
while termina.
velocidad <- 64
while (velocidad > 30) {
print(paste("Tu velocidad es", velocidad))
if (velocidad > 48) {
print("Baja la velocidad por favor")
velocidad <- velocidad - 11
} else {
print("Baja la velocidad")
velocidad <- velocidad - 6
}
}
## [1] "Tu velocidad es 64"
## [1] "Baja la velocidad por favor"
## [1] "Tu velocidad es 53"
## [1] "Baja la velocidad por favor"
## [1] "Tu velocidad es 42"
## [1] "Baja la velocidad"
## [1] "Tu velocidad es 36"
## [1] "Baja la velocidad"
velocidad
## [1] 30
Si se ejecuta un while con una condición que nunca será
FALSE, este no se detendrá creándose un ciclo infinito. En términos
prácticos esto agotaría la RAM de la computadora hasta trabarla, por lo
que tendría que ser reiniciada. Revisa muy bien los loops antes
de correrlos.
Con respecto a esta última observación es necesario describir un
break que, como su nombre lo dice, puede romper un
ciclo.
Observe el siguiente código, es casi igual al anterior, con la
salvedad de que ahora la velocidad inicia en 88 y tenemos un nuevo
if. Este nuevo condicional nos dice que si la velocidad
es mayor a 80, entonces, rompa el ciclo.
velocidad <- 88
while(velocidad > 30){
print(paste("Tu velocidad es", velocidad))
if(velocidad > 80){
break
}
if(velocidad){
print("Baja la velocidad por favor")
velocidad <- velocidad - 11
}else{
print("Baja la velocidad")
velocidad <- velocidad - 6
}
}
## [1] "Tu velocidad es 88"
Como 88 es mayor a 80 todo el loop se detiene.
El bucle for en R es una iteración repetitiva de
cualquier sentencia, donde cada iteración evalúa una misma sentencia a
través de los elementos de un vector.
La diferencia con while es que el primero trabaja sobre
una variable, mientras que el segundo trabaja bajo una condición. La
sintaxis es:
for(i in vector){
Sentencias
}
A continuación, se presenta un ciclo de potencias para los primeros 10 números naturales.
for(i in 1:10){
print(i^2)
}
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
## [1] 36
## [1] 49
## [1] 64
## [1] 81
## [1] 100
Lo primero es especificar que el contador i es un vector que va de 1 a 10. Después, se pide que cada uno de esos números sean elevados al cuadrado. El ciclo toma el primer número del vector, es decir, 1, lo eleva al cuadrado, y nos da el resultado que es 1. El siguiente ciclo toma el segundo valor del vector que es 2, lo eleva al cuadrado, y arroja el resultado que es 4, y así sucesivamente hasta llegar al 10.
Imprime una lista con nombres a través de un for
for(j in c("MARIA","MIGUEL","ISMAEL","JOSE","ANGEL","TEO")){
print(j)
}
## [1] "MARIA"
## [1] "MIGUEL"
## [1] "ISMAEL"
## [1] "JOSE"
## [1] "ANGEL"
## [1] "TEO"
Este tipo de ciclos no solo son sencillos, también son muy versátiles pues, no solo se limita a vectores, también funciona con listas.
Aquí hay una lista con la población, alcaldía y capital de la CDMX,
con ayuda de for es posible recorrerla toda
mex <- list(pop = 8405837,
barrios = c("Azcapo","MHidal", "Xochi", "Izta", "Coyo"),
capital = FALSE)
for (n in mex){
print (n)
}
## [1] 8405837
## [1] "Azcapo" "MHidal" "Xochi" "Izta" "Coyo"
## [1] FALSE
También funciona con una matriz. Aquí hay un juego de Gato, para ello se construyó una matriz que representa las posiciones del juego con sus respectivas “X” y “O”
a <- c("O", NA, "X")
b <- c(NA, "O", "O")
c <- c("X", NA, "X")
row_names <- c(a, b, c)
gato <- matrix(row_names,
byrow = TRUE,
nrow = 3)
gato
## [,1] [,2] [,3]
## [1,] "O" NA "X"
## [2,] NA "O" "O"
## [3,] "X" NA "X"
El objetivo del ejercicio es recorrer cada una de las casillas del
Gato y saber que contienen, para ello necesitamos
anidar un for dentro de otro
for, parece complicado, pero solo se debe comprender qué se
busca y cómo se encuentra.
Un Gato se compone de 9 casillas organizadas en filas y columnas de \(3 * 3\), para recorrer todas ellas se puede iniciar con el primer elemento ubicado en la fila 1 columna 1 y comenzar a leer de derecha izquierda, de tal forma que, el segundo elemento se encuentra en la fila 1 columna 2, y el tercero en la fila 1 columna 3.
¿Cómo se traduce a un lenguaje de programación? Se debe construir un
primer contador que vaya del primer elemento al tercer elemento de la
fila 1. Como se trata de una matriz, es posible identificar todas las
filas como una secuencia, así que el primer for parte de
i y avanza de uno en uno sobre toda la fila de la matriz
gato.
Para leer las columnas se usa el for interno o anidado,
que se escribe casi igual que el anterior, solo que esta vez la
secuencia corre sobre las columnas, de tal forma que el segundo
for parte de j y avanza de uno en uno sobre
toda la columna de la matriz gato.
for (i in 1:nrow(gato)) {
for (j in 1:ncol(gato)) {
print(paste("En la fila", i, "y columna", j, "el Gato contiene", gato[i,j]))
}
}
## [1] "En la fila 1 y columna 1 el Gato contiene O"
## [1] "En la fila 1 y columna 2 el Gato contiene NA"
## [1] "En la fila 1 y columna 3 el Gato contiene X"
## [1] "En la fila 2 y columna 1 el Gato contiene NA"
## [1] "En la fila 2 y columna 2 el Gato contiene O"
## [1] "En la fila 2 y columna 3 el Gato contiene O"
## [1] "En la fila 3 y columna 1 el Gato contiene X"
## [1] "En la fila 3 y columna 2 el Gato contiene NA"
## [1] "En la fila 3 y columna 3 el Gato contiene X"
Un for evalúa variable por variable, entonces, el primer
ciclo del primer for inicia y se detiene en el elemento 1
(fila 1, columna 1) y, posteriormente, inicia el primer ciclo del
segundo for que también se detiene en el elemento 1
(columna 1, elemento 1).
El ciclo debe continuar, dado que no se han terminado de evaluar
todos los elementos del primer for, es decir, este
for sigue abierto, por ende, sigue leyendo la fila 1 con la
salvedad que se mueve un espacio a la derecha para encontrar el elemento
2 (fila 1, columna 2), e inicia el segundo ciclo del segundo
for que se detiene en el elemento 2 (columna 2, fila
1).
Hay un entrecruzamiento entre los dos for en el elemento
2 después de todo, fila 1, columna 2, es igual que columna 2, fila 1,
por eso se pide al final del código gato[i,j] para que
identifique lo que hay al interior de esos cruces.
Antes de imprimir los resultados piensa en la estructura con la que
el algoritmo esta “leyendo” el problema, ¿qué aparece como resultado del
primer for, cómo se puede leer?, ¿qué aparece en el segundo
y en el tercero?
En la fila 1 y columna 1 el Gato contiene O En la fila 1 y columna 2 el Gato contiene NA” En la fila 1 y columna 3 el Gato contiene X”
for que sea válido para
todos los elementos del vector mayores a 10, de ser así, imprima “Eres
popular!”, de lo contario, imprima “Intenta ser más visible!”.
Finalmente, imprime el resultado.linkedin <- c(16, 9, 13, 5, 2, 17, 14)
for(li in linkedin){
if(li > 10 ){
print("Eres popular!")}
else{
print("Intenta ser más visible!")}
print(li)
}
## [1] "Eres popular!"
## [1] 16
## [1] "Intenta ser más visible!"
## [1] 9
## [1] "Eres popular!"
## [1] 13
## [1] "Intenta ser más visible!"
## [1] 5
## [1] "Intenta ser más visible!"
## [1] 2
## [1] "Eres popular!"
## [1] 17
## [1] "Eres popular!"
## [1] 14
for, de tal
forma que,Primer for Este ciclo será valido para todos los
elementos del vector LinkedIn con valores mayores a 10, de ser así,
imprime “Eres popular!”, de lo contario, imprime “Intenta ser más
visible!”.
Segundo for Si el primer elemento del vector es
mayor a 16, rompe el ciclo e imprime “Esto es rídiculo”, pero…
Tercer for Si el primer elemento del vector es menor
a 5,* next salta el resto del código y regresa al
primer for
linkedin <- c(16, 9, 13, 5, 2, 17, 14)
for(li in linkedin){
if (li > 10){
print("Eres popular!")
}else{
print("Intenta ser más visible!")
}
}
## [1] "Eres popular!"
## [1] "Intenta ser más visible!"
## [1] "Eres popular!"
## [1] "Intenta ser más visible!"
## [1] "Intenta ser más visible!"
## [1] "Eres popular!"
## [1] "Eres popular!"
for(li in linkedin){
if(li > 16){
break
}
print("Esto es ridículo")
}
## [1] "Esto es ridículo"
## [1] "Esto es ridículo"
## [1] "Esto es ridículo"
## [1] "Esto es ridículo"
## [1] "Esto es ridículo"
for(li in linkedin){
if (li < 5){
next
}
print ("Esto es vergonzoso!")
}
## [1] "Esto es vergonzoso!"
## [1] "Esto es vergonzoso!"
## [1] "Esto es vergonzoso!"
## [1] "Esto es vergonzoso!"
## [1] "Esto es vergonzoso!"
## [1] "Esto es vergonzoso!"
La familia de funciones apply permite crear bucles sin
tantas redundancias, por lo tanto, de manera más sencilla.
Esta función toma una base de datos o matriz como entrada y regresa un vector o una lista.
m1 <- matrix(C<-(1:10), nrow = 5, ncol = 6)
m1
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 1 6 1 6 1 6
## [2,] 2 7 2 7 2 7
## [3,] 3 8 3 8 3 8
## [4,] 4 9 4 9 4 9
## [5,] 5 10 5 10 5 10
a_m1 <- apply(m1, 2, sum)
a_m1
## [1] 15 40 15 40 15 40
Existe una manera más sencilla de hacer loops en R y es a través de lapply, una función que permite ahorrar código siempre y cuando los datos a analizar se encuentren en una lista.
Esta función requiere de dos elementos, la lista a analizar, y la función que se aplicará a todos los elementos de dicha lista. El resultado de la función será una nueva lista del mismo tamaño que la original.
lapply(x, FUN)
A continuación, tenemos una lista con información de la CDMX, tenemos datos numéricos, strings y lógicos
cdmx <- list(pop = 18000000,
alcaldia = c("Cuauhtemoc","Benijto Juarez", "Miguel Hidalgo", "Coyoacan", "Iztapalapa"),
capital = FALSE)
cdmxfor(info in cdmx){
print(class(info))
}
## [1] "numeric"
## [1] "character"
## [1] "logical"
lapply para para revisar que tipo de variables hay
en la lista cdmxlapply(cdmx, class)
## $pop
## [1] "numeric"
##
## $alcaldia
## [1] "character"
##
## $capital
## [1] "logical"
Recuerda que esto solo es posible porque cdmx se trata
de una lista.
Ahora se presenta un vector con estados de la república mexicana:
estados <- c("Jalisco", "CDMX", "Chiapas", "Michoacan", "Oaxaca", "Jalisco", "Nuevo Leon")
for que cuenta las letras que componen los
nombres de los estados. Necesitas un contador, length()
para contar el tamaño del vector y nchar() para contar el
tamaño de las palabras.num_chars <- numeric()
for(i in 1:length(estados)){
num_chars[i] <- nchar(estados[i])
}
num_chars
## [1] 7 4 7 9 6 7 10
lapply cuenta las letras que componen los
nombres de los estados. Al finalizar convierte la lista en un vector con
unlist.lapply(estados, nchar)
## [[1]]
## [1] 7
##
## [[2]]
## [1] 4
##
## [[3]]
## [1] 7
##
## [[4]]
## [1] 9
##
## [[5]]
## [1] 6
##
## [[6]]
## [1] 7
##
## [[7]]
## [1] 10
unlist(lapply(estados, nchar))
## [1] 7 4 7 9 6 7 10
No lo olvides lapply siempre regresa una lista, pero
generalmente trabajamos con vectores, por lo que unlist no
solo es útil, es esencial.
Además, lapply puede combinarse con funciones, aquí se
presenta el precio de la tortilla en las últimas seis semanas.
p_maiz_l <- list(10.2, 10.4, 10.6, 11, 11.4, 11.6)
doble <- function(x){
return(2 * x)
}
#doble(p_maiz_l)
No es posible usar esta función debido a que p_maiz_l es una lista, no un vector.
p_maiz_v <- unlist(p_maiz_l)
doble <- function(x){
return(2 * x)
}
doble(p_maiz_v)
## [1] 20.4 20.8 21.2 22.0 22.8 23.2
lapply. Regresa el
resultado como vectorresultado <- lapply(p_maiz_l, doble)
resultado
## [[1]]
## [1] 20.4
##
## [[2]]
## [1] 20.8
##
## [[3]]
## [1] 21.2
##
## [[4]]
## [1] 22
##
## [[5]]
## [1] 22.8
##
## [[6]]
## [1] 23.2
unlist(resultado)
## [1] 20.4 20.8 21.2 22.0 22.8 23.2
p_maiz_l <- list(10.2, 10.4, 10.6, 11, 11.4, 11.6)
p_maiz_v <- unlist(p_maiz_l)
multiplicador <- function(x, factor){
x * factor
}
multiplicador(p_maiz_v, 3)
## [1] 30.6 31.2 31.8 33.0 34.2 34.8
lapply.
Regresa el resultado como un vector.p3_maiz <- lapply(p_maiz_l, multiplicador, 3)
p3_maiz
## [[1]]
## [1] 30.6
##
## [[2]]
## [1] 31.2
##
## [[3]]
## [1] 31.8
##
## [[4]]
## [1] 33
##
## [[5]]
## [1] 34.2
##
## [[6]]
## [1] 34.8
unlist(p3_maiz)
## [1] 30.6 31.2 31.8 33.0 34.2 34.8
Aquí tenemos un vector con los apellidos y fechas de nacimiento de algunos famosos pensadores.
filosofos <- c("MARX:1818", "SMITH:1723", "KEYNES:1883", "HAYEK:1899")
strsplit para separar los apellidos de las fechas a
través de :.split_filos <- strsplit(filosofos, split = ":")
split_filos
## [[1]]
## [1] "MARX" "1818"
##
## [[2]]
## [1] "SMITH" "1723"
##
## [[3]]
## [1] "KEYNES" "1883"
##
## [[4]]
## [1] "HAYEK" "1899"
tolower dentro
de un lapply usando split_filos.filos_min <- lapply(split_filos, tolower)
filos_min
## [[1]]
## [1] "marx" "1818"
##
## [[2]]
## [1] "smith" "1723"
##
## [[3]]
## [1] "keynes" "1883"
##
## [[4]]
## [1] "hayek" "1899"
str(filos_min)
## List of 4
## $ : chr [1:2] "marx" "1818"
## $ : chr [1:2] "smith" "1723"
## $ : chr [1:2] "keynes" "1883"
## $ : chr [1:2] "hayek" "1899"
La función strsplit eliminó los : y separó
la información, pero sigue siendo una lista, no se creó una columna.
filos_min selecciona solo a Smith 1723.filos_min[2]
## [[1]]
## [1] "smith" "1723"
filos_min.apellidos <- function(x){
x[1]
}
apellidos(filos_min)
## [[1]]
## [1] "marx" "1818"
filos_min.apellidos <- function(x){
for(x in filos_min)
print(x)
}
apellidos(filos_min)
## [1] "marx" "1818"
## [1] "smith" "1723"
## [1] "keynes" "1883"
## [1] "hayek" "1899"
lapply para que la función apellidos
recorra cada uno de los elementos del vector y seleccione solo los
apellidos.apellidos <- function(x){
x[1]
}
apellidos <- lapply(filos_min, apellidos)
apellidos
## [[1]]
## [1] "marx"
##
## [[2]]
## [1] "smith"
##
## [[3]]
## [1] "keynes"
##
## [[4]]
## [1] "hayek"
fechas <- function(x) {
x[2]
}
fechas <- lapply(filos_min, fechas)
fechas
## [[1]]
## [1] "1818"
##
## [[2]]
## [1] "1723"
##
## [[3]]
## [1] "1883"
##
## [[4]]
## [1] "1899"
No son columnas, sin embargo lapply entiende que
buscamos el segundo elemento de la lista.
La ventaja de lapply es que, al trabajar con listas, es
posible guardar en ellas todo tipo de objetos y obtener como resultado
una lista, pero si el resultado que vamos a obtener de una función solo
regresa un tipo de objeto, entonces, usamos sapply.
Esta función toma una lista, vector o base datos y regresa un vector
o matriz, por lo tanto, hace lo mismo que lapply pero no
regresa una lista.
Su sintaxis es igual que lapply pues admite dos
parámetros, los datos con los que trabajamos y la función que se aplica
a dichos datos.
sapply(X, # Vector o lista
FUN, # Función a ser aplicada
..., # Argumentos adicionales para ser pasados a FUN
simplify = TRUE, # Si FALSE devuelve una lista. Si "array" devuelve un array si es posible
USE.NAMES = TRUE) # Si TRUE y si X es un vector de caracteres, usa los nombres de X
El siguiente vector contiene solo datos de tipo string:
estados <- c("Jalisco", "CDMX", "Chiapas", "Michoacan", "Oaxaca", "Jalisco", "Nuevo Leon")
sapply y nchar para contar las letras
de los nombres de cada Estadosapply(estados, nchar)
## Jalisco CDMX Chiapas Michoacan Oaxaca Jalisco Nuevo Leon
## 7 4 7 9 6 7 10
Parece que obtuvimos el mismo resultado que con un
lapply, pero no es así. Primero, estados es un
vector, no una lista.sapply puede trabajar con ambos.
Segundo, sapply realiza la función nchar en
cada uno de los elementos del vector y, de manera interna, usa la
función simply2array para convertir las listas que dan como
resultado lapply en un vector, es decir,
sapply crea un bucle.
Finalmente, es de resaltar que sapply se tomó la
molestia de nombrar el vector. Si no estás interesado en conservar los
nombres usa USE.NAMES = FALSE.
sapply(estados, nchar, USE.NAMES = FALSE)
## [1] 7 4 7 9 6 7 10
Es posible usar funciones son sapply, pero qué pasa si
la función que quieres realizar da como resultado un vector con dos
variables en lugar de una.
min y max, busca la letra con el menor y mayor
valor alfabético de la palabra Jalisco.primera_ultima <- function(nombre){
letras <- strsplit(nombre, split = "")[[1]]
c(primera = min(letras), ultima = max(letras))
}
primera_ultima("Jalisco")
## primera ultima
## "a" "s"
La letra con menor valor es a y la de mayor valor es s.
estados.sapply(estados, primera_ultima)
## Jalisco CDMX Chiapas Michoacan Oaxaca Jalisco Nuevo Leon
## primera "a" "C" "a" "a" "a" "a" " "
## ultima "s" "X" "s" "o" "x" "s" "v"
Esto ya no es un vector, es una matriz y la función
sapply ya puso todos los nombres.
sapply simplifica los resultados de lapply,
pero esto no siempre ocurrirá, puede que la función que apliques no
arroje (output) un vector del mismo tamaño que aquello que hayas
ingresado (input), por lo tanto, si hay dos variables y los tamaños de
sus vectores no coinciden, no puede haber una matriz.
letras_unicas <- function(nombre){
letras <- strsplit(nombre, split = "")[[1]]
unique(letras)
}
letras_unicas("Oaxaca")
## [1] "O" "a" "x" "c"
lapply sobre el vector estados y
aplica la función letras_unicas.lapply(estados, letras_unicas)
## [[1]]
## [1] "J" "a" "l" "i" "s" "c" "o"
##
## [[2]]
## [1] "C" "D" "M" "X"
##
## [[3]]
## [1] "C" "h" "i" "a" "p" "s"
##
## [[4]]
## [1] "M" "i" "c" "h" "o" "a" "n"
##
## [[5]]
## [1] "O" "a" "x" "c"
##
## [[6]]
## [1] "J" "a" "l" "i" "s" "c" "o"
##
## [[7]]
## [1] "N" "u" "e" "v" "o" " " "L" "n"
lapply regresó una lista con vectores de letras.
sapply sobre el vector estados y
aplica la función letras_unicas.sapply(estados, letras_unicas)
## $Jalisco
## [1] "J" "a" "l" "i" "s" "c" "o"
##
## $CDMX
## [1] "C" "D" "M" "X"
##
## $Chiapas
## [1] "C" "h" "i" "a" "p" "s"
##
## $Michoacan
## [1] "M" "i" "c" "h" "o" "a" "n"
##
## $Oaxaca
## [1] "O" "a" "x" "c"
##
## $Jalisco
## [1] "J" "a" "l" "i" "s" "c" "o"
##
## $`Nuevo Leon`
## [1] "N" "u" "e" "v" "o" " " "L" "n"
sapply hace básicamente los mismo, dado que es lo mejor
que puede hacer en este caso. Esto puede ser un problema porque siempre
esperamos que regrese un vector cuando no siempre será así.
lapply y sapply para
encontrar las temperaturas mínimas y máximas en cada caso.temp <- list(c(3,7,9,6,-1),
c(6,9,12,13,5),
c(4,8,3,-1,-3),
c(1,4,7,2,-2),
c(5,7,9,4,2),
c(-3,5,8,9,4),
c(-3,5,8,9,4))
temp
## [[1]]
## [1] 3 7 9 6 -1
##
## [[2]]
## [1] 6 9 12 13 5
##
## [[3]]
## [1] 4 8 3 -1 -3
##
## [[4]]
## [1] 1 4 7 2 -2
##
## [[5]]
## [1] 5 7 9 4 2
##
## [[6]]
## [1] -3 5 8 9 4
##
## [[7]]
## [1] -3 5 8 9 4
# Minima
lapply(temp, min)
## [[1]]
## [1] -1
##
## [[2]]
## [1] 5
##
## [[3]]
## [1] -3
##
## [[4]]
## [1] -2
##
## [[5]]
## [1] 2
##
## [[6]]
## [1] -3
##
## [[7]]
## [1] -3
sapply(temp, min)
## [1] -1 5 -3 -2 2 -3 -3
# Maxima
lapply(temp, max)
## [[1]]
## [1] 9
##
## [[2]]
## [1] 13
##
## [[3]]
## [1] 8
##
## [[4]]
## [1] 7
##
## [[5]]
## [1] 9
##
## [[6]]
## [1] 9
##
## [[7]]
## [1] 9
sapply(temp, max)
## [1] 9 13 8 7 9 9 9
Al inspeccionar los elementos veras que no son los mismos resultados.
lapply y sapplyextremes_avg <- function(temp){
(min(temp) + max(temp)) / 2
}
sapply(temp, extremes_avg)
## [1] 4.0 9.0 2.5 2.5 5.5 3.0 3.0
lapply(temp, extremes_avg)
## [[1]]
## [1] 4
##
## [[2]]
## [1] 9
##
## [[3]]
## [1] 2.5
##
## [[4]]
## [1] 2.5
##
## [[5]]
## [1] 5.5
##
## [[6]]
## [1] 3
##
## [[7]]
## [1] 3
lapply y
sapply.extremes <- function(temp){
c(min = min(temp),
max = max(temp))
}
sapply(temp,extremes)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## min -1 5 -3 -2 2 -3 -3
## max 9 13 8 7 9 9 9
lapply(temp,extremes)
## [[1]]
## min max
## -1 9
##
## [[2]]
## min max
## 5 13
##
## [[3]]
## min max
## -3 8
##
## [[4]]
## min max
## -2 7
##
## [[5]]
## min max
## 2 9
##
## [[6]]
## min max
## -3 9
##
## [[7]]
## min max
## -3 9
lapply y sapply.bajo_cero <- function(x){
return(x[x < 0])
}
bajo_cero_s <- sapply(temp, bajo_cero)
bajo_cero_s
## [[1]]
## [1] -1
##
## [[2]]
## numeric(0)
##
## [[3]]
## [1] -1 -3
##
## [[4]]
## [1] -2
##
## [[5]]
## numeric(0)
##
## [[6]]
## [1] -3
##
## [[7]]
## [1] -3
bajo_cero_l <- lapply(temp, bajo_cero)
bajo_cero_l
## [[1]]
## [1] -1
##
## [[2]]
## numeric(0)
##
## [[3]]
## [1] -1 -3
##
## [[4]]
## [1] -2
##
## [[5]]
## numeric(0)
##
## [[6]]
## [1] -3
##
## [[7]]
## [1] -3
identical(bajo_cero_s, bajo_cero_l)
## [1] TRUE
Una última función
print_info <- function(x){
cat("La temperatura promedio es", mean(x), "\n")
}
sapply(temp, print_info)
## La temperatura promedio es 4.8
## La temperatura promedio es 9
## La temperatura promedio es 2.2
## La temperatura promedio es 2.4
## La temperatura promedio es 5.4
## La temperatura promedio es 4.6
## La temperatura promedio es 4.6
## [[1]]
## NULL
##
## [[2]]
## NULL
##
## [[3]]
## NULL
##
## [[4]]
## NULL
##
## [[5]]
## NULL
##
## [[6]]
## NULL
##
## [[7]]
## NULL
lapply(temp, print_info)
## La temperatura promedio es 4.8
## La temperatura promedio es 9
## La temperatura promedio es 2.2
## La temperatura promedio es 2.4
## La temperatura promedio es 5.4
## La temperatura promedio es 4.6
## La temperatura promedio es 4.6
## [[1]]
## NULL
##
## [[2]]
## NULL
##
## [[3]]
## NULL
##
## [[4]]
## NULL
##
## [[5]]
## NULL
##
## [[6]]
## NULL
##
## [[7]]
## NULL
Al igual que sapply permite hacer ciclos rápidos e
intenta simplificar el resultado. Sin embargo, cuando usas
vapply debes explicitar que tipo resultado quieres. Su
sintaxis es:
vapply(x, # Vector o lista
FUN, # Función a ser aplicada
FUN.VALUE,
..., # Argumentos adicionales para ser pasados a FUN
USE.NAMES = TRUE) # Si TRUE y si X es un vector de caracteres, usa los nombres de X
Aquí tenemos un nuevo argumento FUN.VALUE que funciona
para regresar el resultado de la función como mejor convenga. Usaremos
el vector estados.
estados <- c("Jalisco", "CDMX", "Chiapas", "Michoacan", "Oaxaca", "Jalisco", "Nuevo Leon")
sapply con la función nchar para
contar las letras de los elementos en el vector
estados.sapply(estados, nchar)
## Jalisco CDMX Chiapas Michoacan Oaxaca Jalisco Nuevo Leon
## 7 4 7 9 6 7 10
vapply con la función nchar para
contar las letras de los elementos en el vector
estados.vapply(estados, nchar, numeric(1))
## Jalisco CDMX Chiapas Michoacan Oaxaca Jalisco Nuevo Leon
## 7 4 7 9 6 7 10
Todo parece igual, pero no es así. nchar es una función
que regresa un vector numérico de tamaño 1. Lo que hicimos fue crear una
plantilla para este resultado con FUN.VALUE = numeric(1),
es decir, le indicamos a vapply que regresara un valor
numérico de tamaño 1.
x <- sapply(estados, nchar)
y <- vapply(estados, nchar, numeric(1))
str(x)
## Named int [1:7] 7 4 7 9 6 7 10
## - attr(*, "names")= chr [1:7] "Jalisco" "CDMX" "Chiapas" "Michoacan" ...
str(y)
## Named num [1:7] 7 4 7 9 6 7 10
## - attr(*, "names")= chr [1:7] "Jalisco" "CDMX" "Chiapas" "Michoacan" ...
Mientras que los valores de x son de tipo integer, los de y son de tipo numeric, tal y como se pidió.
La diferencia entre vapply y sapply es que
el primero es más seguro que el segundo, porque en el primero estoy
especificando el tipo de resultado que quiero, lo que es imposible con
sapply.
info_temp <- function(x){
c(min = min(x),
mean = mean(x),
max = max(x))
}
vapply(temp, info_temp, numeric(3))
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## min -1.0 5 -3.0 -2.0 2.0 -3.0 -3.0
## mean 4.8 9 2.2 2.4 5.4 4.6 4.6
## max 9.0 13 8.0 7.0 9.0 9.0 9.0
Aquí se específica que se buscan 3 resultados
info_temp <- function(x){
c(min = min(x),
mean = mean(x),
median = median(x),
max = max(x))
}
vapply(temp, info_temp, numeric(4))
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## min -1.0 5 -3.0 -2.0 2.0 -3.0 -3.0
## mean 4.8 9 2.2 2.4 5.4 4.6 4.6
## median 6.0 9 3.0 2.0 5.0 5.0 5.0
## max 9.0 13 8.0 7.0 9.0 9.0 9.0
Ahora se buscan 4 resultados
Recuerda * lapply se usa sobre una
lista o vector y regresa una lista. * sapply se usa sobre
una lista o vector y regresa un vector simplificado, si no puede,
regresa la misma lista que lapply * vapply se
usa sobre una lista o vector y explicita específicamente el formato del
resultado
Vamos a hacer uso de algunas funciones populares en R
abs devuelve los valores absolutossum calcula la sumatoria de los datosmean media aritméticaround redondea por default a 0, pero se puede
modificarseq genera secuencias especificando el inicio y el
finalrep repite elementos de vectores y listassort ordena un vector de forma ascendente, trabaja con
todo tipo de datosrev invierte los elementos en una estructura de
datosstr muestra la estructura de los datosappend une elementos a vectores o listasis.* nos dice la clase de los objetosas.* convierte los objetos de R de un tipo a otrounlist transforma listas en vectoresRecuerda que es posible anidar las funciones, pero deben llevar el orden adecuado para llegar al resultado correcto.
errores <- c(1.9, -2.6, 4.0, -9.5, -3.4, 7.3)
sum(abs(round(errores)))
## [1] 29
rev para invertir el orden de vec1. Obtén
el promedio de ambos.vec1 <- c(1.5, 2.5, 8.4, 3.7, 6.3)
vec1
## [1] 1.5 2.5 8.4 3.7 6.3
vec2 <- rev(vec1)
vec2
## [1] 6.3 3.7 8.4 2.5 1.5
mean(c(abs(vec1), abs(vec2)))
## [1] 4.48
A continuación, se presentan las listas de LinkedIn y Facebook
linkedin <- list(16, 9, 13, 5, 2, 17, 14)
facebook <- list(17, 7, 5, 16, 8, 13, 14)
unlist.li_vec <- unlist(linkedin)
li_vec
## [1] 16 9 13 5 2 17 14
fb_vec <- unlist(facebook)
fb_vec
## [1] 17 7 5 16 8 13 14
append.social_vec <- append(li_vec, fb_vec)
social_vec
## [1] 16 9 13 5 2 17 14 17 7 5 16 8 13 14
sort de forma descendentesort(social_vec, decreasing = TRUE)
## [1] 17 17 16 16 14 14 13 13 9 8 7 5 5 2
rep(seq(1, 7, by = 2), times = 7)
## [1] 1 3 5 7 1 3 5 7 1 3 5 7 1 3 5 7 1 3 5 7 1 3 5 7 1 3 5 7
sum(rep(seq(1, 7, by = 2), times = 7))
## [1] 112
R cuenta con expresiones regulares (regex) que son secuencias de caracteres y metacaracteres. que forman un patrón de búsqueda que puedes usar para hacer un match entre strings. Puedes usar una expresión regular para revisar si ciertos patones existen en un texto para reemplazarlos con otros elementos o extraerlos, esto puede ser particularmente útil para limpiar una base de datos.
grep regresa un vector de índices de los elementos de
x que hagan un matchgrepl regresa un vector lógico que identifica los
elementos de x que hacen matchPractiquemos con este vector de carros
carros <- c("mustang", "el camino", "road runner", "trans am", "impala")
grepl para ver cuál de estos carros tienen una
m en su nombregrepl(pattern = "m", x = carros)
## [1] TRUE TRUE FALSE TRUE TRUE
grepl(pattern = "^m", x = carros)
## [1] TRUE FALSE FALSE FALSE FALSE
grepl(pattern = "m$", x = carros)
## [1] FALSE FALSE FALSE TRUE FALSE
grep con los
anteriores.grep(pattern = "m", x = carros)
## [1] 1 2 4 5
Como puedes observar esta función no devuelve un resultado de valores
lógicos sino los índices de aquellos resultados que coinciden con la
búsqueda. Este mismo resultado podríamos obtenerlo con
grepl, pero necesitamos usar which
which(grepl(pattern = "m", x = carros))
## [1] 1 2 4 5
No siempre funcionan estas funciones, en algunas ocasiones debemos ser más específicos y apoyarnos en metacaracteres. Observa este vector con correos:
emails <- c("john.doe@ivyleague.edu", "education@world.gov", "dalai.lama@peace.org","invalid.edu", "quant@bigdatacollege.edu", "cookie.monster@sesame.tv")
#grepl(pattern = "edu", x = emails)
Algo anda mal, el problema es que hay correos que inician con edu, por lo que la función se esta “confundiendo”. Busca sus índices y guarda todo en un objeto.
hits <- grep(pattern = "edu", x = emails)
hits
## [1] 1 2 4 5
Definitivamente algo ando mal, realiza un subset para ver estos correos
emails[hits]
## [1] "john.doe@ivyleague.edu" "education@world.gov"
## [3] "invalid.edu" "quant@bigdatacollege.edu"
Claro, como lo sospechamos, esta búsqueda ha fallado, pero esto aún no termina, hagamos una búsqueda más exacta con los metacaracteres.
@.*: incluimos (@*)
porque debe tratarse de un correo, luego el punto permite hacer un match
con cualquier carácter cero (.) o más () veces\\.edu$: permite hacer un match con la parte (.edu) que
se encuentra al final ($) del string. La parte \ le dice a R que
queremos usar el (.) como un caráctergrepl para buscar esos correos con terminación
(.edu). Esta vez la función tomara en cuenta el (@), el (.*) hará un
match con cualquier carácter, mientras que \ hace que R “ignore” el
punto como tal y lo tome con otro carácter a buscar.grepl(pattern = "@.*\\.edu$", x = emails)
## [1] TRUE FALSE FALSE FALSE TRUE FALSE
Hemos encontrado dos correos, veamos donde se encuentran
hits<-grep(pattern = "@.*\\.edu$", x = emails)
hits
## [1] 1 5
Hagamos el subset para verlos.
emails[hits]
## [1] "john.doe@ivyleague.edu" "quant@bigdatacollege.edu"
¡Voila! los tenemos.
También es posible hacer reemplazos en estos errores tipográficos
sub permite remplazar el primer match buscando con otra
stringgsub permite remplazar todos los matches con otra
stringsub(pattern = "a", replacement = "o", x = carros)
## [1] "mustong" "el comino" "rood runner" "trons am" "impola"
¿Notas algo raro? Así es, no cambio todas las a por
o, tenemos tons Am e impolA, eso es por que
sub solo cambia la primera letra. Si quieres cambiar todas
usa gsub
gsub(pattern = "a", replacement = "o", x = carros)
## [1] "mustong" "el comino" "rood runner" "trons om" "impolo"
¿Recuerdas el operador lógico o |? Pues aquí
también los puedes usar. Cambia la a o la r con un
*_*
gsub(pattern = "a|r", replacement = "_", x = carros)
## [1] "must_ng" "el c_mino" "_o_d _unne_" "t__ns _m" "imp_l_"
sub(pattern="@.*\\.edu$", replacement = "@ipn.edu", x = emails)
## [1] "john.doe@ipn.edu" "education@world.gov"
## [3] "dalai.lama@peace.org" "invalid.edu"
## [5] "quant@ipn.edu" "cookie.monster@sesame.tv"
gsubgsub("A", "a", c("Adios", "HAsta luego"))
## [1] "adios" "Hasta luego"