Introducción a la programación funcional

Javier Emmanuel Anguiano Pita

CONAHCYT-Universidad de Guadalajara

9 de enero de 2025

Agenda del día

  1. Introducción a las estructuras de control en R
    • Expresiones condicionales y bucles.
  2. Uso del motor gráfico de R {base}.

Estructuras de control

Estructuras de control

Estructuras de control

  • Las estructuras de control establecen condicionales en nuestros programas. Por ejemplo, ¿qué condiciones deben cumplirse para realizar una operación? o ¿qué debe ocurrir para ejecutar una función?

  • En otras palabras, determinan la lógica y el orden en el que ocurren las operaciones, en especial al definir funciones.

  • Las estructuras de control más usadas en R son las siguientes:

Estructura de control Descripción
if, else Sí, de otro modo
for Para cada uno en
while Mientras
break Interrupción
next Siguiente

Condicionales if y else

  • La función if (si) se usa cuando queremos que una operación se ejecute unicamente cuando se cumple una condición.

Ejemplo condicionales if y else

  • Para declarar un condicional si, iniciamos nuestra función con if():
if(condicion){
  operacion_si_condicion_TRUE
}
  • Ejemplo:
if(numero > 10){
  resultado <- "El número es mayor que 10"
}

print(resultado)

Ejemplo condicionales if y else

  • Podemos usar la función else{} para establecer la acción a ejecutar si no se cumple la condición:
if(numero > 10){
  resultado <- "El número es mayor que 10"
} else {
  resultado <- "El número es menor que 10"
}
  • La identación es importante así como el uso correcto de {}.

  • Finalmente, si nos interesa que se muestre en la pantalla el resultado usamos la función print() o return().

  • Para usar nuestro condicional debemos definir los argumentos de entrada (numero).

Anidación de condicionales

En el ejemplo anterior hemos omitido evaluar la condición de que numero == 10. Para contemplar esta posibilidad podemos usar el siguiente código:

numero <- 10

if(numero > 10){
  resultado <- "El número es mayor que 10"
} else if (numero == 10){
  resultado <- "El número es igual a 10"
} else {
  resultado <- "El número es menor que 10"
}  
  
print(resultado)

Ejercicio

05:00
  • Escribe una función que tenga como argumento de entrada una edad (número) y su resultado nos muestre en la pantalla si se trata de un niño o un adulto. Usa los condicionales if y else.
    • Supon que la edad adulta se adquiere cuando la persona tiene una edad>=18 años.

Uso de vectores en condicionales

  • Nota que el argumento de entrada solo es un número (escalar) ¿Qué sucede si tratamos de ejecutar el condicional sobre un vector?
edad <- c(5, 15, 21, 67, 40, 98)
probar_edad(edad)
  • En R podemos vectorizar el condicional usando la función ifelse().

  • En lugar de escribir una línea de código para cada comparación, podemos usar una sola llamada a esta función, que se aplicará a cada elemento de un vector.

  • Esta función tiene la siguiente estructura:

ifelse(vector_entrada, valor_SI_TRUE, valor_SI_FALSE)
  • En nuestro ejemplo sobre las edades:
edad <- c(5, 15, 21, 67, 40, 98)
ifelse( edad >= 18, "Adulto", "Niño")

Ejemplo: Función ifelse()

  • Podemos usar la función ifelse() para saber si los número en un vector son pares o nones:
num <- 1:10 

ifelse(num %% 2 == 0, "Par", "Non")
  • Esta función puede ser muy útil para recodificar datos:
num <- c(0, 1 , 1, 0 , 0 ,1, 0)
genero <- ifelse(num == 0, "Hombre", "Mujer")
genero

num2 <- c("Hombre", "Mujer", "Mujer", "Hombre")
genero2 <- ifelse(num2 == "Hombre", 0 , 1)
genero2

Bucles en R

  • En R, los bucles (loop) son estructuras de control de flujo que permiten repetir un bloque de código de forma cíclica ya sea un determinado número de veces o hasta que se cumpla una condición.

for

  • La estructura for nos permite ejecutar un bucle ( loop ) realizando una operación para cada elemento de un conjunto de datos.
  • Su estructura es la siguiente:
for(elementos in objeto){
  operacion_con_elemento
}
  • En lenguaje simple, le estamos diciendo a R:
    • PARA cada elemento EN un objeto, haz lo siguiente {}.
# Ejemplo del uso de un bucle "for"
dado <- 1:6
for(cara in dado){
  dado ^ 2
}

Uso de bucles for

  • Las operaciones en un bucle for se realizan pero sus resultados nunca son devueltos automáticamente, es necesario pedirlos de manera explícita.

  • Una solución para mostrar los resultados de un bucle for es usar la función print().

for(cara in dado) {
  print(cara ^ 2)
}
  • Comprobamos que la operación ha sido realizada a cada elemento de nuestro objeto. Sin embargo, usar print() sólo mostrará los resultados de las operaciones en la consola, no los asignará a un objeto.

Uso de índices en bucles

  • Si deseamos asignar los resultados de un bucle for a un objeto, usamos índices.
  • En R el primer elemento de un bucle siempre es identificado con el número 1, y se realizarán las operaciones hasta llegar al total de elementos que especifiquemos:
# Ejemplo de un dado de seis caras
dado <- 1:6

for(cara in dado){
  print(cara)
}
  • El nombre del índice lo podemos definir explícitamente. Normalmente, se denomina con la letra i.

Asignar valores en un bucle for

  • Para guardar los resultados de cada iteración de nuestro bucle for podemos generar un objeto vacío:
# Ejemplo de un dado de seis caras
dado <- 1:6
mi_vector <- NULL  # Objeto vacío 

for(cara in dado){
  mi_vector[cara] <- cara ^ 2
}

mi_vector

for y vectorización

  • Los resultados que obtuvimos usando el bucle for pueden obtenerse vectorizando la operación:
dado ^ 2 
  • En R el uso de bucles for son poco populares ya que es más rápido y sencillo vectorizar las operaciones.
  • Sin embargo, es conveniente que conozcamos esta estructura de control porque hay ocasiones en que es la mejor herramienta para realizar algunas tareas.

while

  • Este es un tipo de bucle que ocurre mientras una condición es verdadera (TRUE). La operación se realiza hasta que se llega a cumplir un criterio previamente establecido.

  • La sintaxis de while es la siguiente:

while(condicion){
  operaciones
}
  • Con esto le decimos a R:
    • MIENTRAS esta condición es VERDADERA, haz estas operaciones.

Ejemplo de uso de while

Probemos sumar +1 a un valor, mientras que este sea menor que 5.

umbral <- 5
valor <- 0 

while(valor < umbral){
  print("Todavía no")
  valor <- valor + 1
}

Advertencia

¡Ten cuidado de crear bucles infinitos! Si ejecutas una condición que nunca será FALSE, este nunca se detendra.

  • Si haz ejecutado un bucle infinito presiona la tecla ESC para detener su ejecución. De otra forma, podría congelarse tu equipo.

break y next

  • En R las palabras break y next son palabras reservadas. Es decir, NO podemos asignarle nuevos valores y realizan una acción específica cuando aparecen en nuestro código.

  • break nos permite interrumpir un bucle.

  • next nos deja avanzar a la siguiente iteración saltándose la actual.

  • Ambas funciones pueden ser utilizadas en bucles de tipo for y while.

Ejemplo del uso de break

Interrumpimos un for cuando i es igual a 3, aunque aún queden 7 elementos en el objeto.

for(i in 1:10) {
  if(i == 3) {
    break
  }
  print(i)
}

Ejemplo del uso de break

  • Interrumpimos un while antes de se cumpla la condición de que numero sea mayor a 5, en cuanto este tiene el valor de 15.
numero <- 20

while(numero > 5) {
  if(numero == 15) {
    break
  }
  numero <- numero - 1
}
numero

Ejemplo del uso de next

Por su parte, usamos next para “saltarnos” una iteración en un bucle. Cuando la condición se cumple, esa iteración es omitida.

for(i in 1:4) {
  if(i == 3) {
    next
  }
  print(i)
}

Funciones apply

Funciones apply

  • La familia de funciones apply es usada para aplicar una función a cada elemento de una estructura de datos (i.e., matrices, dataframes, arrays y listas).

  • Con esta familia de funciones podemos automatizar tareas complejas usando pocas líneas de código.

  • En el paradigma de R, la familia de funciones apply reciben como argumentos un objeto y al menos una función.

  • En este curso trabajaremos únicamente con las funciones más generales y de uso común de esta familia:

    • apply()
    • lapply()

Función apply()

apply() aplica una función a todos los elementos de una matriz.

  • La estructura de esta función es la siguiente:
apply(X, MARGIN, FUN)
  • La función tiene tres argumentos:
    • X: Una matriz o un objeto que puede coercionarse como matriz (dataframe).
    • MARGIN: La dimensión (margen) que agrupará los elementos de la matriz X, para aplicar una función. 1 se refiere a las filas y 2 son columnas.
    • FUN: La función que queremos aplicar al objeto X en su dimensión MARGIN.

Ejemplo uso apply()

data("mtcars")  # Importamos datos de ejemplo
?mtcars
head(mtcars)
apply(mtcars,2,mean)  # Promedio por columna
apply(mtcars,2,max)  # Maximo por columna
apply(mtcars,2,min)  # Mínimo por columna

# Ejemplo de uso de matrices
m <- matrix(seq(1:16), nrow = 4, ncol = 4)
m

apply(m, 1, min)  # Mínimo por filas

Ejemplo uso apply()

También podemos definir funciones dentro de la función apply() y aplicarlas tanto por filas como por columnas:

# Ejemplo de uso de matrices
m <- matrix(seq(1:16), nrow = 4, ncol = 4)
m

# Cuadrado de cada valor x
apply(m, c(1,2), function(x){x^2})
  • Nota que apply() nos devuelve objetos del mismo tipo al que la función fue aplicada

Función lapply()

lapply() está diseñada para aplicar funciones a todos los elementos de una lista (por eso l).

  • Esta función intentará coercionar a una lista cualquier tipo de objeto que demos como argumento y después aplicará una función a todos sus elementos.
  • La estructura de esta función es la siguiente:
lapply(X, FUN)
  • En donde:
    • X es una lista u objeto coercionable a una lista.
    • FUN es la función a aplicar.
    • Nota que aquí no específicamos MARGIN porque las listas son estructuras unidimensionales que solo tienen largo.

Ejemplo uso lapply()

x <- 1: 5
raiz <- lapply(x, sqrt) # Nos devuelve una lista
raizdf <- unlist(lapply(x, sqrt)) # Convertimos en vector

# Contar caracteres en una palabra
ciudades_vec <- c("Aguascalientes", "Monterrey", "Guadalajara", "México")
ciudades_vec

contar_nchar <- lapply(ciudades_vec, nchar)
contar_nchar

Ejercicio con datos reales

  • Descarga el archivo en MS Excel PIBE_2020-2023.xlsx.
  • Importa la base de datos a R. Nota: Usa los botones del panel Environment.
  1. Usando la función apply() calcula el valor promedio del PIB de cada estado para el período 2020-2023. Guarda el resultado en una nueva variable denominada PIBE_promedio en el mismo dataframe.

  2. Usando la función lapply() calcula el valor aproximado del PIB nacional para cada año. Guarda el resultado en una nueva variable denominada PIB_Nacional. Nota: Supon que puedes aproximar el valor del PIB nacional sumando el valor de los PIBE’s.

Gráficas con R base

Introducción

  • Por defecto, R tiene un sistema de generación de gráficos poderoso y flexible. Sin embargo, al inicio su uso puede resultar complejo.

  • En esta sección revisaremos como crear gráficas usando R base y algunos parámetros que podemos ajustar para mejorar su presentación.

  • Al crear gráficas, notarás que ponemos en práctica todo lo que hemos visto hasta ahora incluyendo importar datos, hacer subconjuntos de objetos y usar funciones.

  • En esta sección trabajaremos de forma simultánea usando estas diapositivas y una práctica guíada Enlace

Ve al Ejercicio # 1 de la práctica guíada

Función plot()

La función plot() puede ser usada de forma general para crear gráficos.

  • Esta función tiene un comportamiento especial. Dependiendo del tipo de datos que ingresemos como argumento generará diferentes tipos de gráfica.

  • Para cada tipo de gráfico podemos ajustar diferentes parámetros que controlan su aspecto.

  • Sintáxis básica:

plot(x, y, type)
  • Donde:

    • x: Las coordenadas del Eje X de los puntos a graficar.
    • y : Las coordenadas del Eje Y de los puntos a graficas (opcional). -type: El tipo de puntos a dibujar. ?plot()

Ejemplo del uso de la función plot()

Relación entre el peso (wt) y la eficiencia en el uso de combustible (mpg) de un conjunto de vehículos en el dataset mtcars.

data("mtcars")

plot(mtcars$wt, mtcars$mpg,
     main = "Relación entre peso y eficiencia",
     xlab = "Peso del vehículo (wt)",
     ylab = "Millas por galón (mpg)", 
     col = "blue",
     pch = 19)

# ¿qué hace pch? 
?pch

Uso de plot()

Dependiendo del tipo de datos que ingresemos como argumentos a la función plot() obtendremos distintos tipos de gráficos:

x y Gráfico
Continuo Continuo Diagrama de dispersión (scatterplot)
Continuo Discreto Diagrama de dispersión
Continuo Ninguno Diagrama de dispersión por renglón
Discreto Continuo Diagrama de caja (Box plot)
Discreto Discreto Gráfico de mosaico (Diagrama de Kinneman)
Discreto Ninguno Gráfico de barras
Ninguno Cualquiera Error

Uso de la función barplot()

  • La función barplot()se utiliza para crear gráficos de barras.

  • Permite visualizar distribuciones de frecuencias, comparar entre categorías o cualquier otro conjunto de datos categóricos.

  • Sintáxis básica:

barplot(height, beside = FALSE, 
        col = "blue", main = "Título", 
        xlab = "Eje X", ylab = "Eje Y")
  • Donde:
    • height: Tabla de frecuencias.
    • beside = TRUE: Indica que las barras de dibujarán lado a lado.
    • col = Especifica el color de las barras.
    • main, ylab, xlab: Titulo para los gráficos del eje.

Ejemplo de uso de la función barplot()

datos <- rep(letters[1:5], c(7,4,2,9,11))
# Número de veces que se repite cada letra
datos

datos <- table(datos)  # Convertir a tabla de frecuencias
datos 

barplot(datos)  # Gráfica de barras
# Personalización de la gráfica

barplot(datos,
        main = "Gráfica personalizada",
        xlab = "Letras aleatorias",
        ylab = "# Ocurrencias",
        col = "lightblue",
        border = "grey")
datos_2 <- sort(datos, decreasing = TRUE)

barplot(datos_2,
        main = "Gráfica ordenada (Mayor a menor)\n",
        xlab = "Letras aleatorias",
        ylab = "Ocurrencias",
        col = "bisque",
        border = "orange")

Ve al Ejercicio # 2 en la práctica guíada

Función legend()

  • Las leyendas son usadas para identificar con mayor claridad los distintos elementos en un gráfico, tales como colores y formas.

  • En R usamos la función legend() para generar leyendas. Esta función debe ser llamada después de crear un gráfico.

  • En cierto modo es una anotación a un gráfico ya existente.

  • legend() es una función relativamente compleja, así que sólo revisaremos lo esencial.

Función legend()

  • Sintáxis básica:
legend(leyenda, fill, "x,y", title)
  • Donde:
    • leyenda: Etiquetas de datos que queremos escribir en la leyenda.
    • fill: Los colores que acompañan a las etiquetas definidas con leyenda. - "x,y": Las coordenadas en pixeles en donde se ubicará la leyenda.
    • title: Titulo de la leyenda.

Ve al Ejercicio # 3 de la práctica guíada

Uso de la función hist()

  • Los histogramas son gráficas que nos permiten observar la distribución de datos númericos usando barras.

  • Cada barra representa el número de veces (frecuencia) que se observaron datos en un rango determinado.

  • Para generar un histograma nosotros podemos usar la función hist() que pide como argumento (obligatorio) un vector x de tipo numérico.

  • Sintáxis básica de uso:

hist(x, xlab, ylab)
  • Donde:
    • x: es un vector de valores numérico.

Ejemplo de uso de la función hist()

# Generamos 5000 datos de una distribución normal (mu = 5, sd = 10)

datos_sim <- rnorm(5000, mean = 5, sd = 10)
hist(datos_sim, main = "Ejemplo de Histograma",
     xlab = "Valores aleatorios", ylab = "Frecuencia"
     )

Ve al Ejercicio # 4 de la práctica guíada

Panel de gráficas en R

  • Hasta ahora sabemos que el motor gráfico de R nos permite visualizar una figura a la vez. Cuando hacemos un nuevo gráfico perdemos el anterior.
  • En ocasiones nos interesa tener un panel de figuras para comparar nuestros resultados.
  • La función par() nos permite crear una “matriz” detrás de escena para colocar múltiples gráficas en el motor visual.
  • Sintáxis básica de uso:
par(mfrow)
  • Donde:
    • mfrow determina un vector con valores de filas y columnas a manera de cuadricula sobre las que pondremos las gráficas.

Ejemplo de múltiples gráficas

par(mfrow = c(2,2))
hist(rnorm(5000, 0,1))
hist(rnorm(200, 5,12))
hist(rnorm(10000, 4,1))
hist(rnorm(100, 6,1))
par(mfrow = c(1,4))
hist(rnorm(5000, 0,1))
hist(rnorm(200, 5,12))
hist(rnorm(10000, 4,1))
hist(rnorm(100, 6,1))

Exportar gráficos

Para exportar un gráfico usamos alguna de las siguientes funciones, cada una corresponde con un tipo de archivo distinto. No son las únicas, pero son las más usadas.

  • bpm()

  • jpeg()

  • pdf()

  • png()

  • tiff()

Exportar gráficos

Cada una de estas funciones tiene los siguientes argumentos tres argumentos principales.

  • filename: El nombre y ruta del archivo de imagen a crear. Si no especificamos una ruta completa, entonces el el archivo será creado en nuestro directorio de trabajo.

  • width: El ancho del archivo de imagen a crear, por defecto en pixeles.

  • height: El alto del archivo de imagen a crear, por defecto en pixeles.

Ejemplo: Exportar gráficas

png(filename = "Histograma_01.png", width = 800, height = 600)

hist(rnorm(15000, 5, 2), 
     main = "Histograma de ejemplo", 
     xlab = "Valores aleatorios",
     ylab = "Frecuencia",
     col = "red")

dev.off()  # Cerramos el motor gráfico y guardamos. 

Recapitular R base

Uso de corchetes y paréntesis

  • [ ]

    Indexar elementos en objetos.

  • ( )

    Pasar argumentos a funciones.

  • { }

    Definir acciones de condicionales, funciones, bucles, etc.

Ya entiendes el lenguaje de R

¿Qué tipo de datos conocemos?

  • numeric
  • character
  • factor
  • logical

¿Cómo podemos encontrar datos faltantes?

  • NA (No disponible)
  • NULL (No existe)
  • " " (Campo vacío)

Ya entiendes el lenguaje de R

¿Qué tipos de estructuras de datos existen?

  • vector (1-D)
  • dataframe (2-D)
  • list (M-D)

¿Qué funciones hemos usado?

  • c()
  • is.na()
  • mean()
  • apply()
  • if-statments
  • function
  • for/ while-loop

Obtener ayuda

  • Para obtener ayuda sobre una función podemos escribir en la consola: ?mean() o help("mean").
  • Usar un motor de busqueda en internet (i.e., Stackoverflow).
  • Modelos de IA generativa (LLM):
    • Ventajas: Puede escribir todo nuestro código a partir de una ide general.
    • Desventajas: no aprendemos. Puede alucinar.

Fin de la sesión