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")