投资学第一次实验材料

张剑

2020/05/14

Categories: 投资学 Tags: 实验课

第一次实验内容

实验概述

使用R软件,运用NPV和IRR判定法则,完成对一项车位投资决策的方案的选择。通过实验,加深学生对于金融现金流、货币时间价值、投资决策判定法则的理解。

实验内容

  1. 了解R语言中变量、数值型变量、逻辑型变量、字符型变量的界定与运算。
  2. 了解R语言中列表、数据框及数据框切片与子集选择等概念界定与实际操作。
  3. 重点了解tidyverse系列包在数据处理中的运用。
  4. 运用所学知识解决实际投资决策问题

实验工具R(tidyverse,jrvFinance)

实验过程

  1. 结合老师给出的脚本,对基本数据操作进行了解,同时完成相关问题
  2. 综合运用数据分析工具和投资决策原则,对不同车位购买方案进行计算,并给出相关结论。

R语言包的运用

R语言的强大之处,在于它可以“即插即用”课中安装包,目前CRAN平台收录了近14000个包。

包的安装使用 install.packages(“包的名字”)这样的方法进行

如安装tidyverse包,可以使用install.packages(‘tidyverse’)这样的命令进行安装


数据类型

1. 数值型

数值型非常简单,就是我们日常说的数字,如12345,我们可以利用typeof()函数对数值型变量进行审视

a <- 1234
typeof(a)
## [1] "double"

2.逻辑型

逻辑型数据只有两种类型,真(TRUE)和假(FALSE),这两个字符是R语言的保留字符,同时可以简写为T和F

b <- F
typeof(b)
## [1] "logical"

3.字符型

字符型数据也就是字符串,文本格式的数据都是这类型的数据,如“四川农业大学”

text <- "四川农业大学经济学院"
typeof(text)
## [1] "character"

4.因子型

因子数据是R语言的特殊数据类型,它代表字符串和数字的的映射关系。

sex <- c("男","女")
sex_f <- as.factor(sex)
sex_f
## [1] 男 女
## Levels: 男 女
is.factor(sex_f)
## [1] TRUE

数据结构

数组

数组是有序的原始序列,可以存储多个同类型的数据。下面是一维数组的例子:

vec1 <- c(1,2,3)
vec1
## [1] 1 2 3
class(vec1)
## [1] "numeric"
cha_vec <- c("a","b","c")
cha_vec
## [1] "a" "b" "c"
class(cha_vec)
## [1] "character"

矩阵被称为二阶数组,包含了行和列两部分,不过矩阵内所有的元素都一种类型。在R中可以很方便的使用matrix()函数创建矩阵

m1 <- matrix(c(1,2,3,4,5,6),nrow=2)
m1
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
m2 <- matrix(c(1,2,3,4,5,6),nrow=2,byrow = T)
m2
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
args(matrix)
## function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) 
## NULL

三阶或以上的数组,可以简单的理解为n维数组,很难在平面上展示n维数据。在R中需要使用array()定义高纬数,可以用?array查看帮助

array3 <- array(1:27,dim=c(3,3,3))
array3
## , , 1
## 
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
## 
## , , 2
## 
##      [,1] [,2] [,3]
## [1,]   10   13   16
## [2,]   11   14   17
## [3,]   12   15   18
## 
## , , 3
## 
##      [,1] [,2] [,3]
## [1,]   19   22   25
## [2,]   20   23   26
## [3,]   21   24   27
class(array3)
## [1] "array"

列表

列表是一个非常有特色的的数据类型,它有一点类似向量,但是R语言中允许列表存在不同的数据类型,甚至允许放入不同的数据结构,比如我们可以在一个列表中放入一个向量和一个矩阵。在R中可以使用list函数来定义一个列表。

一个形象的比喻列表就像一列火车,里面什么都可以装,什么时候用,什么时候拿出来非常灵活。

mix_list <- list(m1,cha_vec,array3)
mix_list
## [[1]]
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
## 
## [[2]]
## [1] "a" "b" "c"
## 
## [[3]]
## , , 1
## 
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
## 
## , , 2
## 
##      [,1] [,2] [,3]
## [1,]   10   13   16
## [2,]   11   14   17
## [3,]   12   15   18
## 
## , , 3
## 
##      [,1] [,2] [,3]
## [1,]   19   22   25
## [2,]   20   23   26
## [3,]   21   24   27

数据框

数据框是R中最重要的数据类型,也是我们接触到的最多的数据类型,大多数时候我们研究的数据都是以数据框的形式出现的。数据框也是由行和列组成,看起来和矩阵比较类似。

但是数据框的每一列都是一个数组,可以将其看成是由不同的素组组合而成;它的每一行可以看做一个列表,存放这不同的类型。列是数组,行是列表。看一个例子

head(iris)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa

我们可以使用str()函数参考数据框结构

str(iris)
## 'data.frame':    150 obs. of  5 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

我们可以看到,最后一列Species是因子型的数据,其他列都是数值型的数据。需要注意的是数据框一般都包含表头,它提供了关于该数据框的信息,如最后一列的名称为Species,可以知道这一列是关于物种类型的数据。

第一个小练习

1.创建一个字符变量,存储你的姓名。
2. 创建一个数值变量,存储你的身高(cm),同时创建一个数值变量存储体重(kg)
3. 创建一个一维数组(向量)存储你和你最好朋友的身高。
4. 随意创建一个4*4的矩阵
5. 尝试创建一个5维数组,使用array函数
6. 尝试创建一个列表,第一个元素存储之前创建的你和你最好朋友的身高数组。第二个列表元素,存储你和她(他)的名字的数组。
7. 观察一下R自带的airquality,和mtcars数据框,回答mtcars数据有多少列,多少行,其中是否存在因子类型的列


R中的程序控制

分支结构

所谓分支结构,就是在运行之前,需要对条件是否满足进行判断,如果符合条件,那么继续运行,否则就跳过。分支结构可以用if语句进行控制,举一个最简单的例子。

x <- 0
y <- 2
if(x>1) {
  y <- 2.5
  print(x)
} else {
  y <- -y
}

请大家思考一下,这样的表述后y是多少?

x <- c(0.05, 0.6, 0.3, 0.9)
for(i in seq(along=x)){
  if(x[i] <= 0.2){
    cat("Small\n")
  } else if(x[i] <= 0.8){
    cat("Medium\n")
  } else {
    cat("Large\n")
  }
}
## Small
## Medium
## Medium
## Large

ifelse函数

函数ifelse()可以根据一个逻辑向量中的多个条件, 分别选择不同结果。如

x <- c(-2, 0, 1)
y <- ifelse(x >=0, 1, 0)
print(y)
## [1] 0 1 1

循环结构

循环结构就是要枚举所有可能的情况,并进行一次遍历,在R中使用循环的方法有两种,一种是使用for循环,从而遍历所有内容;另一种是用while循环,只要满足条件就一直执行,直到条件不满足

sum <- 0
for ( i in 1:5) {
  sum = sum + i 
  print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

请大家思考如果我打印sum等于多少?

i <- 0
while (i<3) {
  i = i + 1
  print(i)
}
## [1] 1
## [1] 2
## [1] 3
# 牛顿法解x^3=100
x0 <- Inf
x1 <- 1 # 初始值
while (abs(x1-x0)>0.00001){
  x0 = x1
  y = x0^3
  dy = 3*x0^2
  x1 = x0 + (100 - y)/dy #向答案收敛
    print(x1)
}
## [1] 34
## [1] 22.6955
## [1] 15.19505
## [1] 10.2744
## [1] 7.165367
## [1] 5.426146
## [1] 4.749559
## [1] 4.644025
## [1] 4.64159
## [1] 4.641589

函数式编程

函数就是一个封装好的程序,通过定义和运用,反复实现同一功能。R非常强调函数式编程。很多时候我们对一些内部函数的细节不需要进行细致的把握,只需要知道它是用来完成上面功能就可以了,我们可以不断地使用别人的包,调用别人写好的函数,实现自己需要的功能。在R中使用function定义一个函数,我们之前在债券课程中已经给大家展示了如何写函数。

函数名 <- function(形式参数表) 函数体

函数体是一个表达式或复合表达式(复合语句), 以复合表达式中最后一个表达式为返回值, 也可以用return(x)返回x的值。 如果函数需要返回多个结果, 可以打包在一个列表(list)中返回。 形式参数表相当于函数自变量,可以是空的, 形式参数可以有缺省值, R的函数在调用时都可以用“形式参数名=实际参数”的格式输入自变量值。

sq_sum <- function(x,y){
  x^2 + y^2
}
sq_sum(5,3)
## [1] 34

稍微复杂一点的例子

f <- function() {
  x <- seq(0, 2*pi, length=50)
  y1 <- sin(x)
  y2 <- cos(x)
  plot(x, y1, type="l", lwd=2, col="red",
       xlab="x", ylab="")
  lines(x, y2, lwd=2, col="blue")
  abline(h=0, col="gray")
}
f()

第二个小练习

写一个分支结构命令,进行如下判断:对之前自己建立的体重变量进行判断,当体重大于80kg,打印”注意控制体重“;当体重低于40kg,返回“你的体重偏轻”,当体重在40-80kg之间,打印”继续保持“

用for循环,计算100!(100的阶乘)

向量索引

R最基本的列向量索引是从1开始的.

a <- c(seq(2,6))
a
## [1] 2 3 4 5 6
a[1]
## [1] 2
a[2:4]
## [1] 3 4 5
a[-1]
## [1] 3 4 5 6
a[c(1,3,5)]
## [1] 2 4 6

同样我们之前介绍了逻辑变量,我们也可以使用逻辑判断来对向量中的元素进行索引

a[c(T,F,F,T,T)]
## [1] 2 5 6
# 我们也可以修改a向量中的某个位置的元素
a[2] <- 0
a
## [1] 2 0 4 5 6
a[2:4] <- c(0,0,1)
a
## [1] 2 0 0 1 6
#我也可以用逻辑判断批量修改a中的元素

a[a==0] <- 100

大家可以思考一下,执行完上面最后一行,a变成什么样子了?

我们还可以做更为复杂的操作

v1 <- c(0.1,1,2,3,4)
v1[v1^2-v1>=0]
## [1] 1 2 3 4

数值向量的算术运算

数值向量的算术运算很简单,主要遵循两个原则:对相应位置的元素进行计算,并自动循环利用较短的向量(循环补齐功能)。

c(1,2,3,4)+1
## [1] 2 3 4 5
c(1,2,3,4) - c(2,3,4,1)
## [1] -1 -1 -1  3
c(1,2,3) *c(2,3,4)
## [1]  2  6 12
c(1,2,3)/c(2,3,4)
## [1] 0.5000000 0.6666667 0.7500000
c(1,2,3) ^2
## [1] 1 4 9
c(1,2,3)^ c(1,2,3)
## [1]  1  4 27
c(1,2,3,14) %% 2
## [1] 1 0 1 0

矩阵索引(矩阵子集)

矩阵进行索引时,第一个参数是行(row),第二个参数是列(column)

m1 <- matrix(1:9,nrow=3)
m1
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
# 选择第1列第2行的单个元素
m1[2,1]
## [1] 2
# 也可以选很多
m1[2:3,2:3]
##      [,1] [,2]
## [1,]    5    8
## [2,]    6    9
m1[1,] #第一行
## [1] 1 4 7
m1[,2] #第二列
## [1] 4 5 6
m1[,1:2]
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6
m1[,-3]
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6
m1 > 3
##       [,1] [,2] [,3]
## [1,] FALSE TRUE TRUE
## [2,] FALSE TRUE TRUE
## [3,] FALSE TRUE TRUE
m1[m1>3]
## [1] 4 5 6 7 8 9
class(m1[m1>3])
## [1] "integer"

矩阵运算

需要注意的是矩阵的乘法 %*%

m1 + m1
##      [,1] [,2] [,3]
## [1,]    2    8   14
## [2,]    4   10   16
## [3,]    6   12   18
m1 - 2*m1
##      [,1] [,2] [,3]
## [1,]   -1   -4   -7
## [2,]   -2   -5   -8
## [3,]   -3   -6   -9
m1 *m1
##      [,1] [,2] [,3]
## [1,]    1   16   49
## [2,]    4   25   64
## [3,]    9   36   81
m1 %*% m1
##      [,1] [,2] [,3]
## [1,]   30   66  102
## [2,]   36   81  126
## [3,]   42   96  150
m1 ^2
##      [,1] [,2] [,3]
## [1,]    1   16   49
## [2,]    4   25   64
## [3,]    9   36   81
m1/m1
##      [,1] [,2] [,3]
## [1,]    1    1    1
## [2,]    1    1    1
## [3,]    1    1    1
#矩阵的转置我们可以使用t()函数进行
t(m1)
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9

数组和矩阵的合并

a <- c(1,2,3,4)
b <- c(5,6,7,8)
cbind(a,b)  # 列合并
##      a b
## [1,] 1 5
## [2,] 2 6
## [3,] 3 7
## [4,] 4 8
rbind(a,b) # 行合并
##   [,1] [,2] [,3] [,4]
## a    1    2    3    4
## b    5    6    7    8

矩阵也可以进行行与列的合并

mm1 <- matrix(seq.int(2,24,2),nrow = 3)
cbind(mm1 ,m1)
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,]    2    8   14   20    1    4    7
## [2,]    4   10   16   22    2    5    8
## [3,]    6   12   18   24    3    6    9

第三个小练习

  1. 如何快速创建一个包含0,0.25,0.5,0.75,1,1.25,1.5,1.75,2的向量
  1. 了解diag函数的参数与作用,使用序列10到0到10(即10,9,…,0,1,2,…,10),创建一个21*21的矩阵

实验课最终两道题目

第一题,假设张老师要买车位,计算三种购车不同年限方案的融资成本(年化利率IRR),给出综合分析。