Sometimes, we will be carrying out some set of operations repetitively each time with a new set of inputs. In such cases, it is easier if we can create a function that can take the inputs and perform the set of operations, thus removing the need for us to code the steps each time the operation is performed. Below is a simple example of a function
\[f(x) = x + x^3 \]
The way to create this function in R is as follows
f<- function(x){
print(x+x^3)
}
If we run the above lines of code, the function has only been defined. Here is how we would then call and use it.
print(f(3))
## [1] 30
## [1] 30
y<-f(5) + f(4)
## [1] 130
## [1] 68
print(y)
## [1] 198
An interesting question here is what would happen if I were to supply a vector or a matrix as an input to this function.
v<-c(2,3,4)
f(v)
## [1] 10 30 68
A<- cbind(c(1,2), c(3,4))
f(A)
## [,1] [,2]
## [1,] 2 30
## [2,] 10 68
We can see that the function has been applied to each value in the vector or the matrix. As we become more familiar with R, we will know to expect this. In R using a function just reduces our effort of typing all the statements again and again. Calling the function is equivalent to just typing out the set of commands that are within the definition of the function. From our understanding of basic operations, we know that applying for example a “to the power 2” operation on a vector or matrix of numbers just applies the operation element-wise and then adding will do element-wise addition.
Let us now write a function to compute the maturity value of a bond with face value \(V\), a compound interest rate of \(r\) and term \(T\).
maturity_value<- function(V, r, T){
maturity<- V* (1+r)^T
print(maturity)
}
maturity_value(100, .1, 10)
## [1] 259.3742
Suppose we have a set of instruments with different parameter values for (face value, interest rate, term), then we could very easily apply the function with each vector as an input, knowing that the function will be applied elementwise.
maturity_value(c(100,200,300), c(.1,.2,.05), c(5,10,20))
## [1] 161.0510 1238.3473 795.9893
We can easily check that what the function is doing is to compute elementwise.
maturity_value(100,.1,5)
## [1] 161.051
maturity_value(200,.2,10)
## [1] 1238.347
maturity_value(5,.05,20)
## [1] 13.26649
What if I want to compute for all combinations of face value, interest rate and terms. Well! then we just need to supply the input accordingly. We need to create a cartesian product of the inputs and then call the function.
Vlist<- c(100,200,300)
rlist<- c(0.1, 0.2, 0.05)
Tlist<- c(5,10,20)
VrT<-expand.grid(Vlist, rlist, Tlist)
out<-maturity_value(VrT[,1], VrT[,2], VrT[,3])
## [1] 161.0510 322.1020 483.1530 248.8320 497.6640 746.4960
## [7] 127.6282 255.2563 382.8845 259.3742 518.7485 778.1227
## [13] 619.1736 1238.3473 1857.5209 162.8895 325.7789 488.6684
## [19] 672.7500 1345.5000 2018.2500 3833.7600 7667.5200 11501.2800
## [25] 265.3298 530.6595 795.9893
data.frame(Value=VrT[,1], Interest_rate=VrT[,2], Term=VrT[,3], Maturity=out)
## Value Interest_rate Term Maturity
## 1 100 0.10 5 161.0510
## 2 200 0.10 5 322.1020
## 3 300 0.10 5 483.1530
## 4 100 0.20 5 248.8320
## 5 200 0.20 5 497.6640
## 6 300 0.20 5 746.4960
## 7 100 0.05 5 127.6282
## 8 200 0.05 5 255.2563
## 9 300 0.05 5 382.8845
## 10 100 0.10 10 259.3742
## 11 200 0.10 10 518.7485
## 12 300 0.10 10 778.1227
## 13 100 0.20 10 619.1736
## 14 200 0.20 10 1238.3473
## 15 300 0.20 10 1857.5209
## 16 100 0.05 10 162.8895
## 17 200 0.05 10 325.7789
## 18 300 0.05 10 488.6684
## 19 100 0.10 20 672.7500
## 20 200 0.10 20 1345.5000
## 21 300 0.10 20 2018.2500
## 22 100 0.20 20 3833.7600
## 23 200 0.20 20 7667.5200
## 24 300 0.20 20 11501.2800
## 25 100 0.05 20 265.3298
## 26 200 0.05 20 530.6595
## 27 300 0.05 20 795.9893
A function can also return a list of quantities. A list unlike a vector can contain objects of different type, for example it can contain a number, a vector, a name and matrix as four different entries. Below is an example of a list and how to access elements of a list.
A<- rbind(data.frame(name="Tom", age="5"), data.frame(name="Jill", age="10"))
print(A)
## name age
## 1 Tom 5
## 2 Jill 10
# list with a string , a number and a matrix as its entries
L<- list( name="Sam", number_of_children=2, kid_details=A)
##To access name
L$name
## [1] "Sam"
## or
L[[1]]
## [1] "Sam"
## To access number of children
L[[2]]
## [1] 2
## TO access second kinds details
L[[3]][2,]
## name age
## 2 Jill 10
## or
L$kid_details[2,]
## name age
## 2 Jill 10
Finally let us take an example to show how afunction can output a list. Given a vector of inputs for face-value, interest rate and term, let us write a function to evaluate and output the maturity value for all combinations of inputs, as well as output the raw inputs.
maturity_value<- function(Vlist, rlist, Tlist){
VrT<- expand.grid(Vlist, rlist, Tlist)
V<-VrT[,1]
r<-VrT[,2]
T<-VrT[,3]
out<- V* (1+r)^T
list(Vlist, rlist, Tlist, data.frame(Value=VrT[,1], Interest_rate=VrT[,2], Term=VrT[,3], Maturity=out))
}
out<-maturity_value(c(100,200), c(.1,.2,.3), Tlist=c(10))
out
## [[1]]
## [1] 100 200
##
## [[2]]
## [1] 0.1 0.2 0.3
##
## [[3]]
## [1] 10
##
## [[4]]
## Value Interest_rate Term Maturity
## 1 100 0.1 10 259.3742
## 2 200 0.1 10 518.7485
## 3 100 0.2 10 619.1736
## 4 200 0.2 10 1238.3473
## 5 100 0.3 10 1378.5849
## 6 200 0.3 10 2757.1698
out[[4]]
## Value Interest_rate Term Maturity
## 1 100 0.1 10 259.3742
## 2 200 0.1 10 518.7485
## 3 100 0.2 10 619.1736
## 4 200 0.2 10 1238.3473
## 5 100 0.3 10 1378.5849
## 6 200 0.3 10 2757.1698