This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.
Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.
plot(cars)
Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.
When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).
The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.
You can knit notebook into PDF or Word. Make sure to install the tinytex
package using the following code: install.packages("tinytex")
. If you already use with another distribution, then you do not need to install tinytex
(though this works perfectly out of the bag). Then from the menu above (Knit), then choose Knit to PDF
or Knit to Word
. This is an excellent way to get your work fully written within RStudio: You will write a text (like this), have a specific structure and also have all your results in one place. This allows for transparency and replicability.
R Scripts only contain R code to be executed. RMarkdown contains many more details, including a text you write (like in word), your code (look at information within a chunk; this is delimited with {r}
).
Look at an example of an R Script. TO create an R script, simply click on New, then R script. copy the code below and add comments with a #. Don’t forget to save it with an extension .R
When you use an R Script, you always need to set the working directory, use setwd("path/to/directory")
and getwd()
. Use the menu above to set it up. With RMarkdown, this is not needed!!
R
is the most influential statistical software that is widely used in data science. The R Project for Statistical Computing. R allows the user to take control of their analyses and being open about how the data were analysed, etc. R
encourages transparency and reproducible research.
If you are a windows user, download the latest version here R version 4.1.2. If you are a MacX user, download the latest version here R version 4.1.2. Other Linux versions available here.
Using up-to-date versions of R
is important as this allows you to use the latest developments of the software. You can have a look at what is new in this latest release here.
You can download the latest version from above and update. Or you can use the package installr
and upgrade to the latest available version. If the package is not installed, use this: install.packages("installr")
and then run with library(installr)
then type installr
in the console (what? what’s a console?). We’ll come to this later on!
R Studio is one of the mostly used free and open-source integrated development environment for R
. It allows the user to have access to various information at the same time, e.g., the Source
, the Console
, the Environment
and the Files
, etc. When you open R studio
, and if you have installed R
appropriately, then R
Studio will “talk” to R
by sending it messages to execute commands.
You can set up the layout to suit your needs. I always find the following layout best for my needs:
Source
pane: the file where you write your codeConsole
where actual code is runEnvironment
pane, which shows you all variables/datasets, with the history of executed code, etc.Files/Viewer
pane, which shows you the files in the current folder, the plots, the installed packages, and help files, etc.If you click on Tools and Global options, then Pane Layout, you can change the order, and add/remove options from the two panes below. You will see that I use a specific formatting as this suits me best and also have a special colour-coding used (Theme Modern et Editor theme = Tomorrow Night Bright). Use the theme that works best for you!!
I use Sublime Text to run Python, Praat and write in . I use R Markdown in R to publish my code and write notebooks. I am in the process of writing my first article with R Markdown for a fully reproducible research.
There are many development environments that can be used to “talk” to R: TinnR, Visual Studio, etc…
GUIs (for Graphical User Interface) for R
are available. I list below a few. However, after trying some, I found it much easier to get to code directly in R. I don’t remember all codes! I use these to my advantage, by saving my code into a script and using it later on in other scripts.
Some of the GUIs are meant to make R
like excel or SPSS, while others are more specialised. Here is a list of some of these GUIs…
install.packages("Rcmdr")
. Then using R
base, run RCommander from using library(Rcmdr)
.library(rattle)
then rattle()
to run)library(Deducer)
after installation)You can always start by using any of the above to familiarise yourself with the code, and then move to using R
fully via code. My recommendation is to start coding first thing and search for help on how to write the specific code you are after.
Well almost. There is one thing we need to consider: telling R
where is our working directory. By default R
saves this to your documents (or somewhere else). Here, this is generally OK, though when working on your own data, things get more complicated.
There are two schools of thought here. 1. Create R
scripts that run the analyses and saves the output(s) directly to your working directory. Does not save the .RData
image at the end 2. Create a project: a self-contained folder, where all your scripts, figures, etc. will be automatically saved. Saves the .RData
at the end
I subscribe to the second, as some of the computations I run take ages to finish.
Click the menu Session -> Set Workign Directory -> Choose Directory
or use setwd("path/to/directory")
(choose the location where you want to save the results)
You can also use getwd()
to know where is your current working directory.
Look at the top-right hand where you can see Projects (none)
. You can create a new project in a new path or based on a specific folder.
Base R comes with many packages already installed. Look at packages
to see which ones are already installed. There are currently 18377 packages on Cran (repository for all packages). No one uses all packages so do not try to install all of them. Simply install what you need!! RMarkdown will let you know if you are running a specific code that lacks a package and asks you to download it.
The best option is to use the menu above (under Tools) and click Install packages
, or type in install.packages(“package.name”). Make sure to always have install dependencies
ticked (using the first option).
Use the following to load a package: library(package.name)
. Once the package is loaded, you can use any of its functions directly into your code. Sometimes you may need to specify to use a particular function from within a particular package, in this case use: package.name::function
. We will most probably not use this today, but this is something you need to know about otherwise undesirable results may occur (or even errors!).
Under the Files pane (right bottom), click on the menu Packages and you will have access to all installed packages. Click on a package and you can see the associated help files. You can also type the following to find help: ?package.name. ??function e.g.,
?stats
??MASS
Or try clicking on the function name to find details of what to specify: e.g., scroll on lmer
(assuming lme4
is installed). Do a Ctrl/Cmd + left mouse click on a function to display options.
::lmer lme4
function (formula, data = NULL, REML = TRUE, control = lmerControl(),
start = NULL, verbose = 0L, subset, weights, na.action, offset,
contrasts = NULL, devFunOnly = FALSE)
{
mc <- mcout <- match.call()
missCtrl <- missing(control)
if (!missCtrl && !inherits(control, "lmerControl")) {
if (!is.list(control))
stop("'control' is not a list; use lmerControl()")
warning("passing control as list is deprecated: please use lmerControl() instead",
immediate. = TRUE)
control <- do.call(lmerControl, control)
}
mc$control <- control
mc[[1]] <- quote(lme4::lFormula)
lmod <- eval(mc, parent.frame(1L))
mcout$formula <- lmod$formula
lmod$formula <- NULL
devfun <- do.call(mkLmerDevfun, c(lmod, list(start = start,
verbose = verbose, control = control)))
if (devFunOnly)
return(devfun)
if (identical(control$optimizer, "none"))
stop("deprecated use of optimizer=='none'; use NULL instead")
opt <- if (length(control$optimizer) == 0) {
s <- getStart(start, environment(devfun)$pp)
list(par = s, fval = devfun(s), conv = 1000, message = "no optimization")
}
else {
optimizeLmer(devfun, optimizer = control$optimizer, restart_edge = control$restart_edge,
boundary.tol = control$boundary.tol, control = control$optCtrl,
verbose = verbose, start = start, calc.derivs = control$calc.derivs,
use.last.params = control$use.last.params)
}
cc <- checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv,
lbound = environment(devfun)$lower)
mkMerMod(environment(devfun), opt, lmod$reTrms, fr = lmod$fr,
mc = mcout, lme4conv = cc)
}
<bytecode: 0x0000018595f26ee8>
<environment: namespace:lme4>
Install a package and search for help. Recommendation: Install package tidyverse
as we will use it from next week.
R
can be used as a calculator. Try some of the following below:
1 + 2
[1] 3
1+2*3
[1] 7
Well wait a second! were you all expecting the result to be 7? how many expected the result to be 9?
Check the following:
1+2)*3 (
[1] 9
1+(2*3)
[1] 7
So parenthesis are important! Always use these to tell R (and any other software) the order of operations. This is the order (remember PEMDAS):
There are many built-in functions in R to do some complicated mathematical calculations.
Run some of the following.
sqrt(3)
[1] 1.732051
3^2
[1] 9
log(3)
[1] 1.098612
exp(3)
[1] 20.08554
We can also create variables (aka temporary place holders).
<- 2
x <- 5
y <- x*y
b x
[1] 2
y
[1] 5
b
[1] 10
+log(y)*x^2 b
[1] 16.43775
When you create a variable and assign to it a number (or characters), you can use it later on.
We can also create sequences of numbers
seq(1, 10, 2)
[1] 1 3 5 7 9
?seq
<- 1:10 z
And we can do the following.. Can you explain what we have done here?
<- z+1
z2 *z2 z
[1] 2 6 12 20 30 42 56 72 90 110
Up to you… Write some more complex maths here just for fun!
# Add below
These will be useful throughout your work in R, but also pretty much any other programming language you encounter. They return values of TRUE or FALSE when evaluated. This type of value is called a boolean
value generally, but R specifically calls it a logical
value (abbreviated lgl
).
==
equivalent to>
greater than<
less than>=
greater than or equal to<=
less than or equal to!=
NOT equivalent to&
and (conjunction)|
or (disjunction)Objects are related to variables (we created above), but can also be dataframes, and other things we create in R. All of these are stored in memory and are shown below (under environment). You can check the type of the “object” below in the list (look at “Type”) or by using class()
.
Let’s look at the variables we created so far.. We will create another one as well…
class(b)
[1] "numeric"
class(x)
[1] "numeric"
class(y)
[1] "numeric"
class(z)
[1] "integer"
class(z2)
[1] "numeric"
<- "test"
a
class(a)
[1] "character"
When we do calculations in R, we need to make sure we use numeric/integer variables only.. Try some of the below
+y x
[1] 7
<- "2"
two + two x
Error in x + two : non-numeric argument to binary operator
Can you explain the error?
We have tried to add a number to a (character) string which is clearly impossible. To do the maths, we need to change the class using any of the following commands: as.character
, as.integer
, as.numeric
, as.factor
, e.g.:
<- as.numeric(two)
two + two x
[1] 4
We can create a vector of objects to do various things on.. We use the function c()
and do various things on:
<- c(1,4,5,12,55,13,45,38,77,836,543)
numbers class(numbers)
[1] "numeric"
mean(numbers)
[1] 148.0909
sd(numbers)
[1] 276.6375
median(numbers)
[1] 38
min(numbers)
[1] 1
max(numbers)
[1] 836
range(numbers)
[1] 1 836
sum(numbers)
[1] 1629
Sometimes we may want to refer to a specific position in the list of numbers we just created… Use the following:
2] numbers[
[1] 4
3:5] numbers[
[1] 5 12 55
-4] numbers[
[1] 1 4 5 55 13 45 38 77 836 543
+numbers[6] numbers
[1] 14 17 18 25 68 26 58 51 90 849 556
Can you explain what we have done in the last operation?
<- 1:4
x <- as.matrix(x)
x x
[,1]
[1,] 1
[2,] 2
[3,] 3
[4,] 4
dim(x)
[1] 4 1
dim(x) <- c(2,2)
dim(x)
[1] 2 2
x
[,1] [,2]
[1,] 1 3
[2,] 2 4
1,] x[
[1] 1 3
1] x[,
[1] 1 2
1,2] x[
[1] 3
# = x x[,]
[,1] [,2]
[1,] 1 3
[2,] 2 4
A dataframe is the most important object we will be using over and over again… It is an object that contains information in both rows and columns.
In this exercise, we will create a 4*9 dataframe. The code below creates four variables, and combines them together to make a dataframe. As you can see, variables can also be characters. To create the dataframe, we use the functions as.data.frame
and cbind
.
<- c("a", "the", "lamp", "not", "jump", "it", "coffee", "walk", "on")
word <- c(500, 600, 7, 200, 30, 450, 130, 33, 300) # note this is completely made up!!
freq <- c("y", "y", "n", "y", "n", "y", "n", "n", "y")
functionword <- c(1, 3, 4, 3, 4, 2, 6, 4, 2)
length <- as.data.frame(cbind(word,freq,functionword,length)) df
Environment
If you have created various variables you do not need any more, you can use rm
to remove these
rm(word,freq,functionword,length)
BUT wait, did I remove these from my dataframe? Well no.. We have removed objects from within the R
environment and not from the actual dataframe. Let’s check this up
df
The code below allows you to save the dataframe and read it again. The extension .csv
is for “comma delimited files”. This is the best format to use as it is simply a text file with no additional formatting.
write.csv(df,"df.txt")
<- read.csv("df.csv")
dfNew df
dfNew
The newly created object contains 5 columns rather than the 4 we initially created. This is normal. By default, R
add a column that reflects the order of the list before it was saved. You can simply delete the column or keep as is (but be careful as this means you need to adjust any references to columns that we will use later on).
R
allows us to read data in any format. If you have a .txt
, .sav
, .xls
, .xlsx
, etc., then there are packages specific to do that (e.g., package xlsx
to read/save .xlsx
files, or the function haven
from the package Tidyverse
to read/save .sav
files).
You can use the built-in plugin in RStudio
to import your dataset. See Import Dataset
within the Environment
.
In general, any specific formatting is kept, but sometimes variable names associated with numbers (as in .sav
files) will be lost. Hence, it is always preferable to do minimal formatting on the data.. Start with a .csv
file, import it to R
and do the magic!
The first thing we will do is to check the structure of our created dataset. We will use the originally created one (i.e., df
and not the imported one (i.e., dfNew
).
str(df)
'data.frame': 9 obs. of 4 variables:
$ word : chr "a" "the" "lamp" "not" ...
$ freq : chr "500" "600" "7" "200" ...
$ functionword: chr "y" "y" "n" "y" ...
$ length : chr "1" "3" "4" "3" ...
The function str
gives us the following information:
$
and what comes after it)class
of a variableAs we can see, the four created variables were added to the dataframe as factors
. We need to change the class
of the numeric variables: freq and length. Let’s do that:
$freq <- as.numeric(df$freq)
df$length <- as.numeric(df$length)
dfstr(df)
'data.frame': 9 obs. of 4 variables:
$ word : chr "a" "the" "lamp" "not" ...
$ freq : num 500 600 7 200 30 450 130 33 300
$ functionword: chr "y" "y" "n" "y" ...
$ length : num 1 3 4 3 4 2 6 4 2
As you can see from the above, we can refer to a particular variable in the dataframe by its name and adding $
. There are additional options to do that. Let’s see what we can do. Can you tell what each of the below does? chat to your neighbour….
1] df[
1] df[,
[1] "a" "the" "lamp" "not" "jump" "it" "coffee"
[8] "walk" "on"
1,] df[
1,1] df[
[1] "a"
Here are the answers:
Practice a bit and use other specifications to obtain specific observations, columns or rows…
# write here
We can use the function summary
to do some basic summaries
summary(df)
word freq functionword length
Length:9 Min. : 7 Length:9 Min. :1.000
Class :character 1st Qu.: 33 Class :character 1st Qu.:2.000
Mode :character Median :200 Mode :character Median :3.000
Mean :250 Mean :3.222
3rd Qu.:450 3rd Qu.:4.000
Max. :600 Max. :6.000
We can create a table with the function table
table(df$functionword, df$freq)
7 30 33 130 200 300 450 500 600
n 1 1 1 1 0 0 0 0 0
y 0 0 0 0 1 1 1 1 1
We sometimes need to create and/or delete new variables.. Do you know how to do that?
Let’s look at the structure again:
str(df)
'data.frame': 9 obs. of 4 variables:
$ word : chr "a" "the" "lamp" "not" ...
$ freq : num 500 600 7 200 30 450 130 33 300
$ functionword: chr "y" "y" "n" "y" ...
$ length : num 1 3 4 3 4 2 6 4 2
We said earlier that we can refer to a specific variable by using $
+ the name of the variable. Let’s use this again and add a new name of variable not in the list of variables above
$newVariable df
NULL
What does NULL
mean? The variable does not exist! Let’s do something else
$newVariable <- NA df
Ah no error messages! Let’s check the structure
str(df)
'data.frame': 9 obs. of 5 variables:
$ word : chr "a" "the" "lamp" "not" ...
$ freq : num 500 600 7 200 30 450 130 33 300
$ functionword: chr "y" "y" "n" "y" ...
$ length : num 1 3 4 3 4 2 6 4 2
$ newVariable : logi NA NA NA NA NA NA ...
So we now have five variables and the last one is named “newVariable” and assigned “NA”. “NA” is used in R
to refer to missing data or is a place holder. We can replace these with any calculations, or anything else. Let’s do that:
$newVariable <- log(df$freq)
dfstr(df)
'data.frame': 9 obs. of 5 variables:
$ word : chr "a" "the" "lamp" "not" ...
$ freq : num 500 600 7 200 30 450 130 33 300
$ functionword: chr "y" "y" "n" "y" ...
$ length : num 1 3 4 3 4 2 6 4 2
$ newVariable : num 6.21 6.4 1.95 5.3 3.4 ...
We replaced “NA” with the log of the frequencies. Let’s check that this is correct only for one observation. Can you dissect the code below? what did I use to ask R
to compute the log of the frequency (freq)? Remember rows and columns
log(df[1,2])
[1] 6.214608
1,5] df[
[1] 6.214608
So they are the same values.
Now we need to change the name of the variable to reflect the computations. “newVariable” is meaningless as a name, but “logFreq” is informative.
colnames(df)[5] <- "logFreq"
str(df)
'data.frame': 9 obs. of 5 variables:
$ word : chr "a" "the" "lamp" "not" ...
$ freq : num 500 600 7 200 30 450 130 33 300
$ functionword: chr "y" "y" "n" "y" ...
$ length : num 1 3 4 3 4 2 6 4 2
$ logFreq : num 6.21 6.4 1.95 5.3 3.4 ...
As can be seen from the above, using the command colnames(df)[5] <- "logFreq"
allows us to change the column name in position 5 of the dataframe. If we were to change all of the columns names, we could use colnames(df) <- c("col1","col2",...)
“.
As an exercise, let’s do that now. Change the names of all columns:
## change column names here
Let us now create a new compound variable that we later delete. This new compound variable will the multiplication of two numeric variables. The result is meaningless of course, but will be used for this exercise.
$madeUpVariable <- df$freq*df$length
dfstr(df)
'data.frame': 9 obs. of 6 variables:
$ word : chr "a" "the" "lamp" "not" ...
$ freq : num 500 600 7 200 30 450 130 33 300
$ functionword : chr "y" "y" "n" "y" ...
$ length : num 1 3 4 3 4 2 6 4 2
$ logFreq : num 6.21 6.4 1.95 5.3 3.4 ...
$ madeUpVariable: num 500 1800 28 600 120 900 780 132 600
Let us now delete this variable given that we are not interested in. Do you know how to do that? Think about how we referred to a variable before? We use df[colNumber]
. What if we use df[-colNumebr]
, what would be the result?
-6] df[
This shows all columns minus the one we are not interested in. If we rewrite the variable df
and assign to it the newly created dataframe we just used above (with the minus sign), then the column we are not interested in will be deleted.
<- df[-6]
df str(df)
'data.frame': 9 obs. of 5 variables:
$ word : chr "a" "the" "lamp" "not" ...
$ freq : num 500 600 7 200 30 450 130 33 300
$ functionword: chr "y" "y" "n" "y" ...
$ length : num 1 3 4 3 4 2 6 4 2
$ logFreq : num 6.21 6.4 1.95 5.3 3.4 ...
Let’s say that we want to change the names of our observations. For instance, the variable “functionword” has the levels “y” and “n”. Let us change the names to become “yes” and “no”. We first need to change the factor
level variable into character and then change the observations. Then we need to transform back to a factor
$functionword <- as.character(df$functionword)
df$functionword[df$functionword == "y"] <- "yes"
df$functionword[df$functionword == "no"] <- "no"
df$functionword <- as.factor(df$functionword)
dfstr(df)
'data.frame': 9 obs. of 5 variables:
$ word : chr "a" "the" "lamp" "not" ...
$ freq : num 500 600 7 200 30 450 130 33 300
$ functionword: Factor w/ 2 levels "n","yes": 2 2 1 2 1 2 1 1 2
$ length : num 1 3 4 3 4 2 6 4 2
$ logFreq : num 6.21 6.4 1.95 5.3 3.4 ...
We can also check the levels of factor and change the reference value. This is useful when doing any type of statistics or when plotting the data. We use levels
, relevel
and ref
levels(df$functionword)
[1] "n" "yes"
$functionword <-relevel(df$functionword, ref = "yes")
dflevels(df$functionword)
[1] "yes" "n"
We can also use the following code to change the order of the levels of a multilevel factor
levels(df$word)
NULL
$word <- factor(df$word, levels = c("a","coffee","jump","lamp","not","it","on","walk","the"))
dflevels(df$word)
[1] "a" "coffee" "jump" "lamp" "not" "it" "on"
[8] "walk" "the"
We may sometimes need to subset the dataframe and use parts of it. We use the function subset
or which
.
<- df[which(df$functionword == 'yes'),]
df_Yes1 #or
<- subset(df, functionword=="yes")
df_Yes2 str(df_Yes1)
'data.frame': 5 obs. of 5 variables:
$ word : Factor w/ 9 levels "a","coffee","jump",..: 1 9 5 6 7
$ freq : num 500 600 200 450 300
$ functionword: Factor w/ 2 levels "yes","n": 1 1 1 1 1
$ length : num 1 3 3 2 2
$ logFreq : num 6.21 6.4 5.3 6.11 5.7
str(df_Yes2)
'data.frame': 5 obs. of 5 variables:
$ word : Factor w/ 9 levels "a","coffee","jump",..: 1 9 5 6 7
$ freq : num 500 600 200 450 300
$ functionword: Factor w/ 2 levels "yes","n": 1 1 1 1 1
$ length : num 1 3 3 2 2
$ logFreq : num 6.21 6.4 5.3 6.11 5.7
When we subset the data, the levels of a factor are kept as they are.
levels(df_Yes1$functionword)
[1] "yes" "n"
levels(df_Yes2$functionword)
[1] "yes" "n"
But we only have one level of our factor..
$functionword df_Yes1
[1] yes yes yes yes yes
Levels: yes n
$functionword df_Yes2
[1] yes yes yes yes yes
Levels: yes n
By default, R
keeps the levels of the factor as they are unless we change it by using the following:
$functionword <- factor(df_Yes1$functionword)
df_Yes1$functionword <- factor(df_Yes2$functionword)
df_Yes2$functionword df_Yes1
[1] yes yes yes yes yes
Levels: yes
$functionword df_Yes2
[1] yes yes yes yes yes
Levels: yes
This is the end of this first session. We have looked at the various R
distributions, the GUIs
to R
, installing and using packages, then R
as a calculator, with basic and more advanced calculations. We then looked at the various object types, and created a dataframe from scratch. We did some manipulations of the dataframe, by creating a new variable, renaming a column, deleting one, and changing the levels of a variable.
This whole workshop relied on the base R
. Many researchers prefer to only use base R
as this is stable and the code rarely changes (well it does change!). Others prefer using many of the R
packages to speed up analyses or create lovely plots. I usually use a combination of base R
plots, and plots created with ggplot2
or lattice
.
We will look at these next week
sessionInfo()
R version 4.1.2 (2021-11-01)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19044)
Matrix products: default
locale:
[1] LC_COLLATE=English_United Kingdom.1252
[2] LC_CTYPE=English_United Kingdom.1252
[3] LC_MONETARY=English_United Kingdom.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United Kingdom.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods
[7] base
loaded via a namespace (and not attached):
[1] Rcpp_1.0.7 nloptr_1.2.2.2 pillar_1.6.4
[4] compiler_4.1.2 tools_4.1.2 boot_1.3-28
[7] digest_0.6.28 lme4_1.1-27.1 nlme_3.1-153
[10] evaluate_0.14 lifecycle_1.0.1 tibble_3.1.5
[13] gtable_0.3.0 PresenceAbsence_1.1.9 lattice_0.20-45
[16] pkgconfig_2.0.3 rlang_0.4.12 Matrix_1.3-4
[19] rstudioapi_0.13 cli_3.1.0 DBI_1.1.1
[22] yaml_2.2.1 xfun_0.27 fastmap_1.1.0
[25] dplyr_1.0.7 knitr_1.36 generics_0.1.1
[28] vctrs_0.3.8 grid_4.1.2 tidyselect_1.1.1
[31] glue_1.4.2 R6_2.5.1 fansi_0.5.0
[34] rmarkdown_2.11 minqa_1.2.4 ggplot2_3.3.5
[37] purrr_0.3.4 magrittr_2.0.1 scales_1.1.1
[40] ellipsis_0.3.2 htmltools_0.5.2 splines_4.1.2
[43] MASS_7.3-54 assertthat_0.2.1 colorspace_2.0-2
[46] utf8_1.2.2 munsell_0.5.0 crayon_1.4.2
[49] psycho_0.6.1