Documente Academic
Documente Profesional
Documente Cultură
4 * 3 / 2
x <- rpois(15, 4)
p <- sum(x) / 15
p
f <- function(v) {
p <- sum(v) / length(v)
p
}
f <- function(v) {
v <- v[!is.na(v)]
p <- sum(v) / length(v)
p
}
f(x)
nombre(argumentos)
## Argumentos:
# En este caso los argumentos se llaman "arg1",
"arg2" y "arg3". En el
# momento de definirla, al igual que al llamarla,
estos deben estar
# separados por comas.
# Es posible definir funciones sin argumentos,
aunque generalmente esto
# no es de gran utilidad. Por ejemplo:
alf <- function()
print("¡No hay problema!")
## Instrucciones:
# Las instrucciones son comandos de R que se van a
ejecutar cada vez que
# el usuario llame la función. En el ejemplo de
"alf", el único comando
# indica que hay que imprimir la frase "¡No hay
problema!".
edad(220)
# Vengo de Melmac, tengo 220 años.
edad("cuarenta")
# Vengo de Melmac, tengo cuarenta años.
# Salida:
# Toda función devuelve algo, ya lo dijimos, y por
defecto, ese algo es
# el último objeto generado dentro de las
instrucciones. Para el caso de
# la función "alf", esto será la frase "¡No hay
problema!" (es lo que
# devuelve la función print), y para el caso de
"edad", será NULL, que es
# lo que devuelve la función cat. Más abajo se
muestran otras formas de
# definir la salida de una función.
x[c(2,5,12,25)] <- NA
SEM(datos = x)
edad(8)
# Vengo de Melmac, tengo 8 años y 5 meses.
Curso de R | Funciones
by Mauricio | Dic 6, 2016 | Curso R
Escribir funciones es una de las actividades más importantes en cualquier
lenguaje de programación. Su finalidad es poder encapsular fragmentos de
código que necesiten ser ejecutados en múltiples ocasiones, con la posibilidad
de ejecutarlos en cada ocasión con diferentes parámetro. A su vez, las
funciones aumentan la legibilidad de un programa, de modo que es más fácil
de entender para uno mismo y para los demás en caso de compartirlo.
Tabla de Contenidos [ocultar]
1 Funciones
o 1.1 Introducción
o 1.2 Argumentos
o 1.3 El argumento …
Funciones
Introducción
Las funciones en R son tratadas como cualquier otro objeto. Para crearlas
utilizamos el comando function(), el cual crear objetos de tipo function, de la
siguiente manera:
f <- function(<argumentos>)
{
## Código de la función (function body)
}
f()
Hola Mundo
class(f)
"function"
f <- function(x, y) { x + y }
body(f)
{
x + y
}
formals(f)
$x
$y
environment(f)
<environment: R_GlobalEnv>
Argumentos
Los argumentos de una función son una serie de valores (opcionales) que se
pasan a la función, de modo que ciertas variables dentro de estas posean
diferentes valores en cada llamada a la función.
area_rectangulo <- function(lado1, lado2)
{
area <- lado1 * lado2
print(paste("el área es ", area))
}
area_rectangulo(2, 3)
"el área es 6"
formals(area_rectangulo)
$lado1
$lado2
f(x = 2, y = 0)
2
Error in print(z) : argument "z" is missing, with no
default
Para evitar este tipo de comportamientos podemos asignar valores por defecto
(default value) a las variables en la declaración de las funciones. Por ejemplo:
f <- function(x = NULL, y = NULL)
{
if (!is.null(x) & !is.null(y)){
print(x+y)
}else{
print('faltan valores')
}
}
f(x = 2, y = 0)
2
f(x = 2)
"faltan valores"
f(y = 0)
"faltan valores"
Para ejemplificar esto en un caso real veamos la función rnorm. Esta genera
números aleatorios a partir de una distribución normal.
str(rnorm)
function (n, mean = 0, sd = 1)
Para indicar los nombre de los argumentos al llamar a una función, R permite
que haya coincidencia parcial en estos. De este modo podemos llamar a una
funciona e indicar solo una parte del nombre de cada argumento.
rnorm(5, s = 10, m = 100)
101.70763 91.48214 103.48912 107.92323 98.50723
El argumento …
Hay un argumento que tiene un uso especial en R, denominando … (tres
puntos). Este tiene la capacidad de capturar todos los valores pasados a la
función que no coinciden con ningún argumento. De este modo, podemos
pasar a una función una cantidad no prefijada de valores.
sumar_pares <- function(...)
{
valores <- c(...)
if(!is.numeric(valores)) return('NaN')
contador <- 0
for(n in valores){
if(n%%2 == 0){
contador <- contador + n
}
}
contador
}
sumar_pares(1:10)
30
Como vemos, para trabajar con los valores capturado por … podemos
convertirlos a un vector con c(...)o una lista con list(...).
Retorno de valores
Las funciones anteriores solamente realizan una seria de pasos y finalizan sin
devolver ningún valor. En muchas ocasiones deseamos que las funciones al
finalizar su ejecución devuelvan algún valor. Para esto tenemos dos
posibilidades.
La primea es hacer que la ultima linea de código evaluada dentro de una
función sea el valor que queremos que sea devuelto.
## Función que cuenta la cantidad de vocales en una cadena
que
## se pasa como argumento
contar_vocales <- function(frase)
{
cantidad_vocales <- 0
frase <- tolower(frase)
frase <- strsplit(frase, "")[[1]]
for (i in frase)
{
if (i %in% c("a", "e", "i", "o", "u"))
{
cantidad_vocales <- cantidad_vocales + 1
}
}
cantidad_vocales
}
# Ejemplo
calcular_raiz2 <- function(n)
{
# Verifico que el que número pasado no sea negativo
if (n < 0) return("Numero negativo")
calcular_raiz2(2)
1.414214
calcular_raiz2(-2)
"Numero negativo"
f <- function(x)
{
z <- 10
2 * z + g(x)
}
g <- function(x)
{
x * z
}
¿Qué valor devolverá f(5)? Veamos.
Cuando llamamos a la función f lo primero que se evalúa es z <- 10. Esta
acción crea un par (z, 10)en el ambiente de la función f. A continuacion se
evalúa 2*z + g(x). En este paso, R busca el valor de la variable z en el
ambiente de la función f, y encuentra el par (z, 10). Luego busca a la
función g, pero no la encuentra definida dentro de la función f, por lo que pasa
a buscarla en el ambiente padre y encuentra:
g <- function(x)
{
x * z
}
Ahora evalúa g(5), y se encuentra con x * z. Acá vemos claramente
que x vale 3, pero ¿qué valor toma la variable z? Como dijimos, R utiliza lexical
scoping. Estos significa que se va a buscar el valor de la variable al ambiente
donde esta fue definida (y no donde fue llamada). Por lo tanto, el valor
de z será 1, y por lo tanto:
f(5)
25
Ahora vemos que sucede si la función g la hubiésemos definido dentro de la
función f:
f <- function(x)
{
g <- function(x)
{
x * z
}
z <- 10
2 * z + g(x)
}
Lo único que cambia al momento de evaluar f(5) es al momento de que R va a
busca el valor de z cuando evalúa g(5). Como ahora g está definida dentro
de f, R va a buscar el valor de z en su nuevo ambiente padre, que es
justamente el ambiente de la función f, y encuentra que ahora el valor de z es
10, y por lo tanto:
f(5)
70
Autor: Alberto Muñoz García
Estructuras de programación
Por ejemplo:
Un ejemplo de dibujo:
> x = seq(-10,10)
> plot(x,x,xlim=c(0,10),ylim=c(0,10))
> for(i in 1:10)
+ abline(h=i,col=i)
> for(i in 1:10)
+ abline(v=i,col=i)
No obstante, los bucles for son lentos en R (y en Splus), y deben ser evitados en la medida de lo
posible.
El bucle while
¿Qué ha sucedido? El cuadrado de 32 excede 1000. En realidad, cuando n valía 31, su cuadrado
(961)
no excedía 1000, y el while() permitió entrar en el bucle, lo que hizo n=32. El número correcto sería
en este caso n-1 = 31.
Ejecución condicional: if
Por ejemplo, vamos a crear dos listas; una para guardar los
números pares de 1 a 10, y otra para los impares:
> n = 10 # Se inicializa n
> pares = c() # Se crea un vector vacío
> impares = c() # Idem
> for(i in 1:n){ # Se van a procesar los números de 1 a n
+ if(i%%2==0) pares<-c(pares,i) # Si al dividir por 2 sale 0
+ else impares<-c(impares,i)} # el numero es par, impar en otro caso
> pares
[1] 2 4 6 8 10
> impares
[1] 1 3 5 7 9
Creación de funciones en R
La estructura general de una función en R es la siguiente:
Por ejemplo, podemos definir una función que calcule la desviación típica:
Una vez definida una función, se la puede llamar y utilizar como a cualquiera otra función
predefinida en el sistema. Por ejemplo, vamos a utilizar la función apply combinada con
desv para calcular las desviaciones típicas de las columnas de una matriz:
> x = matrix(rnorm(15),nrow=3)
>x
[,1] [,2] [,3] [,4] [,5]
[1,] 0.1578703 1.6712974 -0.5419452 0.03345786 -0.6675674
[2,] 0.3215741 -0.6352143 -1.0222260 0.39006069 0.3609624
[3,] 0.4770036 -0.3508383 -0.5147970 1.36219826 -1.6669992
> apply(x,2,desv)
[1] 0.1595845 1.2576365 0.2854502 0.6877219 1.0140156
Las variables definidas dentro del cuerpo de una función son locales, y desaparecen al terminar
la ejecución de la función. Por ejemplo:
Como ejemplo, vamos a redefinir la función desviación típica, de modo que tengamos
la posibilidad de calcular la desviación típica corregida y sin corregir:
En R es posible definir funciones con un número variable de argumentos. Para ello, la sintaxis es:
En el primer caso, la función podría llamarse sin hacer referencia explícita a x (por ejemplo f(2) ).
En el segundo caso deberíamos especificar f(x=2), dado que el sistema, al encontrar primero los
argumentos variables, no podría saber si nos estamos refiriendo a x o a uno de los argumentos
variables.
Vamos a poner un ejemplo en dos fases. En primer lugar, para entender como funciona al tema,
definiremos una función que simplemente devuelve sus argumentos:
Así pues, es variable el número de argumentos, tanto como el número de elementos de cada uno.
Vamos a aprovechar esta facilidad para definir una función que devuelva algunas medidas resumen
de las distribuciones que se le pasen como argumento. La entrada a la función será una serie de
conjuntos de datos, y la salida la media, varianza, mínimo y máximo de cada uno de los conjuntos.
f = function(...)
{
datos = list(...)
medias = lapply(datos,mean) # lapply aplica una función sobre una lista
varianzas = lapply(datos,var)
maximos = lapply(datos,max)
minimos = lapply(datos,min)
for(i in 1:length(datos))
{
cat("Distribución ",i,": \n") # La función cat es para visualizar cosas
cat("media: ",medias[[i]],"varianza: ",varianzas[[i]],"maximo: ",maximos[[i]],"minimo:
",minimos[[i]],"\n")
cat("------------------------------------------------\n")
}
> f(c(1,2),c(1,3,5,7),c(-1,2,-5,6,9))
Distribución 1 :
media: 1.5 varianza: 0.5 maximo: 2 minimo: 1
------------------------------------------------
Distribución 2 :
media: 4 varianza: 6.666667 maximo: 7 minimo: 1
------------------------------------------------
Distribución 3 :
media: 2.2 varianza: 30.7 maximo: 9 minimo: -5
------------------------------------------------
O también:
> x = rnorm(100)
> y = runif(50)
> f(x,y)
Distribución 1 :
media: 0.1616148 varianza: 0.87319 maximo: 2.201592 minimo: -2.143932
------------------------------------------------
Distribución 2 :
media: 0.4985783 varianza: 0.08253697 maximo: 0.9881924 minimo: 0.01329678
------------------------------------------------
Pirimidinas<-function(x) {
Pirimidinas <- 0 # asignar el valor de 100 a Pirimidinas
{
Pirimidinas <- 100-Purinas(x)
}
return(Pirimidinas)
}
#> Pirimidinas(c("A","T","T","G","G","G"))
#[1] 33.33333
#> Purinas(c("A","T","T","G","G","G"))
#[1] 66.66667
#> Purinas(c("A"))
#[1] 100
#> Pirimidinas(c("A"))
#[1] 0
------------------------------------------------------------------------------------
Todas las lineas que se encuentran después de un # son comentarios que se agregan al
código de la función. En este caso el primer comentario menciona lo que hacen las
funciones
que se van a escribir.
Primero se define la primer función y se le da el nombre que se desee y que se aplicara
al objeto x (x), para nuestro caso
el nombre es "purinas" y continuación se empieza a escribir el cuerpo de la función y se
escribe después de haber abierto un corchete ({) :
Purinas<-function(x) {
Ahora le decimos que para cada elemento n del objeto x , en este caso la secuencia de
ADN, se le aplicara
el resto de el código de la función, en pocas palabras, abrimos un loop:
for (n in x) {
A continuación le decimos lo que debe hacer con cada elemento n del objeto x, cada vez
que lo evalué.
Para nuestro caso seria: si (if) el objeto(n) que encuentra en la secuencia(x) es "A" o
"G", entonces le sume
1 a Purinas, que antes habíamos asignado un valor de 0; Que pase al siguiente
elemento(n) de la secuencia(x)
y que vuelva a hacer lo mismo:
}
return((Purinas/(length(x)))*100)
}
Pirimidinas<-function(x) {
Al igual que como lo hicimos con la primer funciòn, asignamos una variable llamada
Pirimidinas
con el valor inicial de 0:
{
Pirimidinas <- 100-Purinas(x)
}
Finalmente lo que hacemos es decirle a R que nos arroje el resultado de la resta anterior,
que es el resultado del porcentaje
de Pirimidinas en la secuencia de ADN:
return(Pirimidinas)
}
Para finalizar lo que se ponen, son ejemplos de casos en los que se prueba o se utiliza la
función, de tal forma que nos aseguremos
de que las dos funciones esta escritas y definidas correctamente, estos ejemplos, se
escriben en forma de comentarios precedidos por
el símbolo de numeral #:
#> Pirimidinas(c("A","T","T","G","G","G"))
#[1] 33.33333
#> Purinas(c("A","T","T","G","G","G"))
#[1] 66.66667
#> Purinas(c("A"))
#[1] 100
#> Pirimidinas(c("A"))
#[1] 0
**Variable Scope
Una variable/objeto que se crea dentro de una función, es llamada una variable local,
puesto que es temporal y solo se utiliza
dentro de la función, mientras se efectúan los cálculos u operaciones, y una vez
obtenido el resultado esta variable es eliminada.
En nuestra función de ejemplo las variables "Purinas" y "Pirimidinas" a las que les
asignamos 0 inicialmente, al igual que la variable
n, son variables locales.
De tal modo que cuando llamemos a "n" por fuera de la función, en la consola de R, nos
dira
que el objeto 'n' no existe y que no lo encuentra.
y si llamo a "Pirimidinas" en la consola de R, el me dirá que Pirimidinas es una función
que llame con ese nombre
, pero no me lo reconoce como una variable por fuera de la función:
------------------------------------------------------------------------------------
> Pirimidinas(c("A","T","T","G","G","G"))
[1] 33.33333
>n
Error: object 'n' not found
> Pirimidinas
function(x) {
Pirimidinas <- 0 # asignar el valor de 100 a Pirimidinas
{
Pirimidinas <- 100-Purinas(x)
}
return(Pirimidinas)
}
> care_perro <- 08071988
------------------------------------------------------------------------------------
De manera que se pueden definir variables locales dentro de funciones, que tengan los
mismos nombres de variables
globales por fuera de la función o inclusive con el mismo nombre de la función, y R no
se confundirá y mantendrá ambas variables
como separadas.
Y finalmente la variable "care_perro" es una variable global que creamos por fuera de
una función y que contiene el número
08071988 .
Esta función la llamamos "firulallo" y "no tiene cuerpo", puesto que dejamos abierto o
vacía la definición de la función per se con los corchetes
y los tres puntos, ( { ... } ).
Mientras tanto, lo que si definimos son argumentos que se ejecutaran por defecto,
siempre y cuando el usuario no cambie el argumento o lo re-defina,
es decir, para y definimos un valor de 5 y para z, que es una variable lógica la definimos
como FALSE o F;
de tal forma que si ejecutamos la función sin cambiar los argumentos por defecto, R
utilizará los que definimos al escribir la función.
Para un objeto x, con valor a 100, utilizando los argumentos por defecto:
>firulallo(100)
Para un objeto x, con valor de 100, cambiando los argumentos por defecto:
Para un objeto x, con valor de 126, cambiando solo un argumento por defecto (el otro
argumento, el que no cambiemos, se ejecutara por defecto):
>firulallo(126, y=45)