Algunas estructuras de programación.
Creación de funciones en R                             Atrás

Estructuras de programación
Creación de funciones en R
 

Estructuras de programación                                                Arriba

R permite crear estructuras repetitivas (loops) y la ejecución condicional de sentencias.
A este fin, los comandos pueden agruparse entre llaves, utilizando la siguiente sintaxis:

{comando1 ; comando2; comando3 ; ....}
 

El bucle for

Para crear un bucle repetitivo (un bucle for), 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)
> 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

La sintaxis es como sigue:

while ( condicion logica)  { expresiones a ejecutar }

Por ejemplo, si queremos calcular qué número es el mayor cuyo cuadrado
no excede de 1000, podemos hacer:

> 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. 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

La sintaxis general es:

if (condicion) comando1 else comando2

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                                                          Arriba

La estructura general de una función en R es la siguiente:

nombre <- function(argumento1 , argumento2, .....)   comandos

Por ejemplo, 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.027650
> sd(x)           # La definida en R coincide con la nuestra
[1] 3.027650

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
 

Alcance de las variables

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:

> y <- 10           # Definimos la variable y
> cuadrado <- function(x){ y <- x^2 ;  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, y no ha cambiado. La y local desaparece
[1] 10

Parámetros por defecto

Una función puede tener varios argumentos, y podríamos querer omitir especificar
algunos de ellos, asumiendo que la función tomará por defecto unos valores
preespecificados.

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:

> desv <- function(x,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, se divide por n-1
[1] 9.166667
> desv(x,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 ello, la sintaxis es:

f <- function(x, ...) { cuerpo de la función }

f <- function(...,x) { cuerpo de la función }

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:

> f<-function(...){ L <- list(...) ; return(L)}
> f(1,2,3)
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3

> f(c(1,2),c(3,4,5))
[[1]]
[1] 1 2
[[2]]
[1] 3 4 5

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

}

Veamos un ejemplo sencillo:

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

Es evidente que la función puede hacerse bastante más completa, pero la idea queda clara.
 
 

Arriba


 

Atrás                                    Adelante