15 RECUPERACIÓN DE SALIDAS
Las funcionalidades incorporadas en Quarto permiten formatear elegante y eficientemente las salidas generadas por R para incorporarlas en un informe. Esta es nuestra herramienta recomendada. Invitamos a consultar al respecto en el libro Quarto. No obstante, algunos usuarios que no estuvieran preparados o motivados para hacer uso de tales herramientas podrían requerir una herramienta que les permita satisfacer un interés más prosaico: llevar las salidas, tal y como se generan por defecto, a un archivo editable, es decir a un archivo de Word o de Excel, sin que se desbaraten en dicho proceso. Esto puede resultar útil para estudiar dichas salidas, para imprimirlas o para tomar y editar lo que de allí se estime conveniente y llevarlo a un informe.
15.1 Salidas de texto
En muchas ocasiones, el objetivo de llevar las salidas a un archivo de texto puede satisfacerse mediante el simple copiado y pegado. No obstante, cuando estas son muy voluminosas, se requieren otras estrategias.
Considérense las siguientes instrucciones en las que se usa la base de datos iris
, la cual forma parte del paquete datasets
que viene preinstalado en R:
data(iris) # Carga la base de datos en memoria
Puede solicitarse un resumen de la base datos:
summary(iris)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width
#> Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
#> 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
#> Median :5.800 Median :3.000 Median :4.350 Median :1.300
#> Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
#> 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
#> Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
#> Species
#> setosa :50
#> versicolor:50
#> virginica :50
#>
#>
#>
Para visualizar las primeras observaciones de este conjunto de datos, así como las últimas, se usan las funciones head
y tail
, respectivamente, así:
head(iris)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3.0 1.4 0.2 setosa
#> 3 4.7 3.2 1.3 0.2 setosa
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5.0 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosa
tail(iris)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 145 6.7 3.3 5.7 2.5 virginica
#> 146 6.7 3.0 5.2 2.3 virginica
#> 147 6.3 2.5 5.0 1.9 virginica
#> 148 6.5 3.0 5.2 2.0 virginica
#> 149 6.2 3.4 5.4 2.3 virginica
#> 150 5.9 3.0 5.1 1.8 virginica
Considérese ahora la obtención de un análisis de varianza para la variable Petal.Width
, en función del factor Species
.
anova <- aov(Petal.Width ~ Species, data = iris)
summary(anova)
#> Df Sum Sq Mean Sq F value Pr(>F)
#> Species 2 80.41 40.21 960 <2e-16 ***
#> Residuals 147 6.16 0.04
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Finalmente, supóngase que se desea llevar toda la información obtenida a un archivo de Word, sin que se desconfigure. Para el efecto, pueden usarse las funciones sink
y capture.output
.
La función sink
es las más expedita, siendo la recomendada cuando se tienen muchas salidas y/o se quiere enviar absolutamente todo al archivo, incluyendo instrucciones y resultados. Dicha función, en su forma básica, tiene un único argumento obligatorio, que es el nombre del archivo, el cual debe escribirse entrecomillado, incluyendo su correspondiente extensión (admite “txt”, “rtf” y “doc”). Es importante aclarar, sin embargo, que, aunque el archivo de salida tenga extensión “rtf” o “doc”, se trata en realidad de un archivo de texto sin formato; por tal razón, si se desea tomar dicho archivo como punto de partida para construir un informe en el que se manejen las diferentes herramientas de formato que proporciona Word y se incluyan gráficos, deberá usarse la opción “guardar como” de Word para guardarlo como un verdadero archivo de Word. Asimismo, podrán incorporarse trozos de dicho documento en cualquier documento Word, mediante el recurso del copiado y pegado, respetando el formato.
Una vez se ejecuta la función sink
con un nombre de archivo como argumento, todo lo que se genera en adelante, tanto instrucciones como resultados, se envía a dicho archivo. Al final del script, debe usarse la función sink
sin ningún argumento para cerrar la conexión con el archivo, permitiendo su manipulación.
El script para el presente ejemplo tendría la siguiente forma.
sink("Salidas.doc")
options(max.print = 10000)
data(iris)
summary(iris)
head(iris)
tail(iris)
anova <- aov(Petal.Width ~ Species, data = iris)
summary(anova)
sink()
El anterior script genera un archivo llamado “Salidas.doc”, que contiene tanto las instrucciones como los correspondientes resultados de todo lo incluido entre sink("Salidas.doc")
y sink()
. Por defecto, se incluye un máximo de 1000 líneas por salida; cualquier información adicional queda truncada. Cuando se tienen salidas muy extensas (que no es el presente caso), debe incluirse una instrucción que permita superar el límite de las 1000 líneas (p. e., options(max.print = 10000)
), asegurando que el archivo de salidas contenga la información completa.
Para ejercer un mayor control sobre lo que se escribe en el archivo, seleccionando exactamente lo que se quiera registrar, sin incluir las correspondientes instrucciones e incorporando saltos de línea entre los diferentes resultados27, puede usarse la función capture.output
, así:
capture.output(summary(iris), cat("\n", "\n"), head(iris),
cat("\n", "\n"), tail(iris), cat("\n", "\n"),
summary(anova), file = "Salidas.doc")
La instrucción anterior genera un archivo de texto llamado “Salidas.doc”, que contiene las cuatro salidas solicitadas. En la sección 15.1.1 se detalla lo relativo a la función cat
.
Con cualquiera de las dos funciones ilustradas (sink
y capture.output
), es posible añadirle información al archivo creado, incluyendo el argumento append = T
. Supóngase que se desea adicionar el resultado de una prueba de Shapiro-Wilk realizada sobre los residuales del modelo. Para ello se ejecutan las siguientes instrucciones, asegurándose de que el archivo “Salidas.doc” esté cerrado.
Este sería el conjunto de instrucciones, usando la función sink
:
sink("Salidas.doc", append = T)
shapiro.test(resid(anova))
sink()
O, usando la función capture.output
:
capture.output(cat("\n", "\n"), shapiro.test(resid(anova)),
file = "Salidas.doc", append = T)
En ocasiones, la apariencia del archivo resultante puede hacer pensar que no se satisfizo el objetivo de capturar el texto, sin que se desconfigurara el formato. Esto es debido a que el contenido capturado es más amplio que el ancho de hoja, lo que hace que la(s) última(s) columna(s) pase(n) a la siguiente línea. Esto se soluciona fácilmente, bien sea disminuyendo el tamaño de la fuente, disminuyendo las márgenes o mediante una combinación de ambas estrategias.
Es importante resaltar que el hecho de que las funciones anteriores (sink
y capture.output
) estén dirigidas exclusivamente a la captura de texto no representa un problema, dado que la exportación de contenido gráfico puede realizarse acorde con lo expuesto en la sección 19.1 o incluso mediante la funcionalidad del botón EXPORT en el panel “plots”.
15.1.1 Funciones para impresión de texto
Entre las funciones que permiten imprimir cadenas de caracteres o texto, se destacan print
, cat
, paste
, c
, strwrap
y WriteLines
. A continuación, se presentan sus principales características.
La función print
despliega en consola la información de su argumento, cualquiera sea su clase. Esta es la función que el sistema usa internamente cuando se invoca un objeto por su nombre y se muestra su contenido en consola.
Esta función no altera el contenido de su argumento para mostrarlo, sino que envía a consola una copia exacta del mismo. Esto puede verificarse, evaluando la clase de cualquier salida generada con print
o, mejor aun, evaluando si la copia que se envía a consola es idéntica a la de su argumento.
class(print(df))
#> id v1 v2
#> 1 a23 2.4 4+3.0i
#> 2 f31 7.9 2-0.8i
#> 3 j33 1.1 1+1.1i
#> 4 m54 8.5 3-5.0i
#> [1] "data.frame"
identical(print(df), df)
#> id v1 v2
#> 1 a23 2.4 4+3.0i
#> 2 f31 7.9 2-0.8i
#> 3 j33 1.1 1+1.1i
#> 4 m54 8.5 3-5.0i
#> [1] TRUE
Para muchos objetos, esta es la única función de impresión posible. No obstante, puede resultar poco práctica para enviar texto a la consola como parte de las salidas generadas por una función y, de hecho, es poco usada para tal fin.
La función cat
(nemotécnicamente: concatenación) realiza un trabajo similar al de la función print
, esto es, imprimir el resultado en pantalla, pero brinda mayores posibilidades de personalización del formato, por lo que suele preferirse en los scripts para presentación de avisos. Esta función únicamente es aplicable a objetos atómicos. Si tales objetos tienen un atributo de dimensionalidad, como es el caso de matrices y arreglos, este se elimina, y se despliega el contenido del vector resultante.
print(m1)
#> a b c
#> [1,] 2 5 9
#> [2,] 0 -1 1
cat(m1)
#> 2 0 5 -1 9 1
Nótese que, además de eliminar el atributo de dimensionalidad, cat
elimina cualquier nombre que pudiera estar asociado con las dimensiones o con los elementos del contenedor. Asimismo, cat
deja de generar los, a veces molestos, indicadores de posición que aparecen cuando se usa print
. La función cat
tampoco encierra entre comillas los objetos tipo carácter, como sí lo hace print
(aunque podría evitarse que print
entrecomille, usando el argumento quote = F
).
cat(id)
#> a23 f31 j33 m54
El principal uso de cat
es la concatenación de diferentes cadenas de caracteres, combinando a menudo información contenida en los argumentos de una función con texto personalizado.
conf.level <- 0.95
confianza <- 100 * conf.level
method <- "Tukey"
cat("Intervalo de confianza del", confianza, "%", "\n",
"usando el método", method)
#> Intervalo de confianza del 95 %
#> usando el método Tukey
Se habrá notado que los saltos de línea están representados por la etiqueta "\n"
. Pueden usarse tantos como se requieran. Si se desea imprimir un texto al final de la línea, antes del salto, puede introducirse antes de la barra invertida. Así, para introducir, por ejemplo, una coma al final de la línea, se usaría ",\n"
.
Nótese que la función cat
separa por defecto todos sus argumentos con un espacio. Para evitar este comportamiento, forzando, por ejemplo, que el símbolo de porcentaje quede pegado de su valor, se usa el argumento sep = ""
. En este caso, al declarar los argumentos, se hace necesario introducir los espacios, donde sean requeridos (después de del y después de método, en el ejemplo). Igualmente, podría usarse el argumento sep
para introducir cualquier otro separador.
cat("Intervalo de confianza del ", confianza, "%", ",\n",
"usando el método ", method, sep = "")
#> Intervalo de confianza del 95%,
#> usando el método Tukey
La función paste
, en algunos casos realiza un trabajo similar al de cat
. Sin embargo, a diferencia de cat
, paste
sí admite objetos recursivos como argumentos, aunque su alcance no es tan amplio como el de print
, que admite cualquier tipo de objeto (funciones, por ejemplo). La función paste
está diseñada para trabajar con texto y lo que hace es concatenar todos sus argumentos como una cadena de caracteres. A diferencia de cat
, paste
permite asignar su resultado a un objeto que será, en todos los casos, una cadena de texto, es decir, un vector tipo character
. La función paste
, al igual que cat
, separa por defecto sus argumentos con un espacio, lo cual puede modificarse mediante el argumento sep
. Asimismo, puede usarse la función paste0
, que no deja espacio por defecto entre sus argumentos.
El hecho de que los resultados de paste
puedan asignarse a un objeto hace que esta función resulte muy versátil para guardar cadenas de texto que luego se traspasen como argumentos de alguna otra función. Así, por ejemplo, para usar el texto generado en el ejemplo anterior como título de un gráfico, bastaría con asignarlo a un objeto que luego se utilice como argumento del gráfico en cuestión (cf. capítulo 19).
main <- paste("Intervalo de confianza del", confianza, "%",
"usando el método", method)
Si la cadena de caracteres resultante fuera a mostrarse en consola, esta se adaptaría automáticamente al ancho de la ventana, ocupando las líneas que fueran necesarias. Esto podría dar lugar a textos poco estéticos, por cuanto la partición de la cadena de caracteres no tendría en cuenta la separación natural entre palabras.
Por otra parte, si se quisiera usar esta cadena de caracteres como título de un gráfico, su longitud podría llegar a ser problemática, puesto que esta se mostraría en una sola línea. Para imprimir en un gráfico un título de gran longitud, distribuyéndolo en varias líneas, es más conveniente usar la función c
, para concatenar lo que se desea imprimir en cada línea.
Considérese el título del gráfico que se genera mediante la función que se presenta en el capítulo 23.
nombre.g <- 'Species'
main <- c('Medias y desviaciones estándar por nivel de',
nombre.g,
'usando la varianza individual dentro de cada grupo')
En este caso, cada uno de los tres elementos del vector main
se muestra centrado en una línea, tal y como se aprecia en el gráfico de el capítulo 23.
Para manejar cadenas de texto muy largas, que incluso puedan estar conformadas por varios párrafos, deben combinarse las funciones strwrap
y WriteLines
. La función strwrap
sí tiene en cuenta los límites naturales entre palabras, pudiendo establecerse el ancho máximo de cada línea, mediante el argumento width
. La impresión de las diferentes líneas resultantes se realiza mediante la función WriteLines
.
A continuación, se presenta de manera resumida y comentada el ejemplo que aparece en las ayudas de la función strwrap
.
Inicialmente se lee el archivo 'THANKS'
, que está ubicado en la carpeta “doc”, dentro de la ruta de instalación de R.
El objeto x
es un vector de la clase character
, de longitud 1, es decir que está conformado por una única cadena de caracteres (otra cosa es el número de caracteres contenidos en dicha cadena, lo cual puede verificarse con la función nchar
).
A continuación, se fracciona la información en párrafos (este trabajo lo hace strsplit
) y se eliminan los 10 primeros, dando por resultado un vector de la clase character
con 4 elementos (cuatro párrafos).
Seguidamente, usando paste
, se unen estos 4 párrafos en una única cadena de caracteres, manteniendo el marcador \n\n
para representar los saltos de párrafo.
x <- paste(x, collapse = "\n\n")
Hasta este punto todo lo que se ha hecho es leer y acondicionar una cadena de caracteres muy larga (864 caracteres), manteniendo un marcador para representar los saltos de párrafo (). Esta cadena de caracteres puede imprimirse, adecuadamente formateada, combinando las funciones strwrap
y WriteLines
.
Para imprimir los once párrafos en cuestión, sin que se parta ninguna palabra y sin que ninguna línea de impresión exceda los 50 caracteres, se usa la siguiente instrucción.
writeLines(strwrap(x, width = 50))
#> The Windows port was originally developed by
#> Guido Masarotto (for a while a member of R Core)
#> and Brian Ripley, then further by Duncan Murdoch
#> (a former member of R Core) and then Jeroen Ooms
#> (base) and Uwe Ligges (packages). Tomas Kalibera
#> is the current main developer of the Windows port
#> and provides assistance with package porting.
#>
#> Tomas Kalibera's work has been sponsored by Jan
#> Vitek and funded by his European Research Council
#> grant "Evolving Language Ecosystems (ELE)".
#>
#> Computing support (including hardware, hosting
#> and infrastructure) has been provided/funded by
#> the R Foundation, employers of R-Core members
#> (notably WU Wien, ETH Zurich, U Oxford and U
#> Iowa) and by Northeastern University and the
#> University of Kent.
#>
#> Distributions of R contain the recommended
#> packages, whose authors/contributors are listed
#> in their DESCRIPTION files.
En resumen, debe usarse la función print
para imprimir el resultado de un objeto no atómico, respetando su estructura; en particular, si se trata de listas o data frames. La función cat
es la más adecuada para formatear texto que se envíe a la consola, siempre que no se requiera guardar dicho contenido. La función paste
(o paste0
) es la más adecuada para formatear cadenas de caracteres, cuyo contenido deba guardarse para uso posterior. La función c
permite controlar los saltos de línea en el título de un gráfico. Las funciones strwrap
y WriteLines
permiten formatear adecuadamente cadenas de caracteres de gran longitud.
15.2 Escritura de datos en una hoja de cálculo
La función writexl::write_xlsx
permite copiar data frames a una hoja de cálculo de Excel. Para tal efecto se usa la siguiente sintaxis:
dfiris <- as.data.frame(iris)
writexl::write_xlsx(dfiris, "Iris.xlsx")
Para este ejemplo, mediante la primera línea se asigna el contenido de iris
al data frame dfiris
28. El data frame que se desee exportar (en este caso, dfiris
) se usa como primer argumento de la función write_xlsx
para ser exportado a la hoja de cálculo “Iris.xlsx”.