2 Mathematics


2.1 Objects

Vectors are probably your most common mathematical objects, which nest scalars as a special case.

Scalars.

Make your first scalar

Code
xs <- 2 # Make your first scalar
xs  # Print the scalar
## [1] 2

Perform simple calculations

Code
(xs+1)^2 # Perform and print a simple calculation
## [1] 9
xs + NA # often used for missing values
## [1] NA
xs*2
## [1] 4

Vectors.

Make Your First Vector

Code
x <- c(0,1,3,10,6) # Your First Vector
x # Print the vector
## [1]  0  1  3 10  6
x[2] # Print the 2nd Element; 1
## [1] 1
x+2 # Print simple calculation; 2,3,5,8,12
## [1]  2  3  5 12  8
x*2
## [1]  0  2  6 20 12
x^2
## [1]   0   1   9 100  36

Apply Mathematical calculations “elementwise”

Code
x+x
## [1]  0  2  6 20 12
x*x
## [1]   0   1   9 100  36
x^x
## [1] 1.0000e+00 1.0000e+00 2.7000e+01 1.0000e+10 4.6656e+04

See that scalars are vectors

Code
c(1)
## [1] 1

1:7
## [1] 1 2 3 4 5 6 7
seq(0,1,by=.1)
##  [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0

Matrices.

Matrices are also common objects

Code
x1 <- c(1,4,9)
x2 <- c(3,0,2)
x_mat <- rbind(x1, x2)

x_mat       # Print full matrix
##    [,1] [,2] [,3]
## x1    1    4    9
## x2    3    0    2
x_mat[2,]   # Print Second Row
## [1] 3 0 2
x_mat[,2]   # Print Second Column
## x1 x2 
##  4  0
x_mat[2,2]  # Print Element in Second Column and Second Row
## x2 
##  0

There are elementwise calculations

Code
x_mat+2
##    [,1] [,2] [,3]
## x1    3    6   11
## x2    5    2    4
x_mat*2
##    [,1] [,2] [,3]
## x1    2    8   18
## x2    6    0    4
x_mat^2
##    [,1] [,2] [,3]
## x1    1   16   81
## x2    9    0    4

x_mat + x_mat
##    [,1] [,2] [,3]
## x1    2    8   18
## x2    6    0    4
x_mat*x_mat
##    [,1] [,2] [,3]
## x1    1   16   81
## x2    9    0    4
x_mat^x_mat
##    [,1] [,2]      [,3]
## x1    1  256 387420489
## x2   27    1         4

And you can also use matrix algebra

Code
x_mat1 <- matrix(2:7,2,3)
x_mat1
##      [,1] [,2] [,3]
## [1,]    2    4    6
## [2,]    3    5    7

x_mat2 <- matrix(4:-1,2,3)
x_mat2
##      [,1] [,2] [,3]
## [1,]    4    2    0
## [2,]    3    1   -1

tcrossprod(x_mat1, x_mat2) #x_mat1 %*% t(x_mat2)
##      [,1] [,2]
## [1,]   16    4
## [2,]   22    7

crossprod(x_mat1, x_mat2)
##      [,1] [,2] [,3]
## [1,]   17    7   -3
## [2,]   31   13   -5
## [3,]   45   19   -7
# x_mat1 * x_mat2

2.2 Functions

Functions are applied to objects

Code
# Define a function that adds two to any vector
add_2 <- function(input_vector) {
    output_vector <- input_vector + 2 # new object defined locally 
    return(output_vector) # return new object 
}
# Apply that function to a vector
x <- c(0,1,3,10,6)
add_2(x)
## [1]  2  3  5 12  8

# notice 'output_vector' is not available here

There are many many generalizations

Code
add_vec <- function(input_vector1, input_vector2) {
    output_vector <- input_vector1 + input_vector2
    return(output_vector)
}
add_vec(x,3)
## [1]  3  4  6 13  9
add_vec(x,x)
## [1]  0  2  6 20 12

sum_squared <- function(x1, x2) {
    y <- (x1 + x2)^2
    return(y)
}

sum_squared(1, 3)
## [1] 16
sum_squared(x, 2)
## [1]   4   9  25 144  64
sum_squared(x, NA) 
## [1] NA NA NA NA NA
sum_squared(x, x)
## [1]   0   4  36 400 144
sum_squared(x, 2*x)
## [1]   0   9  81 900 324

Functions can take functions as arguments

Code
fun_of_seq <- function(f){
    x <- seq(1,3, length.out=12)
    y <- f(x)
    return(y)
}

fun_of_seq(mean)
## [1] 2

fun_of_seq(sd)
## [1] 0.6555548

You can apply functions to matrices

Code
sum_squared(x_mat, x_mat)
##    [,1] [,2] [,3]
## x1    4   64  324
## x2   36    0   16

# Apply function to each matrix row
y <- apply(x_mat, 1, sum)^2 
# ?apply  #checks the function details
y - sum_squared(x, x) # tests if there are any differences
## [1]  196   21  160 -375   52

There are many possible functions you can apply

Code
# Return Y-value with minimum absolute difference from 3
abs_diff_y <- abs( y - 3 ) 
abs_diff_y # is this the luckiest number?
##  x1  x2 
## 193  22

#min(abs_diff_y)
#which.min(abs_diff_y)
y[ which.min(abs_diff_y) ]
## x2 
## 25

There are also some useful built in functions

Code
m <- matrix(c(1:3,2*(1:3)),byrow=TRUE,ncol=3)
m
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    2    4    6

# normalize rows
m/rowSums(m)
##           [,1]      [,2] [,3]
## [1,] 0.1666667 0.3333333  0.5
## [2,] 0.1666667 0.3333333  0.5

# normalize columns
t(t(m)/colSums(m))
##           [,1]      [,2]      [,3]
## [1,] 0.3333333 0.3333333 0.3333333
## [2,] 0.6666667 0.6666667 0.6666667

# de-mean rows
sweep(m,1,rowMeans(m), '-')
##      [,1] [,2] [,3]
## [1,]   -1    0    1
## [2,]   -2    0    2

# de-mean columns
sweep(m,2,colMeans(m), '-')
##      [,1] [,2] [,3]
## [1,] -0.5   -1 -1.5
## [2,]  0.5    1  1.5

Loops.

Applying the same function over and over again

Code
exp_vector <- vector(length=3)
for(i in 1:3){
    exp_vector[i] <- exp(i)
}

# Compare
exp_vector
## [1]  2.718282  7.389056 20.085537
c( exp(1), exp(2), exp(3))
## [1]  2.718282  7.389056 20.085537

store complicated example

Code
complicate_fun <- function(i, j=0){
    x <- i^(i-1)
    y <- x + mean( j:i )
    z <- log(y)/i
    return(z)
}
complicated_vector <- vector(length=10)
for(i in 1:10){
    complicated_vector[i] <- complicate_fun(i)
}

recursive loop

Code
x <- vector(length=4)
x[1] <- 1
for(i in 2:4){
    x[i] <- (x[i-1]+1)^2
}
x
## [1]   1   4  25 676

Logic.

Basic Logic

Code
x <- c(1,2,3,NA)
x > 2
## [1] FALSE FALSE  TRUE    NA
x==2
## [1] FALSE  TRUE FALSE    NA

any(x==2)
## [1] TRUE
all(x==2)
## [1] FALSE
2 %in% x
## [1] TRUE

is.numeric(x)
## [1] TRUE
is.na(x)
## [1] FALSE FALSE FALSE  TRUE

The “&” and “|” commands are logical calculations that compare vectors to the left and right.

Code
x <- 1:3
is.numeric(x) & (x < 2)
## [1]  TRUE FALSE FALSE
is.numeric(x) | (x < 2)
## [1] TRUE TRUE TRUE

if(length(x) >= 5 & x[5] > 12) print("ok")

Advanced Logic.

Code
x <- 1:10
cut(x, 4)
##  [1] (0.991,3.25] (0.991,3.25] (0.991,3.25] (3.25,5.5]   (3.25,5.5]  
##  [6] (5.5,7.75]   (5.5,7.75]   (7.75,10]    (7.75,10]    (7.75,10]   
## Levels: (0.991,3.25] (3.25,5.5] (5.5,7.75] (7.75,10]
split(x, cut(x, 4))
## $`(0.991,3.25]`
## [1] 1 2 3
## 
## $`(3.25,5.5]`
## [1] 4 5
## 
## $`(5.5,7.75]`
## [1] 6 7
## 
## $`(7.75,10]`
## [1]  8  9 10
Code
xs <- split(x, cut(x, 4))
sapply(xs, mean)
## (0.991,3.25]   (3.25,5.5]   (5.5,7.75]    (7.75,10] 
##          2.0          4.5          6.5          9.0

# shortcut
aggregate(x, list(cut(x,4)), mean)
##        Group.1   x
## 1 (0.991,3.25] 2.0
## 2   (3.25,5.5] 4.5
## 3   (5.5,7.75] 6.5
## 4    (7.75,10] 9.0

see https://bookdown.org/rwnahhas/IntroToR/logical.html

2.3 Arrays

Arrays are generalization of matrices. They are often used in spatial econometrics, and are a very efficient way to store numeric data with the same dimensions.

Code
a <- array(data = 1:24, dim = c(2, 3, 4))
Code
a

a[1, , , drop = FALSE]  # Row 1
#a[, 1, , drop = FALSE]  # Column 1
#a[, , 1, drop = FALSE]  # Layer 1

a[ 1, 1,  ]  # Row 1, column 1
#a[ 1,  , 1]  # Row 1, "layer" 1
#a[  , 1, 1]  # Column 1, "layer" 1
a[1 , 1, 1]  # Row 1, column 1, "layer" 1

Apply extends to arrays

Code
apply(a, 1, mean)    # Row means
## [1] 12 13
apply(a, 2, mean)    # Column means
## [1] 10.5 12.5 14.5
apply(a, 3, mean)    # "Layer" means
## [1]  3.5  9.5 15.5 21.5
apply(a, 1:2, mean)  # Row/Column combination 
##      [,1] [,2] [,3]
## [1,]   10   12   14
## [2,]   11   13   15

Outer products yield arrays

Code
x <- c(1,2,3)
x_mat1 <- outer(x, x) # x %o% x
x_mat1
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    2    4    6
## [3,]    3    6    9
is.array(x_mat) # Matrices are arrays
## [1] TRUE

x_mat2 <- matrix(6:1,2,3)
outer(x_mat2, x)
## , , 1
## 
##      [,1] [,2] [,3]
## [1,]    6    4    2
## [2,]    5    3    1
## 
## , , 2
## 
##      [,1] [,2] [,3]
## [1,]   12    8    4
## [2,]   10    6    2
## 
## , , 3
## 
##      [,1] [,2] [,3]
## [1,]   18   12    6
## [2,]   15    9    3
# outer(x_mat2, matrix(x))
# outer(x_mat2, t(x))
# outer(x_mat1, x_mat2)