8.1: Guiones
- Page ID
- 151685
\( \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}\)Los programas de computadora vienen en bastantes formas diferentes: el tipo de programa que más nos interesa desde la perspectiva del análisis de datos cotidiano usando R se conoce como script. La idea detrás de un script es que, en lugar de escribir tus comandos en la consola R uno a la vez, en lugar de escribirlos todos en un archivo de texto. Luego, una vez que hayas terminado de escribirlos y guardar el archivo de texto, puedes obtener R para ejecutar todos los comandos de tu archivo usando la función source ()
. En un momento te mostraré exactamente cómo se hace esto, pero primero mejor explicaré por qué debería importarte.
guiones?
Antes de discutir los conceptos de scripting y programación con más detalle, vale la pena detenerse a preguntar por qué debería molestarse. Después de todo, si miras los comandos R que he usado en todas partes de este libro, notarás que todos están formateados como si los estuviera escribiendo en la línea de comandos. Fuera de este capítulo en realidad no verás ningún guion. No se deje engañar por esto. La razón por la que lo he hecho de esa manera es puramente por razones pedagógicas. Mi objetivo en este libro es enseñar estadística y enseñar a R. Para ello, lo que he tenido que hacer es cortar todo en pequeñas rebanadas: cada sección tiende a centrarse en un tipo de concepto estadístico, y sólo un número pequeño de funciones R. En la medida de lo posible, quiero que veas lo que hace cada función de forma aislada, un comando a la vez. Al obligarme a escribir todo como si estuviera siendo escrito en la línea de comandos, me impone una especie de disciplina: me impide armar muchos comandos en un gran guión. Desde una perspectiva de enseñanza (y aprendizaje) creo que eso es lo correcto... pero desde una perspectiva de análisis de datos, no lo es. Cuando comienzas a analizar conjuntos de datos del mundo real, rápidamente te encontrarás necesitando escribir scripts.
Para entender por qué los scripts son tan útiles, puede ser útil considerar los inconvenientes de escribir comandos directamente en el símbolo del sistema. El enfoque que hemos estado adoptando hasta ahora, en el que escribes comandos uno a la vez, y R se sienta pacientemente entre comandos, se conoce como el estilo interactivo. Hacer su análisis de datos de esta manera es más bien como tener una conversación... una conversación muy molesta entre usted y su conjunto de datos, en la que usted y los datos no se están hablando directamente entre sí, y así hay que confiar en R para pasar mensajes de un lado a otro. Este enfoque tiene mucho sentido cuando solo estás probando algunas ideas: tal vez estás tratando de averiguar qué análisis son sensatos para tus datos, o tal vez simplemente estás tratando de recordar cómo funcionan las diversas funciones R, así que solo estás escribiendo algunos comandos hasta obtener el que deseas. En otras palabras, el estilo interactivo es muy útil como herramienta para explorar tus datos. Sin embargo, tiene una serie de inconvenientes:
- Es difícil salvar tu trabajo de manera efectiva. Puedes guardar el espacio de trabajo, para que posteriormente puedas cargar cualquier variable que hayas creado. Puedes guardar tus parcelas como imágenes. E incluso puedes guardar el historial o copiar el contenido de la consola R en un archivo. Tomadas en conjunto, todas estas cosas te permiten crear un registro razonablemente decente de lo que hiciste. Pero sí deja mucho que desear. Parece que deberías poder guardar un solo archivo que R podría usar (junto con tus archivos de datos sin procesar) y reproducir todo (o al menos, todo lo interesante) que hiciste durante tu análisis de datos.
- Es molesto tener que volver al principio cuando cometes un error. Supongamos que acaba de pasar las últimas dos horas escribiendo comandos. A lo largo de este tiempo, ha creado muchas variables nuevas y ha realizado muchos análisis. Entonces de repente te das cuenta de que había un error tipográfico desagradable en el primer comando que escribías, así que todos tus números posteriores están equivocados. Ahora hay que arreglar ese primer comando, y luego pasar otra hora más o menos revisando el historial de R para tratar de recrear lo que hiciste.
- No puedes dejar notas para ti mismo. Claro, puedes garabatear algunas notas en una hoja de papel, o incluso guardar un documento de Word que resume lo que hiciste. Pero lo que realmente quieres poder hacer es escribir una traducción al inglés de tus comandos R, preferentemente justo “al lado” de los propios comandos. De esa manera, puedes mirar hacia atrás a lo que has hecho y realmente recordar lo que estabas haciendo. En los sencillos ejercicios que hemos realizado hasta ahora, no ha sido tan difícil recordar lo que estabas haciendo o por qué lo estabas haciendo, sino solo porque todo lo que hemos hecho se pudo hacer usando solo unos pocos comandos, ¡y nunca te han pedido que reproduzcas tu análisis seis meses después de que lo hiciste originalmente! Cuando tu análisis de datos comienza involucrando cientos de variables, y requiere comandos bastante complicados para funcionar, entonces realmente, realmente necesitas dejarte algunas notas para explicarte tu análisis a, bueno, a ti mismo.
- Es casi imposible reutilizar tus análisis más tarde o adaptarlos a problemas similares. Supongamos que, en algún momento de enero, se le entrega un problema difícil de análisis de datos. Después de trabajar en él durante años, descubres algunos trucos realmente inteligentes que se pueden usar para resolverlo. Entonces, en septiembre, te entregan un problema realmente similar. Como que puedes recordar lo que hiciste, pero no muy bien. Te gustaría tener un registro limpio de lo que hiciste la última vez, cómo lo hiciste y por qué lo hiciste de la manera que lo hiciste. Algo así realmente te ayudaría a resolver este nuevo problema.
- Es difícil hacer cualquier cosa excepto lo básico. Hay un desagradable efecto secundario de estos problemas. Los errores tipográficos son inevitables. Hasta el mejor analista de datos del mundo comete muchos errores. Entonces, la posibilidad de que puedas encadenar docenas de comandos R correctos seguidos son muy pequeñas. Entonces, a menos que tengas alguna forma de evitar este problema, nunca podrás hacer nada más que simples análisis.
- Es difícil compartir tu trabajo con otras personas. Debido a que no tienes este registro limpio y agradable de lo que los comandos R estuvieron involucrados en tu análisis, no es fácil compartir tu trabajo con otras personas. Claro, puedes enviarles todos los archivos de datos que has guardado, y tu historial y registros de consola, e incluso las pequeñas notas que te escribiste a ti mismo, pero las probabilidades son bastante buenas de que nadie más entienda realmente lo que está pasando (confía en mí en esto: me han entregado muchos bits aleatorios de salida de personas que han estado analizar sus datos, y tiene muy poco sentido a menos que tengas a la persona original que hizo el trabajo sentada justo a tu lado explicando lo que estás viendo)
Idealmente, lo que te gustaría poder hacer es algo así... Supongamos que comienzas con un conjunto de datos myrawdata.csv
. Lo que quieres es un solo documento —llamémoslo MyDataAnalysis.r
— que almacene todos los comandos que has usado para hacer tu análisis de datos. Algo similar a la historia de R pero mucho más enfocada. Solo incluiría los comandos que quieras conservar para más adelante. Luego, más adelante, en lugar de volver a escribir todos esos comandos, solo le dirías a R que ejecute todos los comandos que están almacenados en MyDataAnalysis.r
. Además, para ayudarte a darle sentido a todos esos comandos, lo que te gustaría es la posibilidad de agregar algunas notas o comentarios dentro del archivo, para que cualquiera que lea el documento por sí mismo pueda entender lo que hace realmente cada uno de los comandos. Pero estos comentarios no se interpondrían en el camino: cuando intentas que R ejecute MyDataAnalysis.R
sería lo suficientemente inteligente reconocería que estos comentarios son para beneficio de los humanos, y así los ignoraría. Más adelante podrías ajustar algunos de los comandos dentro del archivo (tal vez en un nuevo archivo llamado MyNewDataAlaysis.r
) para que puedas adaptar un análisis antiguo para poder manejar un nuevo problema. Y podrías enviar por correo electrónico a tus amigos y compañeros una copia de este archivo para que ellos mismos puedan reproducir tu análisis.
En otras palabras, lo que quieres es un guión.
primer guión
Bien entonces. Dado que los guiones son tan terriblemente increíbles, escribamos uno. Para ello, abre un programa sencillo de edición de texto, como TextEdit (en una Mac) o Notebook (en Windows). No uses un programa de procesamiento de textos elegante como Microsoft Word o OpenOffice: usa el programa más simple que puedas encontrar. Abra un nuevo documento de texto y escriba algunos comandos R, presionando enter después de cada comando. Intentemos usar x <- “hello world”
e print (x)
como nuestros comandos. Después guarda el documento como Hola.r
, y recuerda guardarlo como un archivo de texto sin formato: no lo guarde como un documento de Word o un archivo de texto enriquecido. Sólo un viejo y aburrido archivo de texto sin formato. Además, cuando te pregunte dónde guardar el archivo, guárdalo en cualquier carpeta que estés usando como tu directorio de trabajo en R. En este punto, deberías estar mirando algo como la Figura 8.1. Y si es así, ahora has escrito con éxito tu primer programa R. Debido a que no quiero tomar capturas de pantalla para cada guión, voy a presentar scripts usando extractos formateados de la siguiente manera:
## --- hello.R
x <- "hello world"
print(x)
La línea en la parte superior es el nombre del archivo, y no parte del script en sí. Debajo de eso, se pueden ver los dos comandos R que conforman el propio script. Al lado de cada comando he incluido los números de línea. En realidad no los escribes en tu guión, pero muchos editores de texto (incluido el integrado en Rstudio que te mostraré en un momento) mostrarán números de línea, ya que es una convención muy útil que te permite decir cosas como “la línea 1 del script crea una nueva variable, y la línea 2 la imprime”.
Entonces, ¿cómo ejecutamos el script? Suponiendo que el archivo Hello.r
se ha guardado en su directorio de trabajo, entonces puede ejecutar el script usando el siguiente comando:
source( "hello.R" )
Si el archivo script se guarda en un directorio diferente, entonces necesita especificar la ruta al archivo, exactamente de la misma manera que tendría que hacerlo al cargar un archivo de datos usando load ()
. En cualquier caso, al escribir este comando, R abre el archivo script: luego lee cada comando en el archivo en el mismo orden en que aparecen en el archivo, y ejecuta esos comandos en ese orden. El simple script que he mostrado arriba contiene dos comandos. El primero crea una variable x
y el segundo lo imprime en pantalla. Entonces, cuando ejecutamos el script, esto es lo que vemos en pantalla:
source("./rbook-master/scripts/hello.R")
## [1] "hello world"
Si inspeccionamos el espacio de trabajo usando un comando como who ()
u objects ()
, descubrimos que R ha creado la nueva variable x
dentro del espacio de trabajo, y no es sorprendente que x
sea una cadena de caracteres que contiene el texto “hello world”
. Y así, ya has escrito tu primer programa R. Realmente es así de simple.
Uso de Rstudio para escribir scripts
En el ejemplo anterior asumí que estabas escribiendo tus guiones usando un sencillo editor de texto. Sin embargo, suele ser más conveniente usar un editor de texto que esté diseñado específicamente para ayudarte a escribir guiones. Hay muchos de estos por ahí, y los programadores experimentados tendrán sus propios favoritos personales. Para nuestros propósitos, sin embargo, solo podemos usar el integrado en Rstudio. Para crear un nuevo archivo de script en R studio, vaya al menú “Archivo”, seleccione la opción “Nuevo” y luego haga clic en “R script”. Esto abrirá una nueva ventana dentro del panel “fuente”. Entonces puedes escribir los comandos que quieras (o código como generalmente se llama cuando estás escribiendo los comandos en un archivo de script) y guardarlo cuando hayas terminado. Lo bueno de usar Rstudio para hacer esto es que cambia automáticamente el color del texto para indicar qué partes del código son comentarios y cuáles son partes son comandos R reales (estos colores se llaman resaltado de sintaxis, pero en realidad no forman parte de el archivo — es solo Rstudio tratando de ser útil. Para ver un ejemplo de esto, abramos nuestro script Hello.r
en Rstudio. Para ello, vuelve al menú “Archivo”, y selecciona “Abrir...”. Una vez que hayas abierto el archivo, deberías estar mirando algo como la Figura 8.2. Como puedes ver (si estás viendo este libro en color) la cadena de caracteres “hello world” está resaltada en verde.
Usar Rstudio para tu editor de texto también es conveniente por otras razones. Observe que en la esquina superior derecha de la Figura 8.2 hay un pequeño botón que dice “Fuente”? Si haces clic en eso, Rstudio construirá el comando source ()
relevante para ti, y lo enviará directamente a la consola R. Así que ni siquiera tienes que escribir el comando source ()
, que en realidad creo que es una gran cosa, porque realmente me molesta tener que escribir todas esas pulsaciones de teclas adicionales cada vez que quiero ejecutar mi script. De todos modos, Rstudio proporciona varias otras pequeñas herramientas convenientes para ayudar a facilitar el scripting, pero no voy a discutirlas aquí. 134
Comentando tu guión
Al escribir tu análisis de datos como script, una cosa que generalmente es una buena idea es incluir muchos comentarios en el código. De esa manera, si alguien más intenta leerlo (o si vuelves a él varios días, semanas, meses o años después) puede averiguar qué está pasando. Como principiante, creo que es especialmente útil comentar a fondo, en parte porque te mete en el hábito de comentar el código, y en parte porque el simple acto de escribir una explicación de lo que hace el código te ayudará a tener claro en tu propia mente lo que estás tratando de lograr. Para ilustrar esta idea, considere el siguiente guión:
## --- itngscript.R
# A script to analyse nightgarden.Rdata_
# author: Dan Navarro_
# date: 22/11/2011_
# Load the data, and tell the user that this is what we're
# doing.
cat( "loading data from nightgarden.Rdata...\n" )
load( "./rbook-master/data/nightgarden.Rdata" )
# Create a cross tabulation and print it out:
cat( "tabulating data...\n" )
itng.table <- table( speaker, utterance )
print( itng.table )
Notarás que me he exagerado un poco con mis comentarios: en la parte superior del guión he explicado el propósito del guión, quién lo escribió, y cuándo fue escrito. Entonces, a lo largo del propio archivo script he agregado muchos comentarios explicando lo que hace realmente cada sección del código. En la vida real la gente no tiende a comentar esto a fondo, pero la idea básica es muy buena: realmente quieres que tu guión se explique. Sin embargo, como cabría esperar, R ignora por completo todas las partes comentadas. Cuando ejecutamos este script, esto es lo que vemos en pantalla:
## --- itngscript.R
# A script to analyse nightgarden.Rdata
# author: Dan Navarro
# date: 22/11/2011
# Load the data, and tell the user that this is what we're
# doing.
cat( "loading data from nightgarden.Rdata...\n" )
## loading data from nightgarden.Rdata...
load( "./rbook-master/data/nightgarden.Rdata" )
# Create a cross tabulation and print it out:
cat( "tabulating data...\n" )
## tabulating data...
itng.table <- table( speaker, utterance )
print( itng.table )
## utterance
## speaker ee onk oo pip
## makka-pakka 0 2 0 2
## tombliboo 1 0 1 0
## upsy-daisy 0 2 0 2
Incluso aquí, fíjate que el guión anuncia su comportamiento. Las dos primeras líneas de la salida nos dicen mucho sobre lo que realmente está haciendo el guión detrás de escena (el código hace a esto corresponde a los dos comandos cat ()
en las líneas 8 y 12 del guión). Por lo general, es una idea bastante buena hacer esto, ya que ayuda a asegurar que la salida tenga sentido cuando se ejecuta el script.
Diferencias entre scripts y la línea de comandos
En su mayor parte, los comandos que insertas en un script se comportan exactamente de la misma manera que lo harían si escribieras lo mismo en la línea de comandos. La única excepción importante a esto es que si quieres que una variable se imprima en pantalla, necesitas decirle explícitamente a R que la imprima. No se puede simplemente escribir el nombre de la variable. Por ejemplo, nuestro script original de Hello.r
produjo salida visible. El siguiente script no:
## --- silenthello.R
x <- "hello world"
x
Todavía crea la variable x cuando orientas
()
el script, pero no imprimirá nada en la pantalla.
Sin embargo, aparte de que los scripts no utilizan la “impresión automática” como se le llama, no hay muchas diferencias en la mecánica subyacente. Sin embargo, hay algunas diferencias estilísticas. Por ejemplo, si quieres cargar un paquete en la línea de comandos, generalmente usarías la función library ()
. Si quieres hacerlo desde un script, es convencional usar require ()
en su lugar. Los dos comandos son básicamente idénticos, la única diferencia es que si el paquete no existe, require ()
produce una advertencia mientras que library ()
te da un error. Estilísticamente, lo que esto significa es que si el comando require ()
falla en tu script, R continuará audazmente e intentará ejecutar el resto del script. A menudo eso es lo que te gustaría que sucediera, así que es mejor usar require ()
. Claramente, sin embargo, puede obtener simplemente usando el comando library ()
para el uso diario.
¡Hecho!
En este punto, has aprendido los conceptos básicos del scripting. Ahora se te permite oficialmente decir que puedes programar en R, aunque probablemente no deberías decirlo demasiado alto. Hay mucho más que aprender, pero sin embargo, si puedes escribir guiones como estos entonces lo que estás haciendo es de hecho programación básica. El resto de este capítulo está dedicado a introducir algunos de los comandos de teclado que necesitas para que tus programas sean más potentes; y para ayudarte a acostumbrarte a pensar en términos de guiones, para el resto de este capítulo voy a escribir la mayoría de mis extractos como guiones.