12/11/2020

¿Qué es una función?

Las funciones reúnen una secuencia de operaciones como un todo, almacenandola para su uso continuo. Las funciones proveen:

  • Un nombre que podemos recordar y usar para involucrarla.
  • Una solución para la necesidad de recordar operaciones individuales.
  • Un conjunto definido de inputs y outputs esperados.
  • Una mayor conexión con el ambiente de programación.
 nombre <- function(parámetros) {
  operaciones
}

Creación de funciones

potencia <- function(x){
  x^2
  }

potencia(5)
## [1] 25
x <-1:20

potencia(x)
##  [1]   1   4   9  16  25  36  49  64  81 100 121 144 169 196 225 256 289 324 361
## [20] 400

F_a_k <- function(temp) {
  kelvin <- ((temp - 32) * (5 / 9)) + 273.15
  return(kelvin)
}

F_a_k(32)
## [1] 273.15
k_a_C <- function(temp) {
  Celsius <- temp - 273.15
  return(Celsius)
}

k_a_C(32)
## [1] -241.15

R automáticamente devuelve lo qe esté en la última línea de la función. Pero por claridad, podemos colocar el comnado return() .

Ejercicio 10

Escribe una función llamada F_a_C() que toma la temperatura en F y devuelve la temperatura en C. Reutilizando las dos funciones de arriba (o utilizando tus propias funciones si lo prefieres).

Programación defensiva

Es importante garantizar que las funciones solo funcionen para lo que quieres. Este concepto se llama programación defensiva. Nos lleva a probar las condiciones necesarias para que funcione y arrojar un error si algo está mal.

Precio_descuento <- function(d) {
  if (!is.numeric(d)) {
    stop("Debes ingresar un valor numérico.")
  }
  valor <- d-d*.3
  return(valor)
}

# Precio_descuento("1200")
# Error in Precio_descuento("1200") : Debes ingresar un valor entero.

Precio_descuento(12)
## [1] 8.4

Si tuviéramos muchas condiciones para revisar, podría llevar muchas líneas de código probarlas todas. Afortunadamente R provee la función de conveniencia stopifnot(). Podemos listar todos los requerimientos que deben ser evaluados; arroja un error si encuentra uno que se cumpla.

Precio_descuento <- function(d) {
  stopifnot(is.numeric(d) & d>0) 
  valor <- d-d*.3
  return(valor)
}
# Precio_descuento(-200)
# Precio_descuento(-200) : is.numeric(d) & d > 0 is not TRUE 
 
Precio_descuento(200)
## [1] 140

Ejercicio 11

Crea dos funciones, una que arroje una frase personal cuando haya algún error y otra que tenga varias condiciones para que se ejecute.

Ejercicio 12

Crea una función que tenga dos parámetros, “nombre” y “edad”. Luego la función debe arrojar como salida la frase: " (nombre) tiene (edad) años".

La familia apply

La familia de funciones apply() es usada para aplicar una función a cada elemento de una estructura de datos. En particular, es usada para aplicar funciones en matrices, data frames, arrays y listas.

La familia apply esta formada por las siguientes funciones:

  • apply()
  • eapply()
  • lapply()
  • mapply()
  • rapply()
  • sapply()
  • tapply()

Es una familia numerosa y esta variedad de funciones se debe a que varias de ellas tienen aplicaciones sumamente específicas.

Todas las funciones de esta familia tienen una característica en común: reciben como argumentos a un objeto y al menos una función.

Las funciones de la familia apply tienen la particularidad que pueden recibir a otra función como un argumento. Lo anterior puede sonar confuso, pero es más bien intuitivo al verlo implementado.

Nosotros trabajaremos con las funciones más generales y de uso común de esta familia:

  • apply()
  • lapply()

Estas dos funciones nos permitirán solucionar casi todos los problemas a los que nos encontremos. Además, conociendo su uso, las demás funciones de la familia apply serán relativamente fáciles de entender.

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)

apply tiene tres argumentos:

  • X: Una matriz o un data frame.
  • MARGIN: 1 son renglones y 2 son colummnas.
  • FUN: La función que aplicaremos a la matriz X en su dimención MARGIN.

Uso de apply

M <-matrix(1:10,nrow=5)
M
##      [,1] [,2]
## [1,]    1    6
## [2,]    2    7
## [3,]    3    8
## [4,]    4    9
## [5,]    5   10
apply(M,2,sum)
## [1] 15 40
apply(M,1,mean)
## [1] 3.5 4.5 5.5 6.5 7.5

lapply()

lapply() es un caso especial de apply(), diseñado para aplicar funciones a todos los elementos de una lista. La l de su nombre se refiere, precisamente, a lista.

lapply siempre nos devolverá una lista como resultado. La estructura de esta función es:

lapply(X, FUN)

Uso de lapply

mi_vector <- 1:4

lapply(mi_vector, sqrt)
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 1.414214
## 
## [[3]]
## [1] 1.732051
## 
## [[4]]
## [1] 2

lapply(trees, FUN = mean)
## $Girth
## [1] 13.24839
## 
## $Height
## [1] 76
## 
## $Volume
## [1] 30.17097
arboles <- lapply(trees, mean)

class(arboles)
## [1] "list"

Usando lapply con listas

# Fijamos una semilla
set.seed(seed = 2018)

# Creamos una lista con tres data frames dentro
tablas <- list(
  df1 = data.frame(a = rnorm(5), b = rnorm(5), c = rnorm(5)),
  df2 = data.frame(d = rnorm(5), e = rnorm(5), f = rnorm(5)),
  df3 = data.frame(g = rnorm(5), h = rnorm(5), i = rnorm(5))
)

lapply(tablas,cor)
## $df1
##            a          b          c
## a  1.0000000 -0.4427336  0.6355358
## b -0.4427336  1.0000000 -0.1057007
## c  0.6355358 -0.1057007  1.0000000
## 
## $df2
##            d          e         f
## d  1.0000000 -0.6960942 0.4709283
## e -0.6960942  1.0000000 0.2624429
## f  0.4709283  0.2624429 1.0000000
## 
## $df3
##            g          h          i
## g  1.0000000  0.6228793 -0.1472657
## h  0.6228793  1.0000000 -0.1211321
## i -0.1472657 -0.1211321  1.0000000

Pequeño descanso…

Nuevo truco de magia. El truco se llama “tablas magicas”. Por favor ingresen a la siguiente liga, donde se encuentra publicada una pequeña aplicación del truco.

https://www.geogebra.org/m/uhmkrvuq

Gráficas

R cuenta con un sistema de generación de gráficas poderoso y flexible. Sin embargo, tener estar cualidades hace que este sistema sea un tanto complejo para aprender.

Revisaremos como crear las gráficas más comunes, así como algunos de los parámetros que podemos ajustar para mejorar su presentación.

Datos a utilizar

Utilizaremos los datos disponibles en el UCI Machine Learning Repository https://archive.ics.uci.edu/ml/index.php.

Usaremos un conjunto de datos llamado “Bank Marketing Data Set”, que contiene información de personas contactadas en una campaña de marketing directo puesta en marcha por un banco de Portugal.

Comenzamos con la descarga de la copia del archivo .csv desde el sitio de Github de este libro.

download.file(
  url = "https://raw.githubusercontent.com/jboscomendoza/r-principiantes-bookdown/master/datos/bank.csv", 
  destfile = "bank.csv"
  )

banco <- read.csv(file = "bank.csv", sep = ";")

head(banco)
##   age         job marital education default balance housing loan  contact day
## 1  30  unemployed married   primary      no    1787      no   no cellular  19
## 2  33    services married secondary      no    4789     yes  yes cellular  11
## 3  35  management  single  tertiary      no    1350     yes   no cellular  16
## 4  30  management married  tertiary      no    1476     yes  yes  unknown   3
## 5  59 blue-collar married secondary      no       0     yes   no  unknown   5
## 6  35  management  single  tertiary      no     747      no   no cellular  23
##   month duration campaign pdays previous poutcome  y
## 1   oct       79        1    -1        0  unknown no
## 2   may      220        1   339        4  failure no
## 3   apr      185        1   330        1  failure no
## 4   jun      199        4    -1        0  unknown no
## 5   may      226        1    -1        0  unknown no
## 6   feb      141        2   176        3  failure no
dim(banco)
## [1] 4521   17

lapply(banco, class)
## $age
## [1] "integer"
## 
## $job
## [1] "factor"
## 
## $marital
## [1] "factor"
## 
## $education
## [1] "factor"
## 
## $default
## [1] "factor"
## 
## $balance
## [1] "integer"
## 
## $housing
## [1] "factor"
## 
## $loan
## [1] "factor"
## 
## $contact
## [1] "factor"
## 
## $day
## [1] "integer"
## 
## $month
## [1] "factor"
## 
## $duration
## [1] "integer"
## 
## $campaign
## [1] "integer"
## 
## $pdays
## [1] "integer"
## 
## $previous
## [1] "integer"
## 
## $poutcome
## [1] "factor"
## 
## $y
## [1] "factor"

summary(banco)
##       age                 job          marital         education    default   
##  Min.   :19.00   management :969   divorced: 528   primary  : 678   no :4445  
##  1st Qu.:33.00   blue-collar:946   married :2797   secondary:2306   yes:  76  
##  Median :39.00   technician :768   single  :1196   tertiary :1350             
##  Mean   :41.17   admin.     :478                   unknown  : 187             
##  3rd Qu.:49.00   services   :417                                              
##  Max.   :87.00   retired    :230                                              
##                  (Other)    :713                                              
##     balance      housing     loan           contact          day       
##  Min.   :-3313   no :1962   no :3830   cellular :2896   Min.   : 1.00  
##  1st Qu.:   69   yes:2559   yes: 691   telephone: 301   1st Qu.: 9.00  
##  Median :  444                         unknown  :1324   Median :16.00  
##  Mean   : 1423                                          Mean   :15.92  
##  3rd Qu.: 1480                                          3rd Qu.:21.00  
##  Max.   :71188                                          Max.   :31.00  
##                                                                        
##      month         duration       campaign          pdays       
##  may    :1398   Min.   :   4   Min.   : 1.000   Min.   : -1.00  
##  jul    : 706   1st Qu.: 104   1st Qu.: 1.000   1st Qu.: -1.00  
##  aug    : 633   Median : 185   Median : 2.000   Median : -1.00  
##  jun    : 531   Mean   : 264   Mean   : 2.794   Mean   : 39.77  
##  nov    : 389   3rd Qu.: 329   3rd Qu.: 3.000   3rd Qu.: -1.00  
##  apr    : 293   Max.   :3025   Max.   :50.000   Max.   :871.00  
##  (Other): 571                                                   
##     previous          poutcome      y       
##  Min.   : 0.0000   failure: 490   no :4000  
##  1st Qu.: 0.0000   other  : 197   yes: 521  
##  Median : 0.0000   success: 129             
##  Mean   : 0.5426   unknown:3705             
##  3rd Qu.: 0.0000                            
##  Max.   :25.0000                            
## 

La función plot()

En R, la función plot() es usada de manera general para crear gráficos.

Esta función tiene un comportamiento especial, pues puede generarár diferentes tipos de gráfica. Además, para cada tipo de gráfico, podremos ajustar diferentes parámetros que controlan su aspecto, dentro de esta misma función.

plot() siempre pide un argumento \(x\), que corresponde al eje \(X\) de una gráfica. \(x\) requiere un vector y si no especificamos este argumento, obtendremos un error y no se creará una gráfica.

El resto de los argumentos de plot() son opcionales, pero el más importante es \(y\). Este argumento también requiere un vector y corresponde al eje \(Y\) de nuestra gráfica.

plot(iris)

plot(banco$age)

plot(banco$age,type="l",col="blue")

plot(banco$job)

La función hist()

La función hist() nos permite hacer histogramas, el cual es una gráfica que nos permite observar la distribución de datos continuos usando barras. Cada barra representa el número de veces (frecuencia) que se observaron datos en un rango determinado.

La función hist() que siempre nos pide como argumento \(x\) un vector numérico. El resto de los argumentos de esta función son opcionales. Si damos un vector no numérico, se nos devolverá un error.

hist(x = banco$age)

hist(x = banco$age, main = "Histograma de Edades", 
     xlab = "Edad", ylab = "Frecuencia",col="purple")

hist(x = banco$duration, main = "Histograma de Duración", 
     xlab = "Duración", ylab = "Densidad",xaxs="i",yaxs="i",
     col = "ivory",freq = F)

La función barplot()

Además de usar plot(), podemos crear gráficas de barra con la función barplot().

barplot pide como argumento una matriz, que represente una tabla de contingencia con los datos a graficar. Este tipo de tablas pueden ser generadas con la función table().

table() pide como argumento uno o más vectores, de preferencia variables discretas. Si damos sólo un vector como argumento, devuelve un conteo, si damos dos o más variables, devuelve tablas de contingencia.

Por ejemplo, el conteo de la variable educación,

tabla1 <-table(banco$education)
tabla1
## 
##   primary secondary  tertiary   unknown 
##       678      2306      1350       187
tabla2 <- table(banco$loan, banco$education)
tabla2
##      
##       primary secondary tertiary unknown
##   no      584      1890     1176     180
##   yes      94       416      174       7

barplot(tabla1, col=rainbow(4))

barplot(tabla2, col=c("red","blue"),horiz=T,las=1,cex.names=0.7)

La función boxplot()

La función boxplot() genera diagramas de caja, también conocidos como de caja y bigotes, son gráficos que muestra la distribución de una variable usando 5 valores importantes (minimo, primer cuartil, mediana, media, tercer cuartil y máximo ), de modo que de manera visual podemos inferir algunas cosas sobre su dispersión, ubicación y simetría.

Una gráfica de este tipo dibuja un rectángulo cruzado por una línea recta horizontal. Esta linea recta representa la mediana o equivalentemente segundo cuartil, su base representa el pimer cuartil y su parte superior el tercer cuartil. Al rango entre el primer y tercer cuartil se le conoce como intercuartílico (RIC). Esta es la caja.

boxplot(banco$age,col="gray",main="Distribución de edades")

plot(x = banco$education, y = banco$age,ylab="Edades",xlab= "Niveles de eduación",
     main="Distribuciones de niveles de eduación vs edades",col=rainbow(4))

Leyendas

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() siempre nos pide siempre los siguientes argumentos.

  • legend: Las etiquetas de los datos que queremos describir con la leyenda.
  • fill: Los colores que acompañan a las etiquetas definidas con legend. Estos colores tienen que coincidir con los que hemos usado en el gráfico.
  • \(x\) y \(y\): Las coordenadas en pixeles, en las que estará ubicada la leyenda. Existen ubicaciones automáticas “bottomright”, “bottom”, “bottomleft”, “left”, “topleft”, “top”, “topright”, “right”, “center”.
  • title: Para poner título a la leyenda.

tab_banco <- table(banco$loan, banco$education)
barplot(tab_banco,  main = "Préstamos por nivel educativo",
     xlab = "Nivel educativo", ylab = "Frecuencia", 
     col = c("royalblue", "green3"))
legend(x = "topright", legend = c("No", "Si"), fill = c("royalblue", "green3"), 
       title = "Prestamo")

Resumen de los gráficos más utilizados en R

  • plot(): Diagramas de dispersión.

  • barplot(): Diagramas de barras.

  • hist(): Histogramas.

  • boxplot(): Boxplot (Diagrama de caja y bigotes).

Ejercicio 13

Crea un ejemplo de cada uno de las diferentes funciones que acabamos de trabajar.

persp(x = 10*(1:nrow(volcano)), y=10*(1:ncol(volcano)), z=3*volcano, 
      theta = 135, phi = 30, col = "green3", scale = FALSE,
      ltheta = -120, shade = 0.75, border = NA, box = FALSE, 
      main="Volcán MaungaWhau NZ")

x <- seq(-10, 10, length= 80)
y <- x
f <- function(x, y) { r <- sqrt(x^2+y^2); 10 * sin(r)/r }
z <- outer(x, y, f)
z[is.na(z)] <- 1
op <- par(bg = "white")
persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "pink")