+ - 0:00:00
Notes for current slide
Notes for next slide
Copy to clipboard
usethis::create_package(here::here("Packages", "example"))

Advanced R for Econometricians

Writing R packages

Martin C. Arnold, Alexander Gerber

1 / 16

Minimal Package

The smallest usable R package consists of

  • an R/ directory, containing the R Code.
  • a DESCRIPTION file containing meta data about the package.
  • a NAMESPACE file which defines which functions are imported and exported.

  • By running

    Copy to clipboard
    usethis::create_package("path/to/package/pkgname")

    a minimal package gets automatically created. It will also create and open an R project for your package.

  • We learnt how to work with Git and we want you to use it for package development, too.

    Git is easily initialized with:

    Copy to clipboard
    usethis::use_git()
2 / 16
Copy to clipboard
usethis::create_package(here::here("Packages", "example"))

Write your first own package

We start by writing a first little package together. The steps are based on R packages: The whole game.

Before we start we should think about what our package should do:

  • Since factors in R are often frustrating to work with we could write a package which makes working with factors easier.
3 / 16

Write your first own package

We start by writing a first little package together. The steps are based on R packages: The whole game.

Before we start we should think about what our package should do:

  • Since factors in R are often frustrating to work with we could write a package which makes working with factors easier.

  • Have you ever tried to combine 2 factors?

    ## [1] character hits your eyeballs
    ## Levels: character eyeballs hits your
    ## [1] but integer where it counts
    ## Levels: but counts integer where it
    ## [1] 1 3 4 2 1 3 4 2
3 / 16

Write your first own package

We start by writing a first little package together. The steps are based on R packages: The whole game.

Before we start we should think about what our package should do:

  • Since factors in R are often frustrating to work with we could write a package which makes working with factors easier.

  • Have you ever tried to combine 2 factors?

    ## [1] character hits your eyeballs
    ## Levels: character eyeballs hits your
    ## [1] but integer where it counts
    ## Levels: but counts integer where it
    ## [1] 1 3 4 2 1 3 4 2

    Lets write a function called fbind() that does what one would expect.

3 / 16

Write your first own package

Copy to clipboard
fbind <- function(a, b) {
factor(c(as.character(a), as.character(b)))
}
fbind(a, b)
## [1] character hits your eyeballs but integer where it counts
## Levels: but character counts eyeballs hits integer where it your
4 / 16

Where to save your function?

  • All R code of the package should be in .R files in the R/ directory. Put the function you have just written into the file R/fbind.R.

  • By calling

    Copy to clipboard
    usethis::use_r("fbind.R")

    a file gets automatically created in the correct folder.

    If you call this function using an existing file in R\ it will open the corresponding script.

5 / 16

Does the function work in the package environment?

  • Right now this might seem a bit of an overkill, however, if the package becomes more complicated you should use load_all() to make all functions in the R\ directory available.

  • load_all() simulates the process of building, installing, and attaching the package which makes it easy to test if the function works as expected within the package. The RStudio shortcut for this is Ctrl + Shift + L.

6 / 16

Check

After we have checked that the function is working, we also want to check if the package as a whole is working.

Run check() to do so.

Read the output of the check! Deal with problems early and often. It’s just like incremental development of .R and .Rmd files. The longer you go between full checks that everything works, the harder it becomes to pinpoint and solve issues.

You should see 2 warnings:

  • Non-standard license specification
  • Undocumented code objects: 'fbind'
7 / 16

Description File

  • The description file holds the meta data of the package.

    You can change the name and title of the package. There is also room for a little description. Most parts of this file are only relevant when you think about distribute your package e.g. via CRAN.

  • To get rid of the licence warning use licence: CC0. This puts your package in the public domain.

  • More information about licenses can be found here: License: Who can use your package?

  • Another important field is Imports: where you have declare which other packages you use within your package. More about this later.

8 / 16

Documentation

The second warning told us that a documentation for our function is missing. Again, if it is only for private usage this might not be too important. But if the package should be published on CRAN a documentation is required.

The documentation is created when a package is build based on the files in the folder man/. For our function fbind() we need a file man/fbind.Rd. However, we don't need to edit this file yourself.

roxygen2

roxygen2 is a package that helps us with the documentation. We basically comment our function definitions with something like the following:

Copy to clipboard
#' Bind two factors
#'
#' Create a new factor from two existing factors, where the new factor's levels
#' are the union of the levels of the input factors.
#'
#' @param a factor
#' @param b factor
#'
#' @return factor
#' @export
#' @examples
#' fbind(iris$Species[c(1, 51, 101)], PlantGrowth$group[c(1, 11, 21)])
9 / 16

Documentation

  • A very basic template for package documentation gets created by RStudio if you navigate the courser into a function call and click Code > Insert roxygen skeleton or by pressing Ctr + Alt + Shift + R.

  • After this is done run devtools::document(). Now, there should be a man/ directory with a file in it.

10 / 16

NAMESPACE

  • The call to devtools::document() not only creates the documentation but also keeps the NAMESPACE file up-to-date.

  • The export directive in NAMESPACE is what makes fbind() available to a user after attaching foofactors via library(foofactors).

    We actually told roxygen to export fbind() by putting

    Copy to clipboard
    #' @export

    in front of the function call.

  • Your NAMESPACE file should now look like this:

    Copy to clipboard
    # Generated by roxygen2: do not edit by hand
    export(fbind)
11 / 16

Install the package

  • Use check() again again to see if the warnings are gone and everything runs fine. Then run install() to put your package into your library.

  • We may now attach the package using library()

    Copy to clipboard
    library(foofactors)
12 / 16

Import Packages

  • Often we want to use functions from other packages. For this to work we first need to import functions from the namespace of other packages.

    Exercise:

    Add a function that combines lm() and summary() to your package. Then run check(). What do you notice?

13 / 16

Import Packages

  • Often we want to use functions from other packages. For this to work we first need to import functions from the namespace of other packages.

    Exercise:

    Add a function that combines lm() and summary() to your package. Then run check(). What do you notice?

  • Even functions from the (always available) stats or utils packages should be imported. This important for being able to publish a package on CRAN.

    You must declare your intent to use functions from the stats namespace with

    Copy to clipboard
    usethis::use_package("stats")

    This will add the stats package to the import field of the DESCRIPTION file

  • If you want to call a function from that package later use packagname::function()

13 / 16

More about Namespaces

Exercise:

What output do you expect for this code?

Copy to clipboard
library(dplyr)
library(MASS)
mtcars %*% select(mpg)
14 / 16

More about Namespaces

Exercise:

What output do you expect for this code?

Copy to clipboard
library(dplyr)
library(MASS)
mtcars %*% select(mpg)
  • The problem here is that both the dplyr and the MASS package export a function select(). The one in the package which was loaded last is used.

  • Use of Namespaces disambiguates which function we want to use. We can tell R to look for the function with the name select() exported by the dplyr package by calling dplyr::select().

14 / 16

Imports

  • We already know that we need to put packages which we are using need to be specified in the import field of the DESCRIPTION file. It ensures that these packages are installed if our package is installed and dplyr::select() will work within the package.

  • We use NAMESPACE to define which functions from other packages we want to use without having to use::

    Copy to clipboard
    import(dplyr) # import all functions from one package
    importFrom(dplyr, select) # import selected functions

    We think it is better too use :: to make it explicit where a function comes from.

15 / 16

Thank You!

16 / 16

Minimal Package

The smallest usable R package consists of

  • an R/ directory, containing the R Code.
  • a DESCRIPTION file containing meta data about the package.
  • a NAMESPACE file which defines which functions are imported and exported.

  • By running

    Copy to clipboard
    usethis::create_package("path/to/package/pkgname")

    a minimal package gets automatically created. It will also create and open an R project for your package.

  • We learnt how to work with Git and we want you to use it for package development, too.

    Git is easily initialized with:

    Copy to clipboard
    usethis::use_git()
2 / 16
Copy to clipboard
usethis::create_package(here::here("Packages", "example"))
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow