You are on page 1of 35

## Funciones

# La creación de funciones es la principal utilidad
de un lenguaje programado,
# aún en un lenguaje orientado a la estadística
como R. Anteriormente nos
# ocupamos de distintos tipos de objeto que podemos
encontrar en R. En la pre-
# sente unidad nos dedicaremos a la comprensión de
la estructura y funcionamien-
# to de las funciones, así como a la creación y
corrección de las mismas.

## ¿Para qué hacer funciones?

# El primer motivo que encontramos para escribir
funciones es la practicidad.
# Esto es cierto en situaciones en las que se debe
realizar un procedimiento
# que requiere la ejecución de comandos en un orden
específico, o volver a eje-
# cutar una serie de comandos que nos quedó muy
atrás en el historial y sabemos
# que los vamos a tener que utilizar nuevamente. En
casos como estos, puede
# ahorrarnos tiempo y esfuerzo escribir una función
que contenga estos pasos y
# que podamos utilizar una y otra vez. Un ejemplo
claro de esto es la función
# 'sort', que ejecuta las instrucciones necesarias
para ordenar un vector.

x <- sample(1:15) # Si generamos un vector
muestreando los valores de 1 a 15
sort (x) # la ejecución de 'sort' nos devuelve
este vector ordenado.

# Dentro de esta función están las instrucciones
necesarias para realizar la
# tarea, y que se ejecutarán sin necesidad de
hacerlo paso a paso.

sort

# Más adelante volveremos sobre la estructura de
las funciones, su anatomía,
# para entender qué exactamente es cada uno de sus
componentes.

# El segundo motivo, que se desprende del anterior,
es la generalización.
# Muchas veces vamos a generar una función para
atender a un caso particular,
# a un determinado set de datos o situación. Sin
embargo, en la medida en que
# las funciones que escribimos nos resulten útiles,
es importante poder pasar
# de su aplicabilidad a valores fijos a utilizar
variables que podamos modificar
# en cada caso. Veamos un ejemplo, en la creación
de una función que nos permita
# calcular el área de un triángulo.

# El problema planteado es el área de un triángulo
que presenta 3 cm de base y
# 4 de altura. La forma más sencilla de estimar la
misma es, directamente,

4 * 3 / 2

# Sin embargo, si necesitamos hallar el área de
varios triángulos, podemos crear
# la función 'area', utilizando base y altura como
variables.

area <- function(a, b) {
a * b / 2
}

area (4, 3) # Podemos usarla con las medidas de
nuestro triángulo
area (12, 10) # o de cualquier otro.

# En este caso, es muy sencillo entender que se
pasó del caso particular de un
# par de valores de base y altura a una función que
corre para cualquier par de
# valores. En este sentido, la abstracción es
similar a lo que uno ve en las
# matemáticas, en el sentido de pasar de valores
particulares a símbolos que
# pueden ser sustituidos en una ecuación por
valores conocidos, logrando poder
# aplicar la función a cualquier situación similar.

# Otro ejemplo más ilustrativo puede ser el
siguiente: teniendo un vector `x` de
# 15 elementos, podemos calcular su promedio de la
siguiente manera:

x <- rpois(15, 4)
p <- sum(x) / 15
p

# Este código sólo sirve para `x` u otro vector con
15 elementos. Si queremos
# adaptar este código para calcular el promedio de
cualquier vector, indepen-
# dientemente de su longitud, vamos a tener que
sustituir este valor por la
# longitud de un vector genérico, empleando
`length(x)`.

p <- sum(x) / length(x)

# En este caso, aún sin crear una función, hemos
ganado en abstracción, ya que
# salimos del caso concreto en el que `x` tiene 15
elementos y ahora podemos

6. Esto es cierto. f <. En este caso # puede ser más sencillo crear una función que haga la operación deseada. 23)) # Y sabemos que devuelve un resultado para cualquier vector # Si bien puede parecer un derroche crear una función para una operación tan # sencilla. 7)] <.# utilizar esta línea de código para hacerlo para cualquier vector `x` posible. consideremos la situación en que nuestro vector # presenta NAs: x <. por ejemplo creando un objeto 'v' dentro de la misma que sea # nuestro vector sin los NAs.NA f(x) # En tal caso. deberemos agregar un comando para descartar dichos valores en la # propia función.function(v) { p <.sum(v) / length(v) p } f(rpois(19. pero también debe tenerse en cuenta que se pueden agregar nuevas # capacidades y detalles a la función. Sin mencionar que el # vector tiene necesariamente que llamarse `x` para que funcione. # Pero aún dependemos de esta línea de comando. 10) x[c(3. f <.rpois(20.function(v) { . que podemos haber olvidado o # puede haber quedado muy atrás en el historial y volver a encontrarla para # ejecutarla puede ser un derroche de tiempo y esfuerzo.

# La función que utilizaremos para este fin será 'function'.function() print("Hola mundo") g() # En la próxima lección exploraremos los componentes que hacen a las funciones. vamos a tener que escribir # las instrucciones a ejecutar en una nueva función.sum(v) / length(v) p } f(x) # Como último detalle.na(v)] p <. # en una suerte de lección de anatomía de las mismas. # La nueva función 'nombre' va a evaluar las instrucciones en función de # los argumentos provistos. # Es posible crear funciones sin argumentos. no es necesario que las funciones representen una # abstracción o generalización de una operación a partir de un caso concreto. arg2. salvo para tareas sencillas. y se utiliza # de la siguiente manera: nombre <. #### Escribir funciones en R # Muchas veces. para sorpresa de nadie. La # clase de este nuevo objeto es "function".v[!is. . v <. y devolverá posteriormente una salida. arg3) instrucciones # Con este comando la función es *definida* (pero no *ejecutada*). cosas tan simples como: g <.function(arg1.

# Es posible definir funciones sin argumentos.function() print("¡No hay problema!") alf() # Es una función con una sóla salida posible. la función puede ser ejecutada de la siguiente manera: nombre(argumentos) ## Argumentos: # En este caso los argumentos se llaman "arg1". al igual que al llamarla. Por ejemplo: alf <. En el # momento de definirla. podemos # ver la definición de la función: alf sd aov lm ## Instrucciones: # Las instrucciones son comandos de R que se van a ejecutar cada vez que # el usuario llame la función. aunque generalmente esto # no es de gran utilidad. estos deben estar # separados por comas. "arg2" y "arg3". el único comando . En el ejemplo de "alf". # Nota: para chequear cuales son los argumentos de cualquier función # podemos usar la funcion "args": args(alf) args(rnorm) args(sample) # Si escribimos el nombre de la función a secas (sin paréntesis).# Una vez definida.

R nos indica que está faltando el argumento "x". with no default # Muy acertadamente. la "x" usada por la función toma el # valor que el usuario decide darle. "años.\n") cat(texto) } edad(220) # Vengo de Melmac. edad("cuarenta") # Vengo de Melmac. tengo cuarenta años. tengo". esto será la frase "¡No hay problema!" (es lo que # devuelve la función print). x.\n") : # argument "x" is missing. ya lo dijimos. tengo". el # cual no tiene valor por defecto. # Como se puede ver en el ejemplo. # Si se define una función con argumentos. Para el caso de # la función "alf". tengo 220 años.paste("Vengo de Melmac. x. estos serán los objetos # presentes en el momento en que se ejecuten las instrucciones. ese algo es # el último objeto generado dentro de las instrucciones. y para el caso de . Si el usuario no da valor alguno. y por defecto. Por # ejemplo: edad <. "años.# indica que hay que imprimir la frase "¡No hay problema!". R # va a indicarlo con un mensaje de error: edad() # Error in paste("Vengo de Melmac.function(x) { texto <. # Salida: # Toda función devuelve algo.

Por ejemplo."edad". en la función "edad" los objetos "x" y "texto" # existen dentro del ambiente de la función y toman valores particulares a # raíz de las instrucciones de la función y de los valores ingresados por # el usuario. a # través de las instrucciones. el objeto "texto" . Más abajo se muestran otras formas de # definir la salida de una función. el R interpreta que la función se # termina con el primer comando de las instrucciones (ver más abajo). # ya que dentro de la función "x" toma el valor 4. La # utilidad de las llaves consiste en poder usar varios comandos dentro de # la función. # Un detalle importante es que las instrucciones de la función se # ejecutan en un "ambiente paralelo" a nuestra área de trabajo. # 2. indicando el comienzo y el fin de los mismos. Si estas no se usan. En el caso anterior. será NULL.los que están definidos dentro del código de la función. En el ejemplo anterior sería "x". En nuestra área de trabajo puede existir un objeto llamado # "x". sin embargo esto no va a afectar el resutlado del comando "edad(4)". por lo que # es fundamental tener claro qué objetos están presentes en este # ambiente. # El lector atento habrá notado que se usaron las llaves "{" "}" la # última vez.los que están definidos como argumentos de la función (dentro del # paréntesis). que es # lo que devuelve la función cat. # Los objetos que existen dentro del ambiente de la función son: # 1.

funciones: las mismas siempre existirán dentro de nuestra # función. siempre y cuando no se genere otro objeto # con el mismo nombre con las instrucciones. En el ejemplo visto caso no # hay ningún caso de este tipo de objetos que usemos.los que estaban definidos en el área de trabajo en el momento en que # fue definida la función. Esto # significa que si tenemos que repetir varias veces una serie de # instrucciones siguiendo una determinada secuencia.1) . # Estas reglas no se aplican para objetos de la clase "function". # La principal ventaja de las funciones. b=0. pero al final de # la lección ponemos una modificación como ejemplo. # Este ambiente paralelo sólo existe durante la ejecución de la # función. cambiando los argumentos.# tiene estas características. la cual estará disponible para reutilizar cuando # la necesitemos. es juntar una serie de instrucciones. podremos hacerlo # escribiendo una función. # 3. # Un ejemplo muy simple: sinexp <. a=1. de la complejidad # que sea.function(x. siempre y cuando hayan sido definidas de antemano. como ya hemos planteado # anteriormente. es # decir. antes y después todos los objetos (excepto los que cumplen con # la condición 3) van a estar ausentes de nuestra área de trabajo. para poder ejecutarlas en una sola línea de código.

# La ecuación para hacer eso es sd / (n .... a y b: sinexp(10) # evaluada para x=10 sinexp(1:10) # evaluada para todos los x=1. que serán los que R usará en caso de # que el usuario no ingrese otros. 0. 5. 3. b=0.05 de distancia) sinexp(seq(0. .05)) # evaluada para una secuencia de valores (0.08). # por lo que esta es la salida de la función. b=0. 5. # Un ejemplo "de libro": el cálculo del error estándar de un promedio. # Esta función tiene una sóla instrucción. sin(a * x) * exp(x ^ b) # Aquí el último objeto generado es el resultado de la ecuación escrita.1) ^ (1 / 2). 2. # Tiene 3 argumentos: x. 10 sinexp(seq(0. 0. a través del "=": esto indica que "a" y "b" # tienen valores por defecto 1 y 0.05). # Usando la función podemos evaluar la salida para distintas # combinaciones de x.08 curve(sinexp(x. la cual se pone (generalmente) # en la segunda línea y con una indentación. que # es una función que no existe en el paquete básico de R. donde 'sd' es el # desvío estándar y 'n' la cantidad de . a y b.08) # a=2. a=2. Los dos últimos tienen agregada la # asignación de un valor. n=1e4) # hace una gráfica con la función ## Ejemplo: "error estándar".1. 2. 0. to=30.

# La función la vamos a escribir de la siguiente manera: SEM <.1) } # Pero mejor vamos a explicar bien cada una de sus partes: SEM <.rm' # (para definir si se remueven los NA de 'datos'). # .Asignamos la función al objeto 'SEM'. es el alternativo # al 'if'). if (na.function(datos. VAR <. para indicar el comienzo de las # instrucciones # Los argumentos pueden ser objetos de cualquier clase y deben ir # separados por comas. na. Este argumento por # defecto será FALSE. dentro del espacio de la función el objeto 'VAR'.rm = FALSE) { # Primer línea: # .na(datos)] # Crea. # .Ponemos la llave de apertura "{".sd(VAR) N <. donde 'VAR' va a ser .length(VAR) SD / sqrt(N .na(datos)] else VAR <. else VAR <.datos # Instrucciones por defecto ('else'.También escribimos los argumentos de la misma.function(datos.datos[!is. es decir.rm = FALSE) { if (na. que no es # otra cosa que 'datos' con los NA extirpados.rm) VAR <. que van a ser un objeto # 'datos' (el cual debe ser del tipo vector) y un objeto lógico 'na.rm) # Aquí van las instrucciones que se ejecutan si na.observaciones.datos[!is.datos SD <.rm es TRUE. na. # si decidimos remover de la muestra los NA (es una sóla instrucción).

replace = T) .length(VAR) # 'N' va a ser la cantidad de observaciones que tenemos SD / sqrt(N . # Usando este comando. para lo que vamos a crear un # objeto 'x' que consiste en una serie de observaciones de alguna # variable aleatoria. bajo el tema "Estructuras de Control". Alternativamente.1) # Y. se puede usar el comando "return(out)". es posible definir la salida de la función en # cualquier parte de las instrucciones y no necesariamente en la última. SD <. # De hecho. 25.sample(1:100. Una función similar es "invisible". # cuya única diferencia es que no imprime por defecto el resultado en la # consola al terminar la ejecución de la función. # Nota: se va a profundizar en el uso de if/else en otras lecciones del # curso. # Ahora vamos a probar nuestra función.simplemente los datos # de la entrada.sd(VAR) # Calculamos el desvío estándar de 'VAR' N <. } # Y cerramos la llave. cuando se ejecuta "return" se dejan de ejecutar instrucciones # y se devuelve el objeto indicado. en # donde "out" es el objeto que queremos que sea la salida de la función. x <. introducimos la ecuación de la que # partimos. indicando el fin de las instrucciones. # Nota: el último objeto generado en esta función es el producto de la # ecuación del error estándar. finalmente. por lo cual esta es la salida de esta # función.

usando el nombre del argumento # en el momento de llamar a la función logi. .) { x <...rm = TRUE) # Y volvemos a tener un resultado.function(ini=-8.12.. int=0. introduciendo algunos NA. # incluimos el argumento ".. los argumentos # "col".. Esto permite pasar argumentos a la función # plot sin que estén definidos de antemano. type='l'.".05. ## Ejemplo: el argumento especial "." de esta manera: logi <. Por ejemplo. na. SEM(datos = x.seq(ini. by=int) y <.NA # Y volvemos a ejecutar 'SEM' para 'x'.. x[c(2. "lwd".) # acá también se agrega ". fin=8." # Considerando una función simple que grafica una curva logística.. fin. ." return(y) } logi() # La lista de argumentos contiene "..25)] <..... el cual se repite dentro del # llamado a la función plot. "ylab" y "main" se pueden agregar: .5. lo que da un resultado "feo": SEM(datos = x) # Para arreglar este asunto. vamos a indicarle en los argumentos que no # debe tener en cuenta los NA de 'x'.SEM(datos = x) # Ahora vamos realizar un cambio en 'x'.exp(x) / (1 + exp(x)) plot(y ~ x.

por ejemplo: source("/camino/hacia/el/script. Se pueden agrupar varias definiciones en un # mismo archivo. # Una estrategia muy útil es guardar las definiciones de las funciones # que hemos creado en scripts. col="blue". col="blue".logi(-15.logi(-15. lwd=4) x <. sino que las vamos a tener que volver a cargar para volver a # utilizarlas. sobre todo si # tienen una cierta complejidad. una vez guardada el área de trabajo o el script # en que la definimos. ylab='f(x)') # El mismo principio se puede aplicar a cualquier función. Las funciones que creamos no quedan incorporadas a # R en sí. de forma que cada archivo # es una "biblioteca" de funciones. En el momento de iniciar la sesión de # R basta con usar la función "source" para traer la biblioteca al área de # trabajo. lwd=4. 15. 15. particularmente si son funciones que están relacionadas # (pueden depender unas de otras. 15. De todos modos simplifican mucho el trabajo cuando debemos # realizar tareas que requieren varias instrucciones. # pero reduciendo considerablemete el espacio utilizado y perimitiendo # reutilizar la función. 15.R") .logi(-15. col="blue". ylab="Curva Logística") x <. # Como hemos visto las distintas funciones permiten ejecutar una serie de # instrucciones que requieren ser evaluadas en una determinada secuencia. lwd=4. por ejemplo).logi(-15. main="Curva Logística". col="blue") x <.x <.

# 6. que las funciones utilizadas sean # las opciones más 'económicas' en memoria y procesador para realizar # la tarea deseada: si armamos un tándem de funciones muy demandantes # el resultado va a ser un monstruo devorador de recursos.En este esquema previo armar la secuencia de comandos en el orden que # deberían ejecutarse. # 7.# El archivo "estimaPi. No frustrarse si las funciones no nos # quedan bien de entrada.Utilizar herramientas de depuración (ver la lección correspondiente) # ayuda a descubir los errores de programación. en la medida de lo posible.La práctica hace al maestro. no hay una receta universal para escribir # funciones.Intentar probar varias veces con datos artificiales (y sobretodo con # errores artificiales) nuestra función para comprobar que anda bien. # Como comentario final. pero hay algunas recomendaciones que facilitan mucho la # tarea: # 1.Tratar. # 3. .Hacer un esquema previo de qué es lo que queremos de nuestra función # 2. ya que # además de facilitar la colaboración con los colegas sirven # fundamentalmente para identificar fácilmente los comandos que puedan # estar funcionando mal. # 5.R" es un script con 2 funciones incluidas que # ilustra esta idea. # 4.Armar el script siguiendo las recomendaciones de estilo.

Su finalidad es poder encapsular fragmentos de código que necesiten ser ejecutados en múltiples ocasiones. "años y". y. con la posibilidad de ejecutarlos en cada ocasión con diferentes parámetro. las funciones aumentan la legibilidad de un programa. el objeto "y" es usado por la función para completar la # frase de salida.\n") cat(texto) } edad(8) # Vengo de Melmac. x. a pesar de estar definido por fuera de las # instrucciones y los argumentos: y <. tengo". # Como se puede ver. de modo que es más fácil de entender para uno mismo y para los demás en caso de compartirlo. 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."meses.function(x) { texto <.5 edad <.paste("Vengo de Melmac. tengo 8 años y 5 meses. A su vez. . ########################## # Apéndice: se muestra un ejemplo de una función con un objeto presente en el # ambiente de la misma.

1 Introducción o 1.4 Retorno de valores  2 Reglas de alcance (Scoping Rules) Funciones Introducción Las funciones en R son tratadas como cualquier otro objeto.function(<argumentos>) { ## Código de la función (function body) } Luego. el cual crear objetos de tipo function.3 El argumento … o 1. Para crearlas utilizamos el comando function(). Tabla de Contenidos [ocultar]  1 Funciones o 1. para llamar a la función simplemente escribimos el nombre de esta: f <. de la siguiente manera: f <.2 Argumentos o 1.function() .

lado1 * lado2 print(paste("el área es ". area_rectangulo <. { cat("Hola Mundo") } f() Hola Mundo class(f) "function" Las funciones poseen 3 partes:  El cuerpo (body)  Los argumentos (formals)  El ambiente (environment) f <. lado2) { area <. area)) } .function(x.function(lado1. 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 <.area_rectangulo(2. y es en este momento que se genera un error. en el caso anterior. Lo que sucederá es que la función se ejecutará hasta el punto en que debe ser utilizado el argumento faltante. el valor 2 se pasa a la variable lado1. y.lado1 * lado2 print(paste("el área es ". en vez del <-. lado2 = 3) "el área es 6" Este ultimo método es el más recomendable cuando las funciones tienen un gran numero de argumentos. 3) "el área es 6" formals(area_rectangulo) $lado1 $lado2 Cuando se hace un llamado a una función. Por ejemplo. mientras que el valor 3 se pasa a la variable lado2. esta terminará su ejecución sin generar error. Esto es simplemente una cuestión de estilo. Algo a notar cuando asignamos valores a los argumentos es que se suele utiliza el operador =.function(lado1. area)) } area_rectangulo(lado1 = 2. ya que de otro modo seguiría funcionando correctamente la código. En caso de que la función nunca utilice el argumento faltante. f <. pero uno de estos no lo pasamos. Este modo de funcionamiento se debe a que R evalúa las instrucciones al momento de ejecutarse (Lazy Evaluation).function(x. y no antes. z) { print(x+y) print(z) } f(x = 2. Ahora supongamos que hacemos una llamada a una función que tenga una serie de argumentos. lado2) { area <. el orden en que se pasan los valores de los argumentos corresponde con la ubicación de estos en la delación de la función. Si queremos indicar explícitamente que valor asignar a cada argumento debemos indicar el nombre de este al llamar a la función. y = 0) 2 .

1.2262557 0. Por ejemplo: f <. mean = 0.676089 Cuando un argumento es pasado por nombre.3460583 rnorm(3. 10) 2. tiene 3 argumento: la cantidad de muestras a generar (n).function(x = NULL.6465698 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. sd = 1) Como vemos. este representa la cantidad de muestras a generar. Esta genera números aleatorios a partir de una distribución normal. str(rnorm) function (n. la media de la distribución (mean) y el desvió estándar (sd).4596911 1. De este modo se puede hacer una combinación de asignación de argumentos por posición y por nombre. Si indicamos solo un número.331487 -19. . 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.8456187 1.null(x) & !is. 1) -0. y = NULL) { if (!is. dejando por defecto los otros dos argumentos con valores por defecto (lo que haría que la función genere numero a partir de una distribución normal estándar) rnorm(3) -0.1237811 rnorm(3.407747 -11.Error in print(z) : argument "z" is missing.null(y)){ print(x+y) }else{ print('faltan valores') } } f(x = 2. este es quitado de la lista de orden de asignación de valores al llamar a una función.

92323 98. sumar_pares <. De este modo.) if(!is.93423 97. 100) # equivalente a: n = 5.48214 103.98517 109. m = 100) 101..c(. podemos pasar a una función una cantidad no prefijada de valores..contador + n } } contador } sumar_pares(1:10) 30 . denominando … (tres puntos).numeric(valores)) return('NaN') contador <. De este modo podemos llamar a una funciona e indicar solo una parte del nombre de cada argumento. por lo que debemos tratar de evitar su uso. sd = 10 106. Asignación por posición En general no es buena practica la utilización de coincidencias parciales.70806 Para indicar los nombre de los argumentos al llamar a una función.50723 El orden en que se hace la comprobación de argumentos es: 1.function(.) { valores <.. R permite que haya coincidencia parcial en estos. Coincidencia parcial del nombre del argumento 3. Este tiene la capacidad de capturar todos los valores pasados a la función que no coinciden con ningún argumento. El argumento … Hay un argumento que tiene un uso especial en R.0 for(n in valores){ if(n%%2 == 0){ contador <.48912 107.96486 113. sd = 10. rnorm(5.. mean = 100. s = 10.67484 91.70763 91. Coincidencia exacta del nombre del argumento 2. rnorm(5.

0 frase <. Para esto tenemos dos posibilidades. ## Función que cuenta la cantidad de vocales en una cadena que ## se pasa como argumento contar_vocales <. "u")) { cantidad_vocales <.cantidad_vocales + 1 } } cantidad_vocales } resultado <.).. En este ultimo caso. "e". Por ejemplo.Como vemos.)o una lista con list(.strsplit(frase. esta finaliza inmediatamente devolviendo el valor indicado.. "i". para trabajar con los valores capturado por … podemos convertirlos a un vector con c(. "")[[1]] for (i in frase) { if (i %in% c("a".function(frase) { cantidad_vocales <. nuevamente") resultado 9 La segunda alternativa es indicarlo explícitamente mediante el comando return().contar_vocales("Hola mundo. en caso de que un . Lo común es reservar esta alternativa para devolver “señales” en caso de que la función tenga inconvenientes.tolower(frase) frase <. Retorno de valores Las funciones anteriores solamente realizan una seria de pasos y finalizan sin devolver ningún valor.. "o". En muchas ocasiones deseamos que las funciones al finalizar su ejecución devuelvan algún valor. cuando se ejecuta esta instrucción dentro de una función.. 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.

. y es posible para un ambiente tener múltiples ambientes hijos.argumento no sea consistente con lo esperado podemos devolver algún valor que nos indique de esta situación. sqrt(n) } calcular_raiz2(2) 1.function(n) { # Verifico que el que número pasado no sea negativo if (n < 0) return("Numero negativo") # En caso de que los argumentos sean consistentes. si hacemos x <.function(x) { x + z } En la mayoría de los lenguajes de programación. R busca el valor en el ambiente y encuentra que vale 3. Cada ambiente tiene un ambiente padre. Un ambiente es una colección de pares (símbolo. Por ejemplo. x # objeto que devuelve la función } # Ejemplo calcular_raiz2 <. esta sentencia crea el par (x. 3) en el ambiente donde se ejecutó la instrucción. Como z no está definida dentro de la función (a estas variables se las conoce como free variables).3.function(<argumentos>) { if (<alguna_condición>) return(<señal>) # Código de la función . R irá a buscar su valor en el ambiente donde la función fue definida.. f(10) Error in f(10) : object 'z' not found . f <. el ambiente de una función controla como se encuentra el valor asociado con una variable dentro de ella. # continuo con la ejecución de la función. f <. Pero en R esto es valido debido a que utiliza lo que se conoce como lexical scoping para encontrar el valor asociado. De esta forma. valor). Si luego queremos recuperar el valor de la variable x.414214 calcular_raiz2(-2) "Numero negativo" Reglas de alcance (Scoping Rules) El ultimo componente de una función es su ambiente (environment). esta declaración conduciría a un error debido a que la variable z no está definida dentro de la función. Por ejemplo. El único ambiente que no tiene padre (raíz) es el empty environment.

Estos significa que se va a buscar el valor de la variable al ambiente donde esta fue definida (y no donde fue llamada). y se encuentra con x * z. En el primer caso. Esta acción crea un par (z. pero ¿qué valor toma la variable z? Como dijimos.1 f(10) 11 Básicamente. por lo que pasa a buscarla en el ambiente padre y encuentra: g <. Acá vemos claramente que x vale 3.1 f <.function(x) { z <. pasa a buscar el valor de la variable en el ambiente padre. R utiliza lexical scoping. y encuentra el par (z. En este paso. Luego busca a la función g. A continuacion se evalúa 2*z + g(x). pero no la encuentra definida dentro de la función f. Las reglas de alcance de un lenguaje determinan justamente como un valor es asociado con una variable. lo que hace R al necesitar evaluar el valor de z es ir a buscarlo dentro la función f. 10)en el ambiente de la función f. Como no lo encuentra definido. Veamos unos ejemplos: z <.function(x) { x * z } ¿Qué valor devolverá f(5)? Veamos. Por lo tanto. el valor de z será 1. Cuando llamamos a la función f lo primero que se evalúa es z <.z <.10 2 * z + g(x) } g <.function(x) { x * z } Ahora evalúa g(5). mientras que en el segundo caso sí lo está. R busca el valor de la variable z en el ambiente de la función f. y por lo tanto: f(5) 25 . z sigue sin estar definido. 10).10.

No obstante.} ..function(x) { g <. y encuentra que ahora el valor de z es 10. hay que ser cuidadoso al trabajar..function(x) { x * z } z <. Como ahora g está definida dentro de f. sin darnos cuenta. Un típico problema aparece cuando creamos una función. Creación de funciones en R Acciones de Documento    Autor: Alberto Muñoz García Estructuras de programación R permite crear estructuras repetitivas (loops) y la ejecución condicional de sentencias. Luego de debuggear el código nos damos cuenta de que en la función está participando una variable que. y por lo tanto: f(5) 70 Este comportamiento permite realizar operaciones. sin las cuales muchos paquetes no podrían existir.. Algunas estructuras de programación. y dado que no aparec ningún error (porque la función toma su valor de otro ambiente) podemos continuar trabajando y llegar a resultado erróneos más adelante. comando2.Ahora vemos que sucede si la función g la hubiésemos definido dentro de la función f: f <. El peor caso surge cuando no nos damos cuenta de que el valor que obtenemos es incorrecto. la cual no devuelve el valor incorrecto. comando3 . . R va a buscar el valor de z en su nuevo ambiente padre. A este fin. los comandos pueden agruparse entre llaves. no está definida en la función y toma su valor de otro ambiente. que es justamente el ambiente de la función f.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). utilizando la siguiente sintaxis: {comando1 .

xlim=c(0. los bucles for son lentos en R (y en Splus).El bucle for Para crear un bucle repetitivo (un bucle for). si queremos calcular qué número es el mayor cuyo cuadrado no excede de 1000. y deben ser evitados en la medida de lo posible.10) > plot(x. podemos hacer: . El bucle while La sintaxis es como sigue: while ( condicion logica) { expresiones a ejecutar } Por ejemplo.col=i) No obstante. la sintaxis es la siguiente: for (i in listadevalores) { secuencia de comandos } Por ejemplo: > for(i in 1:10) { print(i)} [1] 1 [1] 2 [1] 3 [1] 4 [1] 5 [1] 6 [1] 7 [1] 8 [1] 9 [1] 10 Un ejemplo de dibujo: > x = seq(-10.10).ylim=c(0.10)) > for(i in 1:10) + abline(h=i.x.col=i) > for(i in 1:10) + abline(v=i.

una para guardar los números pares de 1 a 10. y el while() permitió entrar en el bucle. su cuadrado (961) no excedía 1000. impar en otro caso > pares [1] 2 4 6 8 10 > impares [1] 1 3 5 7 9 Creación de funciones en R .> cuadrado = 0 > while(cuadrado<=1000) +{ + n<-n+1 + cuadrado<-n^2 +} > cuadrado [1] 1024 >n [1] 32 > 32^2 [1] 1024 ¿Qué ha sucedido? El cuadrado de 32 excede 1000. lo que hizo n=32. 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. En realidad. vamos a crear dos listas. El número correcto sería en este caso n-1 = 31.i) # Si al dividir por 2 sale 0 + else impares<-c(impares.i)} # el numero es par. cuando n valía 31. Ejecución condicional: if La sintaxis general es: if (condicion) comando1 else comando2 Por ejemplo.

3] [.5419452 0.2.1578703 1..36219826 -1.5147970 1.027650 > sd(x) # La definida en R coincide con la nuestra [1] 3.La estructura general de una función en R es la siguiente: nombre = function(argumento1 .x^2 .3609624 [3.0222260 0.6675674 [2. 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).6712974 -0.2854502 0.2576365 0.) comandos Por ejemplo.1595845 1. y desaparecen al terminar la ejecución de la función... La y local desaparece [1] 10 Parámetros por defecto . . podemos definir una función que calcule la desviación típica: > desv = function(x){sqrt(var(x))} # Definimos la función > x<-1:10 # Generamos datos > desv(x) # Utilizamos la función [1] 3.03345786 -0.0140156 Alcance de las variables Las variables definidas dentro del cuerpo de una función son locales.6669992 > apply(x.2] [. se la puede llamar y utilizar como a cualquiera otra función predefinida en el sistema.4770036 -0.] 0..6352143 -1.] 0.39006069 0.6877219 1.5] [1.] 0. y no ha cambiado.3508383 -0. argumento2.3215741 -0.nrow=3) >x [.4] [.027650 Una vez definida una función. Por ejemplo.1] [.desv) [1] 0. Por ejemplo: > y = 10 # Definimos la variable y > cuadrado = function(x){ y <. return(y)} # Definimos otra y local >x=2 # Asignamos valor a x > cuadrado(x) # Calculamos el cuadrado de x : Se hace y=4 (localmente) [1] 4 >y # Sin embargo.

Una función puede tener varios argumentos. la función podría llamarse sin hacer referencia explícita a x (por ejemplo f(2) ).166667 > desv(x... vamos a redefinir la función desviación típica.list(. Como ejemplo. se divide por n-1 [1] 9. Para ello..) . y podríamos querer omitir especificar algunos de ellos.2. return(L)} > f(1.. definiremos una función que simplemente devuelve sus argumentos: > f = function(. no podría saber si nos estamos refiriendo a x o a uno de los argumentos variables. .) { cuerpo de la función } f = function(.. asumiendo que la función tomará por defecto unos valores preespecificados. la sintaxis es: f = function(x.. de modo que tengamos la posibilidad de calcular la desviación típica corregida y sin corregir: > desv = function(x.3) [[1]] [1] 1 [[2]] [1] 2 [[3]] [1] 3 . dado que el sistema. al encontrar primero los argumentos variables.n=length(x)-1){ sum((x-mean(x))^2)/n} # Definición de # la función > x<-1:10 # Generación de un conjunto de datos > desv(x) # Desviación típica corregida (al no especificar el # segundo parámetro.10) # Desviación típica sin corregir [1] 8.25 Funciones con un número variable de argumentos En R es posible definir funciones con un número variable de argumentos. para entender como funciona al tema..x) { cuerpo de la función } En el primer caso. Vamos a poner un ejemplo en dos fases.){ L <. En primer lugar. En el segundo caso deberíamos especificar f(x=2)...

.3.varianzas[[i]]."\n") cat("------------------------------------------------\n") } } Veamos un ejemplo sencillo: > f(c(1.6.2. varianza.var) maximos = lapply(datos.mean) # lapply aplica una función sobre una lista varianzas = lapply(datos."maximo: ".4."minimo: ".max) minimos = lapply(datos. La entrada a la función será una serie de conjuntos de datos.i.-5.2).c(1.) { datos = list(."varianza: ". es variable el número de argumentos.5 maximo: 2 minimo: 1 ------------------------------------------------ Distribución 2 : media: 4 varianza: 6..maximos[[i]].666667 maximo: 7 minimo: 1 ------------------------------------------------ ..) medias = lapply(datos.. tanto como el número de elementos de cada uno.5)) [[1]] [1] 1 2 [[2]] [1] 3 4 5 Así pues.5.7). y la salida la media. mínimo y máximo de cada uno de los conjuntos. Vamos a aprovechar esta facilidad para definir una función que devuelva algunas medidas resumen de las distribuciones que se le pasen como argumento.5 varianza: 0.> f(c(1.c(-1.medias[[i]].9)) Distribución 1 : media: 1.min) for(i in 1:length(datos)) { cat("Distribución ".2). f = function(.c(3.minimos[[i]].": \n") # La función cat es para visualizar cosas cat("media: ".

"T".9881924 minimo: 0.y) Distribución 1 : media: 0.201592 minimo: -2. En este caso el primer comentario menciona lo que hacen las funciones que se van a escribir.4985783 varianza: 0.0 # asignar 0 a Purinas for (n in x) { if (n == "A") Purinas <.143932 ------------------------------------------------ Distribución 2 : media: 0.Distribución 3 : media: 2."G".87319 maximo: 2."T".Purinas + 1 # contar las purinas } return((Purinas/(length(x)))*100) } Pirimidinas<-function(x) { Pirimidinas <."G")) #[1] 66.Purinas + 1 # contar las purinas if (n == "G") Purinas <.01329678 ------------------------------------------------ # calcular el porcentaje de purinas y pirimidinas en una secuencia de ADN Purinas<-function(x) { Purinas <."G"."G")) #[1] 33.08253697 maximo: 0.33333 #> Purinas(c("A".0 # asignar el valor de 100 a Pirimidinas { Pirimidinas <."G".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.7 maximo: 9 minimo: -5 ------------------------------------------------ O también: > x = rnorm(100) > y = runif(50) > f(x."T". .1616148 varianza: 0.100-Purinas(x) } return(Pirimidinas) } #> Pirimidinas(c("A"."G"."T".2 varianza: 30.

En pocas palabras. que antes habíamos asignado un valor de 0. cerramos el cuerpo y terminamos de escribir. 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) { Le asignamos un valor de 0 (para empezar) al porcentaje de purinas en la secuencia. a la que llamaremos "Pirimidinas": Pirimidinas<-function(x) { Al igual que como lo hicimos con la primer funciòn. entonces le sume 1 a Purinas. nuestra primer función. y a partir dse este valor empezaremos a hacer el conteo de las purinas para cada base en la secuencia: Purinas <. en este caso la secuencia de ADN.Purinas + 1 # contar las purinas Finalmente le decimos que cierre la parte de operaciones de la función con el corchete (}) y que lo ue la función nos debe arrojar (return) es el valor del ((número de las bases que sean Purinas. asignamos una variable llamada .Purinas + 1 # contar las purinas if (n == "G") Purinas <. el length(x) es el mismo número de elementos(n) de x). abrimos un loop: for (n in x) { A continuación le decimos lo que debe hacer con cada elemento n del objeto x. Que pase al siguiente elemento(n) de la secuencia(x) y que vuelva a hacer lo mismo: if (n == "A") Purinas <.Primero se define la primer función y se le da el nombre que se desee y que se aplicara al objeto x (x). se le aplicara el resto de el código de la función.0 # asignar 0 a Purinas Ahora le decimos que para cada elemento n del objeto x . es decir. multiplicado x 100). Y empezamos a escribir la segunda función. sobre la longitud (length) de la secuencia(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". en pocas palabras. le decimos que nos arroje como resultado de la función el porcentaje de bases purinicas que se encuentran en la secuencia de ADN: } return((Purinas/(length(x)))*100) } De este modo.

en nuestro caso llamaremos la función "Purinas" (previamente creada) y a 100 le restaremos el valor de el resultado de la función "Purinas" de una secuencia de ADN (x). el porcentaje de Pirimidinas será 100 menos el porcentaje de Purinas que ya calculamos previamente: { Pirimidinas <.66667 #> Purinas(c("A")) #[1] 100 #> Pirimidinas(c("A")) #[1] 0 **Variable Scope Una variable/objeto que se crea dentro de una función. se escriben en forma de comentarios precedidos por el símbolo de numeral #: #> Pirimidinas(c("A"."T".100-Purinas(x) } Finalmente lo que hacemos es decirle a R que nos arroje el resultado de la resta anterior."T"."G".0 # asignar el valor de 100 a Pirimidinas Lo siguiente es algo muy importante en R."G")) #[1] 33. de tal forma que nos aseguremos de que las dos funciones esta escritas y definidas correctamente."G")) #[1] 66."G".33333 #> Purinas(c("A". puesto que el resto de las bases de las secuencias que no son Purinas. que es el resultado del porcentaje de Pirimidinas en la secuencia de ADN: return(Pirimidinas) } Para finalizar lo que se ponen."G"."T". es llamada una variable local."T". deben explicitamente ser Pirimidinas y como es un porcentaje. son ejemplos de casos en los que se prueba o se utiliza la función. y una vez obtenido el resultado esta variable es eliminada. estos ejemplos. En nuestra función de ejemplo las variables "Purinas" y "Pirimidinas" a las que les ."G".Pirimidinas con el valor inicial de 0: Pirimidinas <. mientras se efectúan los cálculos u operaciones. puesto que es temporal y solo se utiliza dentro de la función. y es el hecho de que se puede llamar una función dentro de otra función.

R . de tal forma que si ejecutamos la función sin cambiar los argumentos por defecto. en la consola de R. **Argumentos por defecto Consideremos la función: > firulallo <. ( { . y si llamo a "Pirimidinas" en la consola de R. } Esta función la llamamos "firulallo" y "no tiene cuerpo"."G". } ). que es una variable lógica la definimos como FALSE o F.asignamos 0 inicialmente. y R no se confundirá y mantendrá ambas variables como separadas.0 # asignar el valor de 100 a Pirimidinas { Pirimidinas <. lo que si definimos son argumentos que se ejecutaran por defecto."T". 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 .y=5. es decir.. al igual que la variable n."T".100-Purinas(x) } return(Pirimidinas) } > care_perro <.. nos dira que el objeto 'n' no existe y que no lo encuentra. De tal modo que cuando llamemos a "n" por fuera de la función.08071988 ------------------------------------------------------------------------------------ De manera que se pueden definir variables locales dentro de funciones. son variables locales. para y definimos un valor de 5 y para z. pero no me lo reconoce como una variable por fuera de la función: ------------------------------------------------------------------------------------ > Pirimidinas(c("A".z=F) { . que tengan los mismos nombres de variables globales por fuera de la función o inclusive con el mismo nombre de la función."G".33333 >n Error: object 'n' not found > Pirimidinas function(x) { Pirimidinas <. el me dirá que Pirimidinas es una función que llame con ese nombre ..function(x. siempre y cuando el usuario no cambie el argumento o lo re-defina."G")) [1] 33.. Mientras tanto. puesto que dejamos abierto o vacía la definición de la función per se con los corchetes y los tres puntos.

y=45) ESO ES TODO POR AHORA Y ESPERO PRONTO PODER COMPARTIR MÁS COSAS Y QUE LES HAYA GUSTADO Y LES PAREZCA MUCHO MÁS FÁCIL AHORA! . el que no cambiemos. con valor a 100. cambiando solo un argumento por defecto (el otro argumento.utilizará los que definimos al escribir la función. utilizando los argumentos por defecto: >firulallo(100) Para un objeto x. Z=TRUE) Para un objeto x. con valor de 100. y=60. Para un objeto x. con valor de 126. se ejecutara por defecto): >firulallo(126. cambiando los argumentos por defecto: >firulallo(100.