1 + 4[1] 5
Basic Operations with R
Boolean Operation
Vectors, Matrices, Lists, and Data Frames
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).
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
# 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
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!
7 + 7[1] 14
140/9[1] 15.55556
82 + 79 + 29[1] 190
82 + 2 * 6[1] 94
(82 + 2)*6[1] 504
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 environmentVariables/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”, “_”
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
italyPop<-59 ### mln of hinabitants
germanyPop<- 68 ### mln of hinabitants
italyWater<- 1.24 ### % of water
germanyWater<-1.27 ### % of waterGiven 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
R manipulates data structures. The main data structures are:
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
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
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"
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
Create:
a vector with numeric values (tell where they are or not integers)
a vector with logicals
a vector with characters
a factor vector (e.g. think about a real variable you could potentially find in a dataset)
a vector with numeric/double and missing values
A vector of numbers from 5 to 15
A vector of number from 100, 200,300,… to 1000 using the function seq
A vector repeating the sequence (2,3,4) by 7 times (use the function rep)
Verify the type of each vector using the functions “typeof”
Verify the length of each vector
Verify where is the missing value in the vector n.5
Sum the elements within the vector n.5
Without running the functions, predict the output of the following vectors, based on the “implicit coercion” rules we mentioned above:
c(2.3,2.0,“females”, NA)
c(1,2,3, TRUE)
c(1.0,9.0,NA)
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 columnsI 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
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).
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
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 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.
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)!