1.1 Organización
Para la organización de archivos (datos, código, informes…) lo recomendable es emplear un directorio con la estructura adecuada.
Dependiendo del objetivo puede interesar emplear un proyecto de RStudio (menú File > New project…). En mi caso empleo esta opción para paquetes, libros en bookdown, webs con blogdown y aplicaciones shiny. En otros casos empleo una carpeta que puede tener subdirectorios (si el proyecto es más grande) para distintos tipos de archivos o para distintas tareas (con el objetivo de facilitar la búsqueda). Por ejemplo: datos, informes, resultados_2023…
Mi recomendación es emplear nombres de archivos y carpetas en minúscula (o con la primera letra en mayúsculas), sin espacios (por ejemplo empleando _
para separar palabras o iniciales) y sin caracteres especiales (ASCII, sin acentos…).
Los nombres deberían ser lo más descriptivos posibles (en el sentido de evitar confusión).
Pueden incluirse descripciones más completas en el código, en ficheros de texto (e.g. Descripcion_archivos.txt), o incluso en hojas de cálculo.
Yo además acostumbro a incluir archivos del tipo Notas.txt (con recordatorios, decisiones…) o Pendente.txt (con próximos pasos, mejoras o verificaciones pendientes…).
Además, nos puede interesar establecer opciones de R específicas para el proyecto (por ejemplo opciones de configuración de memoria, de paquetes o variables de entorno, incluyendo claves privadas), de forma que se establezcan automáticamente al iniciar R o RStudio.
Para más detalles ver la ayuda de ?Startup
, el apéndice Invoking R o el post de RStudio
Managing R with .Rprofile, .Renviron, Rprofile.site, Renviron.site, rsession.conf, and repos.conf
Para desarrollar código y proyectos de forma colaborativa, la recomendación es emplear un sistema de control de versiones. Se puede configurar RStudio para emplear Git (ver el libro Happy Git and GitHub for the useR o la sección Git and GitHub), sin embargo yo prefiero emplear GitHub Desktop.
1.1.1 Código e informes
Mi recomendación a la hora de escribir código es seguir un proceso iterativo. Se comienza realizando pruebas y al finalizar cada etapa se trata de reorganizar el código (adaptándolo al estilo de programación elegido, lo que incluiría añadir comentarios y secciones) de forma que sea más cómodo continuar trabajando en siguientes etapas (y si es posible que resulte más fácil de adaptar para otros casos).
En el caso de informes el proceso sería similar, empleando como punto de partida un fichero de código en formato spin (ver Sección 3.7), en el que el texto RMarkdown se incluye como un comentario de código empleando #'
.
Por ejemplo:
#' # Sección
#'
#' ## Subsección
#'
#' Texto rmarkdown...
En primer lugar me preocupo de escribir un código funcional y, además de ir añadiendo comentarios de la forma habitual, voy añadiendo secciones y texto rmarkdown en formato spin. Finalmente, cuando tengo una primera versión del código (que puedo ir previsualizando; en RStudio basta con pulsar2 Ctrl + Shift + K, el icono correspondiente en la barra superior, o seleccionar File > Compile Report…), lo transformo a formato .Rmd con un comando de la forma:
::spin("Informe.R", knit = FALSE) knitr
donde termino de redactar (knitr::purl("Informe.Rmd", documentation = 2)
genera un nuevo fichero Informe.R donde resulta más cómodo modificar o desarrollar código).
Se recomienda elegir un estilo que sea consistente y seguirlo por completo en todo el proyecto. Lo principal sería el operador de asignación, el espaciado y el estilo de nombres (de objetos, variables o ficheros):
estilo.clasico
: es el estilo del paquete base de R. Muchos programadores no lo recomiendan (principalmente porque este separador no se admite en otros lenguajes y porque puede dar lugar a confusión con métodos S3, ver Sección 2.3).estilo_serpiente
(oEstilo_serpiente
): es el estilo de la colección de paquetestidyverse
.EstiloCamello
(oestiloCamello
): es el estilo (casi obligatorio) para las clasesR6
(ver Sección 2.3). El paqueteshiny
emplea la variante que comienza por minúsculas.
Recomiendo emplear <-
como operador de asignación y escribir todos los nombres en minúsculas.
Yo tengo tendencia a emplear el estilo.clasico
, sobre todo si el código no depende de paquetes tidyverse (en ese caso suelo emplear estilo_serpiente
).
También influye el estilo de nombres empleado por la fuente de datos o el requerido en los resultados.
El estilo también debe especificar el sangrado, el espaciado, etc. Por ejemplo:
Para facilitar la legibilidad es muy recomendable incluir un espacio entre los elementos del comando.
En RStudio se puede seleccionar un trozo de (una línea de) código y pulsar Ctrl + Shift + A para formatearlo.
También podemos emplear el paquete styler
para formatear el código.
Por ejemplo, en RStudio podemos emplear Addins > Styler > Style active file.
Además se recomienda crear secciones y documentar el código adecuadamente.
En RStudio se puede crear una sección pulsando Ctrl + Shift + R o añadiendo al menos 4 guiones (-
, también =
o #
) después de un comentario.
Por ejemplo:
# Sección ----
## Subsección ----
El orden de las secciones y subsecciones es importante. Al principio del código debería ir:
- Los parámetros o variables globales.
- La carga de paquetes (únicamente los mínimos requeridos).
- La carga de código externo.
- La carga de archivos de datos (o al principio de la sección donde se emplean, si son datos auxiliares).
No se recomienda emplear rutas absolutas en el código, del tipo:
setwd("C:/Documentos/Proyectos/Proyecto_X")
load("C:/Documentos/Proyectos/Proyecto_X/datos_x.RData")
source("C:/Documentos/Proyectos/R/Herramientas.R")
Como punto de partida el directorio de trabajo debería ser la carpeta del proyecto. Esto ya ocurre por defecto si empleamos proyectos de RStudio o si iniciamos RStudio abriendo un archivo de código en esta carpeta. En general, la recomendación es asumir que el directorio de trabajo es aquel en el que se encuentra el archivo de código (lo que también ocurre por defecto al compilar un documento RMarkdown). Si no es el caso se puede emplear el menú Sesion > Set Working Directory > To Source File Location.
Para establecer la ruta a archivos o directorios se recomienda emplear rutas relativas (usando ../ para acceder a la carpeta anterior; ./ sería el actual directorio de trabajo). Por ejemplo:
load("datos/datos_x.RData")
source("../R/Herramientas.R")
<- as.character(Sys.Date() - 1, format = "%m_%d") # Por ejemplo...
fecha_txt ::render("informe.Rmd", params = list(fecha_txt = fecha_txt),
rmarkdownoutput_file = paste0('informes/informe_', fecha_txt, '.html'),
envir = new.env(), encoding = "UTF-8")
La mejor forma de organizar funciones es desarrollar un paquete, como se comenta más adelante en la Sección 2.4.
1.1.2 Datos
La recomendación es emplear ficheros de datos con el formato por defecto de R (datos binarios comprimidos), con extensión .RData. Hay que tener en cuenta que lo esperable es que el archivo contenga un conjunto de datos con el mismo nombre, aunque podría no ser el caso e incluso contener varios objetos.
Uno de los problemas con los ficheros .RData es que, al cargarlos con load()
de la forma habitual, se añaden al entorno de trabajo los objetos que contienen con los nombres con que se almacenaron (y si ya existe alguno con ese nombre lo sobreescribe)
Para almacenar un único objeto de forma que se pueda cargar posteriormente especificando el nombre, se pueden emplear las funciones saveRDS()
y readRDS()
.
Sin embargo, lo habitual es que inicialmente los datos procedan de una fuente externa. Se pueden importar datos externos en casi cualquier formato a R (aunque puede requerir instalar paquetes adicionales). Mi recomendación es separar los análisis de la importación de los datos. Crear un fichero de código específicamente para importar los datos3, hacer el (pre)procesado y guardarlos en formato .RData. Yo habitualmente empleo el mismo nombre para el archivo de código y el archivo de datos que se genera (e.g. datos.R contiene el código necesario para generar datos.RData; no suelo renombrar el fichero fuente de datos externo, aunque se aleje mucho del estilo elegido). Asociado a un mismo conjunto de datos puede haber distintos archivos de código para realizar distintos análisis (el nombre de esos archivos debería dar una pista del análisis que realizan).
En muchas ocasiones, para modificar los nombres de las variables o los niveles de un factor, suelo recurrir a la función dput()
para escribirlos en modo texto (e.g. dput(tolower(names(datos)))
o dput(levels(datos$factor))
) y posteriormente modificarlos a mano.
Yo recomiendo añadir un atributo variable.labels
que contenga un vector de etiquetas de las variables y empleando como nombres de las componentes las propias variables:
data(cars)
# dput(names(cars))
<- c(speed = "Speed (mph)", dist = "Stopping distance (ft)")
var.lab attr(cars, "variable.labels") <- var.lab
str(cars)
## 'data.frame': 50 obs. of 2 variables:
## $ speed: num 4 4 7 7 8 9 10 10 10 11 ...
## $ dist : num 2 10 4 22 16 10 18 26 34 17 ...
## - attr(*, "variable.labels")= Named chr [1:2] "Speed (mph)" "Stopping distance (ft)"
## ..- attr(*, "names")= chr [1:2] "speed" "dist"
# View(cars)
# with(cars, plot(speed, dist, xlab = var.lab["speed"],
# ylab = var.lab["dist"]))
Para leer ficheros de Excel acostumbro a utilizar los paquetes openxlsx
(solo para archivos con extensión .xlsx) o readxl
(colección tidyverse
; Sección 4).
En estos casos además se puede añadir una nueva hoja de cálculo con los nombres de las variables junto con su etiqueta, que se puede cargar y emplear durante el preprocesado.
Adicionalmente esta tabla puede incluir una columna con los nuevos nombres (yo recomiendo no modificar los antiguos en este fichero), otra con un filtro para seleccionar variables (o el orden después del procesado) e incluso una columna con anotaciones o observaciones.
Ver top500.R en ejemplos.
Para mostrar las combinaciones de teclas en RStudio podemos emplear el menú Tools > Keyboard Shortcuts Help.↩︎
Con algunos tipos de datos, se puede emplear los submenús de RStudio File > Import Dataset para seleccionar los ajustes, previsualizando el resultado, y generar el código para importarlos.↩︎