8.4: Funciones de escritura
- Page ID
- 151697
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)En esta sección quiero volver a hablar de funciones. Las funciones se introdujeron en la Sección 3.5, pero desde entonces has aprendido mucho sobre R, así que podemos hablar de ellas con más detalle. En particular, quiero mostrarte cómo crear el tuyo propio. Para seguir con el mismo marco básico que utilicé para describir bucles y condicionales, aquí está la sintaxis que usas para crear una función:
FNAME <- function ( ARG1, ARG2, ETC ) {
STATEMENT1
STATEMENT2
ETC
return( VALUE )
}
Lo que esto hace es crear una función con el nombre FNAME, que tiene argumentos ARG1, ARG2 y así sucesivamente. Siempre que se llama a la función, R ejecuta las sentencias en las llaves, y luego emite el contenido de VALUE al usuario. Tenga en cuenta, sin embargo, que R no ejecuta los comandos dentro de la función en el espacio de trabajo. En cambio, lo que hace es crear un entorno local temporal: todas las declaraciones internas en el cuerpo de la función se ejecutan ahí, por lo que permanecen invisibles para el usuario. Solo se devuelven al espacio de trabajo los resultados finales en el VALOR.
Para dar un ejemplo sencillo de esto, vamos a crear una función llamada quadruple ()
que multiplica sus entradas por cuatro. De acuerdo con el enfoque adoptado en el resto del capítulo, utilizaré un guión para hacer esto:
## --- functionexample.R
quadruple <- function(x) {
y <- x*4
return(y)
}
Cuando ejecutamos este script, de la siguiente manera
source( "./rbook-master/scripts/functionexample.R" )
no parece haber pasado nada, pero hay un nuevo objeto creado en el espacio de trabajo llamado cuádruple
. No en vano, si le pedimos a R que nos diga qué tipo de objeto es, nos dice que es una función:
class( quadruple )
## [1] "function"
Y ahora que hemos creado la función quadruple ()
, podemos llamarla igual que cualquier otra función Y si quiero almacenar la salida como una variable, puedo hacer esto:
my.var <- quadruple(10)
print(my.var)
## [1] 40
Una cosa importante a reconocer aquí es que las dos variables internas que utiliza la función quadruple ()
, x
e y
, permanecen internas. Es decir, si inspeccionamos el contenido del espacio de trabajo,
library(lsr)
## Warning: package 'lsr' was built under R version 3.5.2
who()
## -- Name -- -- Class -- -- Size --
## balance numeric 1
## day character 1
## i integer 1
## interest numeric 1
## itng.table table 3 x 4
## month numeric 1
## monthly.multiplier numeric 1
## msg character 1
## my.var numeric 1
## payments numeric 1
## quadruple function
## speaker character 10
## today Date 1
## total.paid numeric 1
## utterance character 10
## w character 1
## W character 1
## w.length integer 1
## words character 7
## x numeric 1
vemos todo en nuestro espacio de trabajo desde este capítulo incluyendo la propia función quadruple ()
, así como la variable my.var
que acabamos de crear.
Ahora que sabemos cómo crear nuestras propias funciones en R, probablemente sea una buena idea hablar un poco más sobre algunas de las otras propiedades de funciones que he estado pasando por alto. Para empezar, aprovechemos esta oportunidad para escribir el nombre de la función en la línea de comandos sin los paréntesis:
quadruple
## function (x)
## {
## y <- x * 4
## return(y)
## }
Como puede ver, cuando escribe el nombre de una función en la línea de comandos, R imprime el código fuente subyacente que usamos para definir la función en primer lugar. En el caso de la función quadruple ()
, esto es bastante útil para nosotros: podemos leer este código y ver realmente qué hace la función. Para otras funciones, esto es menos útil, como vimos en la Sección 3.5 cuando intentamos escribir citación
en lugar de citación ()
.
Argumentos de función revisados
Bien, ahora que estamos empezando a tener una idea de cómo se construyen las funciones, echemos un vistazo a dos funciones un poco más complicadas que he creado. El código fuente para estas funciones está contenido dentro de los scripts FunctionExample2.r
y FunctionExample3.r
. Empecemos por mirar el primero:
## --- functionexample2.R
pow <- function( x, y = 1) {
out <- x^y # raise x to the power y
return( out )
}
y si escribimos source (“functionExample2.r”)
para cargar la función pow ()
en nuestro espacio de trabajo, entonces podemos hacer uso de ella. Como puede ver al mirar el código para esta función, tiene dos argumentos x
e y, y
todo lo que hace es elevar x
a la potencia de y
. Por ejemplo, este comando
pow(x=3, y=2)
## [1] 9
calcula el valor de 3 2. Lo interesante de esta función no es lo que hace, ya que R ya cuenta con mecanismos perfectamente buenos para calcular potencias. Más bien, observe que cuando definí la función, especificé y=1
al enumerar los argumentos? Ese es el valor predeterminado para y
. Entonces, si ingresamos un comando sin especificar un valor para y
, entonces la función asume que queremos y=1
:
pow( x=3 )
## [1] 3
Sin embargo, como no especificé ningún valor predeterminado para x
cuando definí la función pow ()
, siempre necesitamos ingresar un valor para x
. Si no lo hacemos R va a escupir un mensaje de error.
Entonces ahora ya sabes cómo especificar valores predeterminados para un argumento. La otra cosa que debo señalar mientras estoy en este tema es el uso de la...
argumento. El...
argumento es un constructo especial en R que solo se usa dentro de funciones. Se utiliza como una forma de hacer coincidir contra múltiples entradas de usuario: en otras palabras,...
se utiliza como mecanismo para permitir al usuario ingresar tantas entradas como quiera. No voy a hablar en absoluto de los detalles de bajo nivel de cómo funciona esto, pero te voy a mostrar un ejemplo sencillo de una función que hace uso de ella. Para ello, considere el siguiente guión:
## --- functionexample3.R
doubleMax <- function( ... ) {
max.val <- max( ... ) # find the largest value in ...
out <- 2 * max.val # double it
return( out )
}
Cuando escribimos source (“FunctionExample3.r”)
, R crea la función doubleMax ()
. Puedes escribir tantas entradas como quieras. La función doubleMax ()
identifica el mayor valor en las entradas, pasando todas las entradas del usuario a la función max ()
, y luego la duplica. Por ejemplo:
doubleMax( 1,2,5 )
## [1] 10
Hay más funciones que esto
Hay muchos otros detalles de las funciones que he ocultado en mi descripción en este capítulo. Los programadores experimentados se preguntarán exactamente cómo funcionan las “reglas de alcance” en R, 137 o quieren saber cómo usar una función para crear variables en otros entornos 138, o si los objetos de función pueden asignarse como elementos de una lista 139 y probablemente cientos de otras cosas además. Sin embargo, no quiero que esta discusión se vuelva demasiado abarrotada de detalles, así que creo que es mejor —al menos para los fines del libro actual— detenerse aquí.