Paquetes
Como crear tu primer paquete con datos y algunas funciones.
Intro
Para crear un paquete principalmente hay que saber crear funciones.
Pero ¿Porque crear un paquete? 🤔
Algunas razones:
- Repito pasos y análisis con datos similares, hasta ahora re-uso funciones de scripts anteriores.
- Estudiantes y colegas me preguntan como realizar análisis similares, pero no están familiarizados con la sintaxis de las funciones
- Los artículos me piden más detalles de como se realizaron los análisis y el espacio es limitado para dar detalles.
- Aunque existan paquetes similares no cubren todos los pasos, sirven de inspiración pero no resuelven el problema.
1.1. Nombrar el paquete ✏️
Para crear paquetes se puede usar el paquete usethis
#install.packages('usethis')
library(usethis)
Antes de iniciar a crear un paquete, se puede consultar si el nombre no esta siendo usando en otro paquete en la página CRAN. También existe el paquete available para revisar si el paquete ya existe en CRAN o en github y si el nombre del paquete puede ser ofensivo.
install.packages('available')
library(available)
available("nombre_paquete")
Te va preguntar si quieres que revise por contenido ofensivo, puedes poner Y.
Urban Dictionary can contain potentially offensive results,/ [N]o: should they be included? [Y]es
Después abre paginas para mostrar que significa el nombre de el paquete.
1.2. Iniciar un paquete 👩🏽🔧️
Para crear un paquete la función create_package crea el esqueleto de los paquetes.
Dentro puedes poner el nombre del paquete que te interesa crear.
::create_package("nombre_paquete") usethis
Aparecerá algo así:
'nombre_paquete/'
√ Creating '...'
√ Setting active project to 'R/'
√ Creating 'DESCRIPTION'
√ Writing : nombre_paquete
Package: What the Package Does (One Line, Title Case)
Title: 0.0.0.9000
Version@R (parsed):
Authors* First Last <first.last@example.com> [aut, cre] (YOUR-ORCID-ID)
: What the package does (one paragraph).
Description: `use_mit_license()`, `use_gpl3_license()` or friends to
License
pick a license: UTF-8
Encoding: true
LazyData: list(markdown = TRUE)
Roxygen: 7.1.1
RoxygenNote'NAMESPACE'
√ Writing 'nombre_paquete.Rproj'
√ Writing '^nombre_paquete\\.Rproj$' to '.Rbuildignore'
√ Adding '.Rproj.user' to '.gitignore'
√ Adding '^\\.Rproj\\.user$' to '.Rbuildignore'
√ Adding '...' in new RStudio session
√ Opening '<no active project>' √ Setting active project to
Nota: Si te encuentras dentro de un proyecto va a preguntar si deseas sobregrabar el proyecto existente. Si es el caso: 2: Absolutely
'NAMESPACE'
v Writing -existing file 'nombre_paquete.Rproj'?
Overwrite pre
1: Not now
2: Absolutely
3: No way
Aparecerá algo como:
'nombre_paquete.Rproj'
v Writing '^nombre_paquete\\.Rproj$' to '.Rbuildignore'
v Adding '^\\.Rproj\\.user$' to '.Rbuildignore'
v Adding '...' in new RStudio session
v Opening '<no active project>' v Setting active project to
Se abrirá el proyecto en otra ventana.
1.3. Archivos 📄📂️
La función anterior creó los archivos:
- .gitignore
- .Rbuildignore
- DESCRIPTION
- NAMESPACE
- README.md
Las Carpetas:
- R
1.4. Git & Github 🐱🐙
Si ya tienes instalado git puedes directamente conectar el paquete con tu repositorio, escribiendo en tu consola:
::use_git() usethis
Aparecerá algo como:
'...'
√ Setting active project to '.Rdata', '.httr-oauth', '.DS_Store' to '.gitignore'
√ Adding 6 uncommitted files:
There are '.gitignore'
'.Rbuildignore'
'DESCRIPTION'
'NAMESPACE'
Is it ok to commit them?
1: Absolutely not
2: Yup
3: Negative
3: Yup… es si
Aparecerá algo como:
√ Adding files'Initial commit
√ Making a commit with message A restart of RStudio is required to activate the Git pane
Restart now?
1: Yup
2: No
3: Not now
Si deseas reiniciar RStudio para activar git:
1: Yup… es sip
Se reiniciara la sesión
Para ahora conectarlo con github, hay que escribir en la consola:
::use_github() usethis
Aparecerá algo como:
i Defaulting to https Git protocol'C:/...'
√ Setting active project to branch ('master')
√ Checking that current branch is default '...'
√ Creating GitHub repository 'origin' to 'https://github.com/...git'
√ Setting remote in DESCRIPTION to 'https://github.com/...'
√ Setting URL field in DESCRIPTION to 'https://github.com/...'
√ Setting BugReports field 1 uncommitted file:
There is 'DESCRIPTION'
Is it ok to commit it?1: No
2: No way
3: I agree
Si es correcto elegir 3: I agree, que significa de acuerdo
Aparecerá algo como:
√ Adding files'Add GitHub links to DESCRIPTION'
√ Making a commit with message 'master' branch to GitHub and setting 'origin/master' as upstream branch
√ Pushing 'https://github.com/...' √ Opening URL
Abrirá github
1.4. devtools ⏳
Escribir en la consola
::check() devtools
Esta función revisa la versión, plataforma, sesiones y demás.
Tarda un poquito.
0 errors √ | 1 warning x | 0 notes √
El warning ocurre porque hay que darle una licencia al paquete.
-standard license specification:
Non`use_mit_license()`, `use_gpl3_license()` or friends to pick a
license: FALSE Standardizable
1.5. Licencia 📋
Para software la licencia más común es MIT
::use_mit_license("Mi Nombre") usethis
Aparecerá algo como:
in DESCRIPTION to 'MIT + file LICENSE'
√ Setting License field 'LICENSE'
√ Writing 'LICENSE.md'
√ Writing '^LICENSE\\.md$' to '.Rbuildignore' √ Adding
Para revisar si funcionó:
::check() devtools
Tarda un poquito.
0 errors √ | 0 warning √ | 0 notes √
1.6. metadata ☎️
Para agregar metadata se debe abrir y modificar el documento que dice DESCRIPTION, agregando tus datos.
Esta es la información de contacto si hay problemas con el paquete.
@R:
Authorsperson(given = "Miriam",
family = "Lerma",
role = c("aut", "cre"),
email = "miriamjlerma@gmail.com",
comment = c(ORCID = "0000-0002-7632-9289"))
1.7. README 🏗️
Para crear un nuevo README, el paquete usethis tiene una función para crearlo de manera automática,
library(usethis)
use_readme_rmd(open = rlang::is_interactive())
'...'
√ Setting active project to 'README.Rmd'
√ Writing '^README\\.Rmd$' to '.Rbuildignore'
√ Adding 'README.Rmd'
Modify '.git/hooks/pre-commit' √ Writing
2. Datos 💾
Para agregar datos en tu paquete, puedes cargar tus datos y después guardarlos dentro de tu proyecto.
Por convención los datos son colocados en una carpeta que lleve el nombre de data dentro del paquete.
Puedes crear esta carpeta desde RStudio abriendo la pestaña de Files y eligiendo New Folder.
Para comprimir datos pesados puedes guardarlos como .rda.
save(TDR_raw, file="TDR_raw.rda")
Para revisar el peso de los datos puedes usar:
object.size(TDR_raw)
::mem_used() pryr
2.1. Documentar datos
Para documentar tus datos, puedes abrir un nuevo script (File>NewFile>R Script) o usar la función del paquete usethis.
Tanto la función use_r como use_data funcionan.
::use_r("mis_datos")
usethis::use_data("mis_datos") usethis
Esta función agrega comentarios Roxigen y guarda el documento en tu folder llamado R.
En mi caso yo le di al script el mismo nombre que a los datos.
#' Mis datos son datos de...
#' Contiene 264197 obs de 1 variable.
#' @docType data
#' @usage data(mis_datos)
#' @format Un data frame con 1 variable
#' @keywords datasets
#' @references Lerma et al. 2021
#' @examples
#' data(mis_datos)
"mis_datos"
Una vez creado el archivo .rda y .R se puede revisar si funcionó usando funciones del paquete devtools
::check() devtools
Si los datos son muy pesados y te aparece un mensaje como este:
: significantly better compression could be obtained
Note--resave-data by using R CMD build
Es mejor agregar el argumento compress.
save(TDR_raw, file="TDR_raw.rda", compress = "xz")
2.2. Resumido
Agrega datos al paquete
save(mis_datos, file="mis_datos.rda")
# Tu objeto, tu documento rda y tu R deben tener el mismo nombre.
::use_r("mis_datos")
usethis
#Insertar Roxigen Skeleton (CTRL+ALT+SHIFT+R) o copiar y pegar de otro archivo
::document()
devtools
::check() devtools
Si después de usar devtools::check(), aparece:
0 errors √ | 0 warnings √ | 0 notes √
Ya tienes tu primer paquete con datos 🥳.
- Para instalar el paquete de manera local
::install("C:/....") devtools
- Para instalar el paquete desde github
::install_github("Desarrollador/paquete") devtools
2.3. Actualizaciones
RData
Si aparece el mensaje WARNING: Added dependency on R >= 3.5.0 because serialized objects in serialize/load version 3 cannot be read in older versions of R. Hay que usar .RData
save(TDR_raw, file = "TDR_raw.RData", version = 2)
LazyData Tambien tener cuidado de incluir en DESCRIPTION
: true LazyData
If LazyData DB of 21.3 MB without LazyData Compression set
Agregar
:xz LazyDataCompression
If checking data for ASCII and uncompressed saves … Warning: package needs dependence on R (>= 2.10)
In DESCRIPTION:
: R (>= 2.10) Depends
Para poder usar directamente los datos
3. Funciónes 🤸🏾
Para este paso deberías tener alguna función en mente.
Si aún no sabes como crear tu primera función puedes ir a r4ds.
La estructura es algo así:
<-function(argumentos){
nombre_de_la_funcionalgo_que_haga_la_funcion_usando(argumentos)
return(resultado)
}
3.1. Función sin dependencias
Para agregar la función al paquete.
::use_r("mi_primera_funcion") usethis
Abre un nuevo script
Pega allí la función
Aparecerá algo como:
'C:/...'
√ Setting active project to 'R/mi_primera_funcion.R'
Modify `use_test()` to create a matching test file Call
Ahora en la carpeta R aparecerá dentro la función
Agregar un Roxigen skeleton:
- Poner el cursor justo en la primera linea de la función.
- Abrir la pestaña de Code>Insert Reoxygen Skeleton (también funciona con Control+Alt+Shift+R).
Aparecerá algo como:
#' Title
#'
#' @param data
#' @param trip_start
#' @param trip_end
#'
#' @return
#' @export
#'
#' @examples
Después de rellenar la información necesaria, para agregar la función al paquete, escribe en la consola:
::document() devtools
Aparecerá algo como:
Writing NAMESPACE Writing mi_primera_funcion.Rd
Al abrir la carpeta man aparecerá un documento rellenado.
El nombre man viene de manual y esta es la documentación del paquete.
No debe ser editado de manera manual.
Ya puedes revisar la documentación.
?mi_primera_funcion
::check() devtools
3.2. Funciones con dependencia
Te recomiendo probar tu función con datos de ejemplo, antes de incluirla en el paquete.
- Revisa que paquetes son requeridos, por ejemplo: tidyr
- Define los argumentos por separado como objeto.
=misdatos
data='mi_primer_argumento'
mi_primer_argumento='mi_segundo_argumento' mi_segundo_argumento
- Prueba la función
mi_funcion(data = mis_datos,
mi_primer_argumento='mi_primer_argumento',
mi_segundo_argumento='mi_segundo_argumento')
Otra opción es usar el paquete ‘testthat’ para probar tu función.
Para agregar la función al paquete:
::use_r("tu_funcion") usethis
Abre un nuevo script. Pega allí la función. En la consola aparecerá algo como:
'R/tu_funcion.R'
Modify `use_test()` to create a matching test file Call
Ahora en la carpeta R dentro del paquete aparece la función.
Nota sugiere que uses use_test pero puede en conflicto con el siguiente paso.
Puedes usar /rm() para quitar tu función.
Para poner la función en la memoria local y confirmar que se ejecute hay que incluirla en el paquete y probarla.
::load_all() devtools
Para documentar la función hay que crear un Roxigen skeleton.
Para esto se debe poner el cursor justo en la primera linea de la función.
Después ir a la pestaña de Code>Insert Reoxygen Skeleton (tambíen funciona con Control+Alt+Shift+R).
Va a aparecer algo así:
#' Title
#'
#' @param data
#' @param mi_primer_argumento
#' @param mi_segundo_argumento
#'
#' @return
#' @export
#'
#' @examples
Nota que identifica de manera automática las variables de la función
Ahora que ya esta la función y la documentación para agregar el paquete hay que escribir en la consola:
::document() devtools
Aparece:
Writing NAMESPACE Writing mi_funcion.Rd
Ahora en la carpeta man, aparece un documento rellenado.
man viene de manual y esta es la documentación del paquete.
Nota No debe ser editado de manera manual.
Puedes revisar la documentación de la función.
?mi_funcion
Dependencias son paquetes necesarios para que la función, funcione.
Para revisar si necesitas dependencias se puede usar:
::check() devtools
Si tu paquete tiene dependencias, aparecerán errores, warnings y notas.
Por ejemplo, un paquete que usa: - un %>% (pipe) depende del paquete magrittr, y - la función separate depende del paquete dplyr.
Para agregar las dependencias se puede escribir el nombre de los paquetes dentro de la función use_package
::use_package("dplyr") usethis
Aparecerá algo como:
'dplyr' to Imports field in DESCRIPTION
√ Adding `dplyr::fun()` Refer to functions with
Así mismo aparecerá en el documento DESCRIPTION:
:
Imports dplyr
Lo siguiente es especificar el paquete en la función, tal como recomienda el siguiente mensaje.
`dplyr::fun()` Refer to functions with
pipe 🖇️
La función pipe (%>%) del paquete magrittr es especial.
Por lo que hay que usar:
::use_pipe() usethis
Aparecerá algo como:
'magrittr' to Imports field in DESCRIPTION
√ Adding 'R/utils-pipe.R'
√ Writing `devtools::document()` to update 'NAMESPACE' Run
Se recomienda volver a documentar.
::document() devtools
Ahora deberá aparecer en la carpeta R un script llamado utils-pipe.R y
en el archivo DESCRIPTION deberá aparecer Imports magrittr
Para checar el paquete:
::check() devtools
0 errors √ | 0 warnings √ | 0 notes √
Listo! el paquete esta completo 🥳
stats 🧮
Cuando queremos agregar alguna función que incluya cálculos de desviación estándar, aunque no se necesite cargar el paquete en RStudio, la función proviene de un paquete.
El paquete es stats
Por lo tanto el paquete stats debe ser incluido en las dependencias.
::use_package("stats") usethis
Y agregado a la función.
<- data %>%
resultado::summarise(max_depth_mean=mean(.data[[var1]]),
dplyrmax_depth_sd=stats::sd(.data[[var1]]),
max_depth_max=max(.data[[var1]]))
::document()
devtools::check() devtools
::check() devtools
0 errors √ | 0 warnings √ | 0 notes √
Listo! el paquete esta completo 🥳
ggplot 🎨
Cuando creamos una función con ggplot hay que declarar el uso de la función en varios argumentos de la función. Aquí puedes leer más.
Si no, aparecerá un error:
1 error x | 0 warnings √ | 1 note x
Esto occurre debido a que al revisar el paquete, no detecta varias funciones del paquete ggplot.
function definition for 'aes' no visible global
Ejemplo:
::ggplot(data=data,ggplot2::aes(x=.data[[var1]],
ggplot2y=as.numeric(.data[[var2]])))+
::geom_line()+
ggplot2::ylab("Diving depth (m)")+
ggplot2::xlab("Month.Day Hour:Minute")+
ggplot2::scale_y_reverse()+
ggplot2::theme_bw() ggplot2
for possible problems ... checking R code
También pueden aparecer problemas con las variables al usar ggplot dentro de una función.
for global variable '.data' no visible binding
Para resolver esto hay que declarar las variables dentro de la función y posteriormente usar .data
<-TDR_trip
data<-time_column
var1<-depth_column
var2
::ggplot(data,
ggplot2::aes(x=.data[[var1]],
ggplot2y=.data[[var2]))+
::geom_line() ggplot2
::document()
devtools::check() devtools
::check() devtools
0 errors √ | 0 warnings √ | 0 notes √
Listo! el paquete esta completo 🥳
3.3. Otros problemas 👻
Problema En algunas funciones puedes haber usado assign. Usar assign no es recomendado, por lo que aparecerá una nota.
Solución Usar return().
Problema No nested functions, no circular dependencies.
Solución No puedes usar funciones de tu paquete en otras funciones del mismo paquete.
Problema Borrar funciones.
Solución Para borrar funciones se debe borrar el script en el archivo R y volver a documentar el paquete para que se reflejen los cambios.
Problema El ejemplo tiene más de 100 caracteres, es considerado muy largo.
Solución Separar en la documentación.
100 characters: \examples lines wider than
Problema Solo puedo tener un resultado (return)
Solución Crea una lista con los returns.
Por ejemplo:
funcion(primer_argumento, segundo_argumento){
<-primer_argumento*segundo_argumento
multiplicacion<-primer_argumento+segundo_argumento
suma<-(list("multiplicacion"=multiplicacion,"suma"=suma))
listareturn(lista)
}
Problema Al usar slot en sapply.
Solución Hay que agregar la dependencia methods.
3.4. Resumido
::use_r("nombre_funcion")
usethis
#Insertar Roxigen Skeleton (CTRL+ALT+SHIFT+R)
::document()
devtools
::check()
devtools
::use_package("ggplot2")
usethis
#Referirse a funciones con ::
::check() devtools
Otros
4.1 Warnings ⚠️
Es útil agregar warnings para que el usuario (quien sera a veces tu mismo) pueda corregir errores.
Para checar que el data frame contenga datos, revisa que el numero de filas no sea cero.
if (nrow(data)!=0){
else {
} warning("Please check the name of the data frame")
}
También puedes revisar si tu data frame contiene una columna de acuerdo a su nombre
if ("Nombre_columna" %in% colnames(data)){
else {
} warning("Please check that your data frame has X column, otherwise please rename/create the column")
}
Ademas podemos revisar si una columna en especifico aparece en el data frame
if (!is.null(data[[columna]])) {
else {
} warning("The column X is not in your dataframe. Please check the name of the column")
}
️
4.2. Crear tu propio sticker ❣️
Para crear un hexSticker puedes usar plantillas:
- En powerpoint plantilla hecha por Emi Tanaka
- En R paquete hexSticker hecho por GuangchuangYu
Para instalar el paquete hexSticker, puedes descargarlo desde en CRAN:
install.packages("hexSticker")
4.3. Zenodo 🔗
Zenodo es un repositorio de acceso abierto operado por CERN (Organización Europea para la Investigación Nuclear).
Ventajas Permite que se depositen allí artículos de investigación, datos, software, informes y otro tipo de objeto digital relacionado con la investigación. La ventaja frente a github es que asigna un DOI.
Desventajas Las versiones de paquetes se pueden registrar en zenodo. No obstante, NO es tan practico ya que cada versión tiene su propio DOI y la versión anterior no puede ser eliminada.
Créditos y recursos 👩🏽🏫
Libros
R Packages R Packages 2eTutoriales sobre datos
Incluir datos
Documentar datosTu paquete en una hora
Piping hot dataVideos
Rladies como crear funciones
Rladies como crear paquetes