Las funciones nos ayudan a organizar código que cumple un ‘rol’ especÃfico. AsÃ, se facilita la lectura y corrección del mismo, al crear elementos independientes. Asà mismo, usando funciones verás como integrar lo visto en las secciones anteriores.
Veremos tres elementos organizadores: input, transformación, output. Por ejemplo, si necesitas convertir un valor numérico de Fahrenheit en Celsius, el input is el valor en Fahrenheit, la transformación es la formula, y la output es el resultado en Celsius (u otro que corresponda).
# ejecutar
converterToCelsius=function(valueInFarenheit){ #input
#transformacion
resultInCelsius= (valueInFarenheit-32)*5/9
#output
return (resultInCelsius)
}
Del ejemple anterior, veamos la sintaxis de una función. El primer element es el nombre (converterToCelsius) a la izquierda de =; luego el input, que es un detalla de lo que la función espera se ingrese usando la palabra reservada function; de ahÃ, la transformación se escribirá dentro de los {}; la última fila de la transformación tiene devuelve la output (for example: resultInCelsius), para lo cual se usa la palabra clave return. Si escribes sólo la output sin usar el comando return la función aun funciona, pero disminuye su readability. El código ejemplo le ha dado una nueva función a R:
converterToCelsius(100)
He organizado los materiales de la siguiente manera:
El input no tiene que ser sólamente uno:
# 2 inputs:
XsumY=function(valueX,valueY){
###
resultSum=valueX+valueY
###
return (resultSum)
}
Veamos cómo funciona:
XsumY(3,10)
Algún input puede tener un valor default:
riseToPower=function(base,exponent=2){
#####
result=1
if (exponent > 0){
for (time in 1:exponent){
result=result*base
}
}
#####
return(result)
}
Vemos cómo funciona:
riseToPower(9)
riseToPower(9,3)
riseToPower(9,0)
Nota aqui unas diferencias:
# quizas esto es mas claro:
riseToPower(base=9,exponent=0)
# con argumentos explicitos no se require orden
riseToPower(exponent=0,base=9)
Siempre hay que estar listo para saber qué hacer ante posibles cálculos; para evitar ello:
divRounded=function(numerator,denominator,precision=2){
if (denominator==0){
return('0 en el denominador')
}else{
result = numerator/denominator
return (round(result, precision))}
}
Probando:
n=13
d=12
p=3
divRounded(n,d,p)
Podemos preparar una lista como input e ingresarla a la función con la ayuda de do.call:
inputArgs=list(precision=3,numerator=13,denominator=12)
do.call(divRounded,inputArgs)
La output no tiene que ser un único valor:
factors=function(number){
vectorOfAnswers=c() # para guardar respuestas
for (i in 1:number){
#si el residuo de 'number'/'i' es igual a cero...
if ((number %% i) == 0){
# ...añade 'i' a la respuesta!
vectorOfAnswers=c(vectorOfAnswers,i)
}
}
return (vectorOfAnswers)
}
Probando:
factors(20)
Creemos una función:
double=function(x){
return (2*x)}
Creemos un vector:
myVector=c(1,2,3)
¿Qué sale de aqu�
double(myVector)
La función aplicada a un vector, aplica la transformación a cada elemento.
Pero esto te da error:
myList=list(1,2,3)
double(myList)
Aquà lo importante es saber aplicar la función según el tipo de input. Usemos Map, con vectores:
Map(double,myVector) # devuelte lista
con Lista:
Map(double,myList) # devuelte lista
Tenemos también mapply. Aquà con vector:
mapply(double,myVector)
Aquà con lista:
mapply(double,myList)
Nota que la estructura de la output es distinta.
Creemos un data frame:
numberA=c(10,20,30,40,50)
numberB=c(6,7,8,9,10)
dataDF=data.frame(numberA,numberB)
dataDF
Antes de transformar el DF, haré una copia:
dataDF2=dataDF
# aqui está la copia
dataDF2
Apliquemos la función double a cada elemento de la copia:
for (column in 1:ncol(dataDF2)){
for (row in 1:nrow(dataDF2[column])){
dataDF2[row,column]=double(dataDF2[row,column])
}
}
# updated:
dataDF2
La copia tiene nuevos valores, pero el original sigue igual:
dataDF
Ahora, apliquemos la función directamente al df:
double(dataDF)
Esta serÃa otra alternativa, pero el resultado no es un df:
lapply(dataDF,double)
Para que el resultado no sea en lista::
as.data.frame(lapply(dataDF,double))
Hay funciones que se pueden aplicar a filas o columnas.
# se aplica por sólo por columnas:
as.data.frame(lapply(dataDF,sum))
Para aplicar por fila o columna tenemos apply:
# por fila
apply(dataDF,1,sum)
# por columna
apply(dataDF,2,sum)
AUSPICIO:
El desarrollo de estos contenidos ha sido posible gracias al grant del Berkeley Initiative for Transparency in the Social Sciences (BITSS) at the Center for Effective Global Action (CEGA) at the University of California, Berkeley
RECONOCIMIENTO
El autor reconoce el apoyo que el eScience Institute de la Universidad de Washington le ha brindado desde el 2015 para desarrollar su investigación en Ciencia de Datos.