Introduction to Statistical Modelling with R

Author

Giulia Gaggero, CESLab

Index

  • Basic Operations with R

  • Boolean Operation

  • Vectors, Matrices, Lists, and Data Frames

How to read this document

This is an RMarkdown/Quarto Presentation document.

The part in gray are “chuncks” of RCode that you can directly copy, paste and run in your RStudio.

Everything that is written after the # symbol is a comment (within the R script).

Let’s start…

We can use the Console to make simple computations.

After writing the formula, press “Enter” and the output will appear

In the scripts you have to select and press enter to “Run” the code

1 + 4
[1] 5

“Arrow-up” button (⍐) is used to go back in the commands

Basic operations…

# if I use # I will write comments (green colour in whyte screen visualization)

1 + 4 ### ADDITION 
[1] 5
7 - 1 ### SUBTRACTION
[1] 6
9/3 ### DIVISION
[1] 3
3*2 ###  MULTIPLICATION
[1] 6
2^3 ## (2*2*2)  POWER (elevazione a potenza)
[1] 8
(3+2)*3 # use the parenthesis to give priority to operations
[1] 15

Exercise

Run the following operations:

  • seven plus seven

  • 140 divided by 9

  • 87 multiplied by 3

  • 82+2 and the result multiplied by 6

    First Use the console to run this operations!

    Create a script in which you write each operation and you put comments (#…) and save the file in a specific folder!

Anwers

7 + 7
[1] 14
140/9
[1] 15.55556
82 + 79 + 29
[1] 190
82 + 2 * 6
[1] 94
(82 + 2)*6
[1] 504

Create Objects (Variables)

We create objects using “<-” this symbol.

You can also use “=” but can be confusing…we will see why

An object can be everything (a scalar, vectors, matrices, dataframes, lists).

The name you assign to an object:

  • is arbitrary (“pippo” is fine as far as you can remember what is inside the “pippo” variable)

  • cannot be an arabic character (e.g. 4<-5)

  • You can use “Uppercases”, “_”, etc. within the names (e.g. firstNumber)

    Pay attention to the fact that R is case sensitive! “Pippo” and “pippo” are not recognised as the same person by R!

We start from scalars….

firstNumber<-5
secondNumber<-2

firstNumber*secondNumber ## operations with variables 
[1] 10
ls() ## Function that list of variables in the Global environment
[1] "firstNumber"     "has_annotations" "secondNumber"   
rm() ## Function that eliminates the variables in the Global environment

Variables/Objects will appear in the Global Environment

Pay attention to the fact that R is case sensitive!

“FirstNumber” is not equal to “firstnumber”

General Rule: Be consistent with “uppercase”, “lowercase”, “_”

Boolean Operations

Operations that will compare to elements and whose output can be “TRUE” or “FALSE”

“==” You are asking whether two elements are equal

“!=” You are asking whether two elements are NOT equal

“>” “<” You are asking whether the first element is higher/lower than the second

3 == 39
[1] FALSE
3!=39
[1] TRUE
3>39
[1] FALSE
3<39
[1] TRUE
### Create Variables 

peopleBrixen<-21688 #inhabitants in Brixen
peopleBozen<-106951 # inhabitants in Boxen

## Interrogate R...

peopleBrixen == peopleBozen
[1] FALSE
peopleBrixen != peopleBozen
[1] TRUE
peopleBrixen > peopleBozen
[1] FALSE
peopleBrixen < peopleBozen
[1] TRUE
(peopleBrixen != peopleBozen) & (peopleBrixen < peopleBozen) 
[1] TRUE

Other important operators are “&” (and), “|” (or).

Briefly recap the Truth Tables….

CONJUNCTION (&)

A B A & B
TRUE TRUE TRUE
TRUE FALSE FALSE
FALSE TRUE FALSE
FALSE FALSE FALSE

Example: To define an animal a “house cat”, it should be a “feline” AND “living in a house”.

Is “Romeo” (“O’Malley) from the Aristocats a”house cat”? Choose the condition…

DISJUNCTION (OR)

A B A OR B
TRUE TRUE TRUE
TRUE FALSE TRUE
FALSE TRUE TRUE
FALSE FALSE FALSE

Example: A pet, can be a “cat living in a house” (A) OR “a dog living in a house” (B).

Is “Duchess” from the Aristocats a pet? Choose the condition…

## In R, the logical AND operator is &

# TRUE & TRUE = TRUE
(peopleBrixen != peopleBozen) & (peopleBrixen < peopleBozen) 
[1] TRUE
# TRUE & FALSE = FALSE
(peopleBrixen != peopleBozen) & (peopleBrixen > peopleBozen) 
[1] FALSE
# FALSE & TRUE = FALSE
(peopleBrixen == peopleBozen) & (peopleBrixen < peopleBozen) 
[1] FALSE
# FALSE & FALSE = FALSE
(peopleBrixen == peopleBozen) & (peopleBrixen > peopleBozen) 
[1] FALSE
## In R, the logical OR operator is |

# TRUE | TRUE = TRUE
(peopleBrixen != peopleBozen) | (peopleBrixen < peopleBozen) 
[1] TRUE
# TRUE | FALSE = TRUE
(peopleBrixen != peopleBozen) | (peopleBrixen > peopleBozen) 
[1] TRUE
# FALSE | TRUE = TRUE
(peopleBrixen == peopleBozen) | (peopleBrixen < peopleBozen) 
[1] TRUE
# FALSE | FALSE = FALSE
(peopleBrixen == peopleBozen) | (peopleBrixen > peopleBozen) 
[1] FALSE

! operator will return the opposite…

!TRUE
[1] FALSE
!FALSE
[1] TRUE
!(peopleBrixen < peopleBozen)
[1] FALSE
!(peopleBrixen == peopleBozen)
[1] TRUE

Exercise

italyPop<-59 ### mln of hinabitants
germanyPop<- 68 ### mln of hinabitants

italyWater<- 1.24  ### % of water
germanyWater<-1.27 ### % of water

Given these variables, create two FALSE premises (statement) and two TRUE premises (statement).

Use the & operator to connect two premises (conjunction) in a way that the output will be TRUE

Use the OR operator to connect two premises (disjunction) in a way that the output will be FALSE

Data Structures

R manipulates data structures. The main data structures are:

Vectors

Vector is the simplest data structure. It contains >=1 elements of the same type (i.e. logical, integer, double, character).

Vectors are created in R by using the function c().

typeof()/mode() functions are used to explore the type of elements that are stored in a vector

vector0<-7 
vector1<-c(1,2,7,4) ### "numeric"/"double" vector 
vector1_2<-c(1.1,3.4,5,9.2) ### "numeric"/"double" vector

vector2<-c("giacomo","giovanni","karolyn") ## character vector 

vector3<-c(TRUE, FALSE, TRUE) ## logical vector

vector4<-c("1.1","3.4","5","9.2","ciao") ## "" transfor everything in a character

vector5<-factor(c("females","males","females","males","other")) ## integer (Very Important)

typeof(vector0)
[1] "double"
typeof(vector1)
[1] "double"
mode(vector1)
[1] "numeric"
typeof(vector2)
[1] "character"
typeof(vector3)
[1] "logical"
typeof(vector4)
[1] "character"
typeof(vector5)
[1] "integer"
str(vector5) 
 Factor w/ 3 levels "females","males",..: 1 2 1 2 3
### the function "structure" str() show the inside structure of the vector 

function length() gives you the number of elements in the vector.

length(vector0)
[1] 1
length(vector1)
[1] 4
length(vector2) ###etc.
[1] 3

Fast creation of vectors

Use the functions rep(), seq()

c(1:10) ## from 1 to 10
 [1]  1  2  3  4  5  6  7  8  9 10
c(2:20) ##from X to X
 [1]  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
seq(from = 5, to= 20, by = 5) ## function seq(from = XX, to = XX, by = XXX)
[1]  5 10 15 20
seq(from = 4, to= 20, by = 5) 
[1]  4  9 14 19
rep(0,4) ### rep(ARGUMENT1,ARGUMENT2) rep(X,Ntimes)
[1] 0 0 0 0
rep(TRUE,5)
[1] TRUE TRUE TRUE TRUE TRUE
rep("ciao",5)
[1] "ciao" "ciao" "ciao" "ciao" "ciao"
rep(c(1,2), 9)
 [1] 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2

Implicit Coercion

If you put inside a vectors objects of different type (e.g. integer, logical), there will be an implicit coercion, since vectors can only contain objects of a single type.

Let’s see who is the winner…the type of object prevailing on the others

c(TRUE, 1, FALSE) ##
[1] 1 1 0
c(2.3, TRUE) ## Implicit coercion! What happens?
[1] 2.3 1.0
c(1,2,3, "ciao")
[1] "1"    "2"    "3"    "ciao"
c(FALSE, "ciao", TRUE)
[1] "FALSE" "ciao"  "TRUE" 

Vectors with missing data (NA)

Coercion doesn’t happen with missing data (missing data appear in R with the “NA” symbol)

c(1,2,3,NA) ##
[1]  1  2  3 NA
c(2.3,2.0,3.0,NA) 
[1] 2.3 2.0 3.0  NA
c("ciao","good morning", NA)
[1] "ciao"         "good morning" NA            
c(FALSE,NA,TRUE)
[1] FALSE    NA  TRUE

But pay attention at computations with NA elements.

1 + NA
[1] NA
1 + c(1,2,3,4,NA)
[1]  2  3  4  5 NA
completeVector<-c(1,2,3,4)
incompleteVector<-c(1,2,3,4,NA)

sum(completeVector)
[1] 10
sum(incompleteVector)
[1] NA

You cannot run computations with NA objects. You need to exclude them!

To check whether there is an NA in your vector, you use the function is.na()

is.na(completeVector)
[1] FALSE FALSE FALSE FALSE
is.na(incompleteVector) 
[1] FALSE FALSE FALSE FALSE  TRUE
sum(incompleteVector) #Default mode of the sum function: sum(object, na.rm = FALSE)
[1] NA
sum(incompleteVector, na.rm = TRUE) ## specify that we whant to remove the NA
[1] 10

Let’s Exercise with vectors

  1. Create:

    1. a vector with numeric values (tell where they are or not integers)

    2. a vector with logicals

    3. a vector with characters

    4. a factor vector (e.g. think about a real variable you could potentially find in a dataset)

    5. a vector with numeric/double and missing values

    6. A vector of numbers from 5 to 15

    7. A vector of number from 100, 200,300,… to 1000 using the function seq

    8. A vector repeating the sequence (2,3,4) by 7 times (use the function rep)

  2. Verify the type of each vector using the functions “typeof”

  3. Verify the length of each vector

  4. Verify where is the missing value in the vector n.5

  5. Sum the elements within the vector n.5

  6. Without running the functions, predict the output of the following vectors, based on the “implicit coercion” rules we mentioned above:

    1. c(2.3,2.0,“females”, NA)

    2. c(1,2,3, TRUE)

    3. c(1.0,9.0,NA)

Matrices

Vector: 1* n elements (unidimensional collection of elements)

Matrix: n * n elements (bidimensional collection of elements)

Array: n * n * … elements (multidimensional collection of elements)

A scalar is a specific type of vector. A vector is a specific type of matrix. A matrix is a specific type of array…

How to create a matrix in R:

matrix1<-matrix(c(1:6), nrow = 2, ncol= 3)
matrix1 ##show the object matrix 1
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
matrix2<-matrix(c(1:6), nrow = 3, ncol= 2)
matrix2 ##show the object matrix 2
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6

By default, a matrix will fill cells by columns…otherwise, you have to specify it!

matrix1col<-matrix(c(1:6), nrow = 3, ncol= 2, byrow = TRUE) ### bydefault byrow = FALSE
matrix1col
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6

Explore the dimension of our matrices, using the dim() function

dim(matrix1) ## nrow, ncol
[1] 2 3
dim(matrix2) ## nrow, ncol
[1] 3 2
length(matrix1) ## multiply cols*rows
[1] 6
length(matrix2)
[1] 6

It is possible to transpose a matrix:

matrix1 ##2rows*3columns
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
t(matrix1) ## t transpose the matrix (rows become columns and viceversa)
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6
## 2rows*3 columns

I can assign names to columns and rows, using the functions “colnames()”,“rownames()”

matrix2
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6
rownames(matrix2)<- c("Subject1","Subject2","Subject3")
colnames(matrix2)<- c("Q1","Q2")
matrix2
         Q1 Q2
Subject1  1  4
Subject2  2  5
Subject3  3  6

Operations with Matrices

I can add, multiply or divide each element in a matrix by a number (scalar)…

matrix1
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
matrix1 +1
     [,1] [,2] [,3]
[1,]    2    4    6
[2,]    3    5    7
matrix1*2
     [,1] [,2] [,3]
[1,]    2    6   10
[2,]    4    8   12
matrix1/2 ## subdivision
     [,1] [,2] [,3]
[1,]  0.5  1.5  2.5
[2,]  1.0  2.0  3.0

…by a vector (sum a matrix with a vector)

…or you can do operations between matrices

matrix1
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
matrix1 + c(2,3) ###default by column 
     [,1] [,2] [,3]
[1,]    3    5    7
[2,]    5    7    9
matrix1 + c(2,3,4) ###default by column 
     [,1] [,2] [,3]
[1,]    3    7    8
[2,]    5    6   10
matrix100<-matrix(c(100,200,300,400,500,600), nrow = 2, ncol = 3)
matrix100
     [,1] [,2] [,3]
[1,]  100  300  500
[2,]  200  400  600
matrix1 + matrix100
     [,1] [,2] [,3]
[1,]  101  303  505
[2,]  202  404  606

you can sum matrices with matrices.

We will not go into details with the operations between matrix (just keep in mind that they have their own rules).

Fast creation of Matrices

Use the rep, seq functions to also create matrices.

matrix(rep(0,9), ncol = 3, nrow=3)
     [,1] [,2] [,3]
[1,]    0    0    0
[2,]    0    0    0
[3,]    0    0    0
matrix(0, ncol = 3, nrow=3)
     [,1] [,2] [,3]
[1,]    0    0    0
[2,]    0    0    0
[3,]    0    0    0

When working with R can be sometimes useful to create empty matrices that you will fill later….

matrix(, ncol = 2, nrow=3)
     [,1] [,2]
[1,]   NA   NA
[2,]   NA   NA
[3,]   NA   NA
matrix(NA, ncol = 2, nrow=3)
     [,1] [,2]
[1,]   NA   NA
[2,]   NA   NA
[3,]   NA   NA

A matrix can also contain “characters” or other type of objects…

matrix(c("pizza","pasta","mandolino"), ncol = 2, nrow=3)
     [,1]        [,2]       
[1,] "pizza"     "pizza"    
[2,] "pasta"     "pasta"    
[3,] "mandolino" "mandolino"
matrix(TRUE, ncol = 2, nrow=3)
     [,1] [,2]
[1,] TRUE TRUE
[2,] TRUE TRUE
[3,] TRUE TRUE

Remember that the implicit coercion is valid also for matrices…

matrix(c("pizza","pasta",1), ncol = 2, nrow=3)
     [,1]    [,2]   
[1,] "pizza" "pizza"
[2,] "pasta" "pasta"
[3,] "1"     "1"    
matrix(c(1,2,TRUE), ncol = 2, nrow=3)
     [,1] [,2]
[1,]    1    1
[2,]    2    2
[3,]    1    1

Check if there are NA in a matrix with the is.na function

matrix1
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
is.na(matrix1)
      [,1]  [,2]  [,3]
[1,] FALSE FALSE FALSE
[2,] FALSE FALSE FALSE
incompleteMatrix<-matrix(c(1,2,NA), ncol = 2,nrow=3)
incompleteMatrix
     [,1] [,2]
[1,]    1    1
[2,]    2    2
[3,]   NA   NA
is.na(incompleteMatrix)
      [,1]  [,2]
[1,] FALSE FALSE
[2,] FALSE FALSE
[3,]  TRUE  TRUE

Exercise with Matrices

  • Create a 2*4 matrix with numeric values

  • Create a 3*3 matrix with all NA or 0

  • Create the following matrix and name columns “FirstCol”,“SecondCol”

FirstCol SecondCol
1 12
3 15
6 18
9 21
  • Verify the length and dimension of the previous matrix, using the appropriate functions

  • apply the is.na() function to all the matrices you created, to check wether there are missing values

Data Frames

Data Frames are similar to matrices, because of their bidimensional structure (nrows x ncolumns).

Data frames can contain vectors (columns) of a different type (numeric, factors, character).

Our datasets (e.g. the one you extract from surveys) are usually organized as data frames, with a structure observations (rows)*variables(columns).

Examples of data frames:

Table1

SubjID Age Nationality Empathy Score
Subj1 67 Italian 83
Subj2 45 German 56
Subj3 23 French 65
Subj4 65 Italian 74
Subj5 54 German 80

Table2

SubjID Time (T1,T2,T3) Empathy Score
Subj1 T1 83
Subj1 T2 85
Subj1 T3 87
Subj2 T1 56
Subj2 T2 58
Subj2 T3 70

When there is only one administration phase, each row represents data from one subject. When there is >1 administration phase (repeated measures design, longitudinal studies), each row represents the administration at a given time (table 2).

How to create data frames in R?

Let’s take table 1 and recreate it with R

### First create the vectors 

SubjID<-c("Subj1","Subj2","Subj3","Subj4","Subj5")
Age<-c(67,45,23,65,54)
Nationality<-factor(c("Italian","German","French","Italian", "German"))
EmpathyScore<-c(83,56,65,74,80)

myDf1<-data.frame(SubjID,Age,Nationality,EmpathyScore) ##combine the vectors
myDf1
  SubjID Age Nationality EmpathyScore
1  Subj1  67     Italian           83
2  Subj2  45      German           56
3  Subj3  23      French           65
4  Subj4  65     Italian           74
5  Subj5  54      German           80
## If I want to change the names of my columns, I use the function colnames()
colnames(myDf1)<-c("ParticipantID","Age","Nation","EmpathyS")

str(myDf1) ##detect the structure of a data frame
'data.frame':   5 obs. of  4 variables:
 $ ParticipantID: chr  "Subj1" "Subj2" "Subj3" "Subj4" ...
 $ Age          : num  67 45 23 65 54
 $ Nation       : Factor w/ 3 levels "French","German",..: 3 2 1 3 2
 $ EmpathyS     : num  83 56 65 74 80
dim(myDf1) ## dimensions of data frame
[1] 5 4
View(myDf1)

Exercise! Your turn. Recreate the data frame in the second table!

Most of the time you will not need to create data frames from zero.

It is rather possible that you will need to download data frames (e.g. from Qualtrics, LimeSurvey, Google Moduli, etc.) and modify them (e.g. rename variables, change the type of variables) or cleaning them (check for NA, compute missing data) before moving to statistical analyses.

Lists

A list is an heterogeneous collection of objects of different types. A list can contain: vectors, matrices of different size, data frames, and even other lists.

vector2<-c("giacomo","giovanni","karolyn") ## character vector 
matrix1<-matrix(c(1:6), nrow = 2, ncol= 3) ## numeric matrix

list1 <-list(vector2,matrix1,myDf1)
  
list1
[[1]]
[1] "giacomo"  "giovanni" "karolyn" 

[[2]]
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

[[3]]
  ParticipantID Age  Nation EmpathyS
1         Subj1  67 Italian       83
2         Subj2  45  German       56
3         Subj3  23  French       65
4         Subj4  65 Italian       74
5         Subj5  54  German       80
#View(list1)
#str(list1)

#list1[[1]]
#list1[[2]]
#list1[[3]]

Exercise: Create a list containing list1 and another element of your choice (a vector, a matrix, a data.frame)!