第1章 R语言入门
在本章,我们将讨论R语言的基础概念,这是学习本书其他章节的基础,但我们并不会深入讨论关于R的每个概念。本章的目标读者是那些并不了解R语言、想要在量化金融领域寻求职业机会或者应用R语言进行量化金融分析的初学者。本章会教你开始用R编写程序的基础知识,但假如你想要编写更加复杂的程序,则需要查看其他相关书籍。
本章包括以下内容。
- 为什么要用R
- 如何下载并安装R软件
- 如何安装R程序包
- 数据类型
- 导入和输出不同类型的数据
- 如何编写R表达式
- 函数
- 如何执行R程序
- 循环与条件语句
1.1 为什么要用R
许多统计软件都可以用来解决量化金融问题,但R本质上不是一个统计软件包,而是一种灵活且强大的语言,我们可用R来完成高质量的分析工作。
想要用R,人们无需成为专业编程人员或计算机专家。了解基础的编程知识对学习R当然有所助益,但这并不是先决条件。
R的绘图功能少有匹敌,这是R语言的一个突出的优点。
R语言的另一个优点在于它有着众多的扩展程序包。对于任何一个统计概念,在R中很有可能已经存在对应的程序包。R有许多专门用来进行统计和量化金融分析的工具。
R具备扩展性,提供很多功能来帮助量化金融领域的开发者编写解决分析性问题的工具或方法。当学术界有新的研究发表时,可能就会出现新的相关程序包。R的开发社区非常活跃且易于接近,人们热衷于为各种新概念开发出新的程序包。这都使得R和量化金融领域出现的前沿概念能保持同步。
R生来就是为了处理数据,但在它诞生之时,并不存在所谓的大数据。处理大数据带来的额外挑战包括数据多样化(如文本数据、测量数据等)、数据安全、存储器、CPU I/O RSC要求、多机处理等。R中用来应对大数据挑战的相关技术包括映射-归约(map-reducing)、内存中处理、流数据处理、降频采样(down sampling)、分块处理(chunking)等。
总之,R是免费软件,有着优秀的数据处理和制图功能,在网上存在海量的关于R程序包的帮助文档或技术文档。因此,R是高效且容易学习的工具。对于那些想要在量化金融领域寻求职业机会的人们来说,学习R是时代的需求。
1.2 下载并安装R软件
在本节中,我们将讨论如何为不同的操作系统(Windows、Linux和Mac)下载并安装R软件。
打开网页浏览器,登录R官网,你可以基于不同的操作系统下载相应版本的R。
对于Windows版本,依次点击Download R for Windows链接、base链接和Download R 3.#.# for Windows链接,从而给你的Windows操作系统下载相应版本的R。双击打开下载的安装包,选择你偏好的语言选项,接下来的安装步骤依次如下。
1.安装向导。
2.许可协议。
3.选定你打算安装到的目标文件夹。
4.选择安装组件。基于你的系统设置相应选项,如果你不知道系统设置,则选择全部选项。
5.如果你想要自定义安装,则点击选项(option)按钮。
6.根据你的需要选择R的运行选项和桌面快捷方式选项。
至此完成Windows环境下R软件的下载和安装。
类似地,你也可以在Linux和Mac操作环境下下载相应的安装程序,然后循序完成不同的安装选项设置,直至完成安装。
1.3 安装R程序包
程序包(package)由R函数、编译代码和示例数据集等组成,它们的存储目录被称作程序库(library)。R会默认安装一组程序包,如果你要使用其他程序包则必须自行添加。
我们使用如下代码来检测系统中存在哪些R程序包:
.libPaths()
用上面的命令来获得或设定R程序库的路径,它会输出类似如下的结果:
## "C:/Program Files/R/R-3.3.1/library"
执行如下代码会列出所有可用的程序包:
library()
存在两种安装新程序包的方法:直接从CRAN安装和手动安装。
1.3.1 直接从CRAN安装
CRAN是“综合性R存档网络(Comprehensive R Archive Network)”的首字母简称,它是由FTP服务器构成的全球网络,而在这些FTP服务器中存储着完全相同的各种版本的R代码和文档。
下面的代码用来直接从CRAN下载并安装R程序包(用户需要选定合适的镜像):
install.packages("包名")
举例说明,如果你要安装ggplot2
包和forecast
包,则代码如下:
install.packages("ggplot2")
install.packages("forecast")
1.3.2 手动安装
手动下载所需的程序包,然后用install.packages()
将程序压缩包解压存入系统中的指定位置(如"/DATA/RPACKAGES/")。譬如,我们想要安装ggplot2
包,则使用如下代码可完成安装并将其加载到R的当前工作环境中(其他程序包也可用类似方法安装):
install.packages("ggplot2", lib = "/data/Rpackages/")
library(ggplot2, lib.loc = "/data/Rpackages/")
1.4 数据类型
在编程语言中,人们需要用不同的变量来存储不同的信息。变量(variable)是用来存储值的内存位置。创建变量就是在内存中预订存储空间。用户可能需要存储不同类型的数据,如字符、浮点数、布尔值等。操作系统根据数据类型分配内存并决定在预订的内存位置存入哪些数据。
你在R中碰到的一切都被称作对象(object)。
R有5种基本的数据对象类型,又称原子对象(atomic object),而其他数据对象都基于原子对象。接下来我们将会给出关于基本对象的一些示例并验证它的类(class)。
- 字符
我们将字符取值赋予一个变量并验证它的类,代码及结果如下:
a <- "hello"
class(a)
## [1] "character"
- 数值
我们将数值赋予一个变量并验证它的类,代码及结果如下:
b <- 2.5
class(b)
## [1] "numeric"
- 整数
我们将整数赋予一个变量并验证它的类,代码及结果如下:
c <- 6L
class(c)
## [1] "integer"
- 复数
我们将复数赋予一个变量并验证它的类,代码及结果如下:
d <- 1 + 2i
class(d)
## [1] "complex"
- 逻辑(TRUE/FALSE)
我们将逻辑取值赋予一个变量并验证它的类,代码及结果如下:
e <- TRUE
class(e)
## [1] "logical"
R中基本的数据类型被称作向量(vector),它由相同类型的对象组成。向量不能同时包含两种不同类型的对象,比如同时包含字符对象和数值对象。但列表(list)是个例外,它可以同时包含多种类型的对象,比如同时包含字符对象、数值对象和列表对象。
接下来我们讨论R中常见的数据类型,并给出相应示例。
1.4.1 向量
前面已经给出向量的定义。如果我们想构建一个包含多个元素的向量,我们可用c()
函数将元素合并成一个向量,如:
a <- "Quantitative"
b <- "Finance"
c(a, b)
## [1] "Quantitative" "Finance"
类似地,
Var <- c(1, 2, 3)
Var
## [1] 1 2 3
1.4.2 列表
列表是一种包含多种类型对象(如向量,甚至列表)的R对象。让我们用如下代码构建一个列表并将其列印出来:
List1 <- list(c(4, 5, 6), "Hello", 24.5)
List1
## [[1]]
## [1] 4 5 6
##
## [[2]]
## [1] "Hello"
##
## [[3]]
## [1] 24.5
我们可根据需要提取列表中的元素,比如提取上述列表List1
中的第二个元素:
List1[2]
## [[1]]
## [1] "Hello"
我们也可用c()
函数将两个列表合并起来,如:
list1 <- list(5, 6, 7)
list2 <- list("a", "b", "c")
Combined_list <- c(list1, list2)
Combined_list
## [[1]]
## [1] 5
##
## [[2]]
## [1] 6
##
## [[3]]
## [1] 7
##
## [[4]]
## [1] "a"
##
## [[5]]
## [1] "b"
##
## [[6]]
## [1] "c"
1.4.3 矩阵
矩阵(matrix)是具有两个维度的矩形数据集,它可通过将向量输入到matrix()
函数中得到。使用如下命令创建一个2行3列的矩阵并将其打印出来:
M <- matrix(c(1, 2, 3, 4, 5, 6), nrow = 2, ncol = 3)
M
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
1.4.4 数组
矩阵只有两个维度,数组(array)则可有着任意的维度。array()
函数有个dim
参数,设定所需的维度。使用如下命令创建一个数组并将其打印出来:
a <- array(1:18, dim = c(3, 3, 2))
a
## , , 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
1.4.5 因子
因子(factor)是由向量构建的R对象,它将向量及其不同元素取值所对应的标签一起存储起来。不管向量是否为数值型、字符型,还是布尔型,标签通常为字符形式。
因子用factor()
函数创建,nlevels()
函数可得到因子水平数,如:
a <- c(2, 3, 4, 2, 3)
fact <- factor(a)
fact
## [1] 2 3 4 2 3
## Levels: 2 3 4
nlevels(fact)
## [1] 3
1.4.6 数据框
数据框(dataframe)是表格形式的数据对象,由相同长度的向量组成,但每个向量可存储不同类型的数据(如数值型、字符型、布尔型等)。
数据框可用data.frame()
函数生成,如:
data <- data.frame(
Name = c("Alex", "John", "Bob"),
Age = c(18, 20, 23),
Gender = c("M", "M", "M")
)
data
## Name Age Gender
## 1 Alex 18 M
## 2 John 20 M
## 3 Bob 23 M
1.5 导入和输出不同类型的数据
在R中,我们可以读入存储在R环境之外的文档,也可以将数据输出到可由操作系统直接读取的文档中。R可读取和存储不同格式的文档(如CSV、Excel、TXT等)。在本节中,我们将讨论如何读取和存储不同格式的文档。
读入或存储文档的第一步就是明确工作目录,代码如下:
getwd()
这会给出你所运行R的当前工作目录。如果这不是你想要的目标目录,则可用setwd()
函数进行设定。比如,如下代码会将目录"C:/Users"设定为R的工作目录:
setwd("C:/Users")
1.5.1 读取和存储CSV格式文档
CSV格式文档是用逗号分隔数据取值的纯文本文档。让我们考虑包含如下股票市场数据内容的CSV文档:
Date,Open,High,Low,Close,Volume,Adj Close
14-10-2016,2139.679932,2149.189941,2132.97998,2132.97998,3228150000,2132.97998
13-10-2016,2130.26001,2138.189941,2114.719971,2132.550049,3580450000,2132.550049
12-10-2016,2137.669922,2145.360107,2132.77002,2139.179932,2977100000,2139.179932
11-10-2016,2161.350098,2161.560059,2128.840088,2136.72998,3438270000,2136.72998
10-10-2016,2160.389893,2169.600098,2160.389893,2163.659912,2916550000,2163.659912
CSV文档名为ch01_sample.csv
,存储在工作目录的子文件夹data
中。在此我们使用相对路径读入上述文档,代码如下:
data <- read.csv("data/ch01_sample.csv")
data
## Date Open High Low Close Volume Adj.Close
## 1 14-10-2016 2140 2149 2133 2133 3.228e+09 2133
## 2 13-10-2016 2130 2138 2115 2133 3.580e+09 2133
## 3 12-10-2016 2138 2145 2133 2139 2.977e+09 2139
## 4 11-10-2016 2161 2162 2129 2137 3.438e+09 2137
## 5 10-10-2016 2160 2170 2160 2164 2.917e+09 2164
read.csv()
函数默认生成数据框,这可通过如下代码进行确认:
is.data.frame(data)
## [1] TRUE
接下来,我们在R中将相应的数据分析函数应用于这个数据框上。一旦完成分析,用户也可用write.csv()
函数将数据输出到目标文件夹的文档中,代码如下(输出结果从略):
write.csv(data, "data/ch01_result.csv", row.names = FALSE)
# 重新读入并列印数据,看看数据输出是否正确
output <- read.csv("data/ch01_result.csv")
output
1.5.2 XLSX文档
Excel文档是最常见的存储数据的文档,扩展名为.xls或.xlsx。xlsx
包可用来在R环境下读取或写入.xlsx文档。安装xlsx
包依赖于Java,所以系统中要安装Java。xlsx
包可用如下命令进行安装:
install.packages("xlsx")
当运行上述命令时,R会询问打算使用的CRAN镜像,用户应选定目标镜像。我们可通过如下命令来验证xlsx
包是否安装成功:
any(grepl("xlsx", installed.packages()))
## [1] TRUE
如果显示结果为[1] TRUE
,则说明该包成功安装。
接着,我们运行如下代码载入xlsx
包:
library("xlsx")
现在让我们在Excel软件中将之前的ch01_sample.csv
文档存储为xlsx格式的文档ch01_sample.xlsx
,然后在R环境中用如下代码读入数据:
data <- read.xlsx("data/ch01_sample.xlsx", sheetIndex = 1)
data
## Date Open High Low Close Volume Adj.Close
## 1 14-10-2016 2140 2149 2133 2133 3.228e+09 2133
## 2 13-10-2016 2130 2138 2115 2133 3.580e+09 2133
## 3 12-10-2016 2138 2145 2133 2139 2.977e+09 2139
## 4 11-10-2016 2161 2162 2129 2137 3.438e+09 2137
## 5 10-10-2016 2160 2170 2160 2164 2.917e+09 2164
类似地,你也可用xlsx
包中的write.xlsx()
将R数据对象直接存储为.xlsx格式的文档(输出结果从略):
write.xlsx(data, "data/ch01_result.xlsx", row.names = FALSE)
# 重新读入并列印数据,看看数据输出是否正确
output <- read.xlsx("data/ch01_result.xlsx", sheetIndex = 1)
output
1.5.3 网络数据或在线数据资源
如今网络是数据的一个主要来源,我们可将网络上的数据直接读入到R环境中,例如:
# URL <- "http://ichart.finance.yahoo.com/table.csv?s=^GSPC"
# snp <- as.data.frame(read.csv(URL))
# head(snp)
# 译者注:书中给出的类似URL已无法使用,
# 作为替代,我们使用quantmod包从Yahoo下载数据
# install.packages("quantmod")
library(quantmod)
snp <- getSymbols(Symbols = "^GSPC", src = "yahoo",
from = "2015-10-15", to = "2016-10-15",
auto.assign = FALSE)
snp <- as.data.frame(snp)
colnames(snp) <- c("Open", "High", "Low", "Close", "Volume", "Adj.Close")
snp$Date <- rownames(snp)
snp <- snp[order(snp$Date, decreasing = TRUE), ]
snp <- snp[c("Date", "Open", "High", "Low", "Close", "Volume", "Adj.Close")]
rownames(snp) <- NULL
head(snp)
## Date Open High Low Close Volume Adj.Close
## 1 2016-10-14 2140 2149 2133 2133 3.228e+09 2133
## 2 2016-10-13 2130 2138 2115 2133 3.580e+09 2133
## 3 2016-10-12 2138 2145 2133 2139 2.977e+09 2139
## 4 2016-10-11 2161 2162 2129 2137 3.438e+09 2137
## 5 2016-10-10 2160 2170 2160 2164 2.917e+09 2164
## 6 2016-10-07 2164 2166 2145 2154 3.620e+09 2154
执行上述代码会从Yahoo Finance下载标普500指数("^GSPC
")的数据,处理为数据框格式,并用head()
函数列示出部分数据。类似地,我们也可通过执行下面的代码下载道琼斯工业指数("^DJI"
)的数据到R环境中:
dji <- getSymbols(
Symbols = "^DJI", src = "yahoo",
from = "2015-10-15", to = "2016-10-15",
auto.assign = FALSE
)
dji <- as.data.frame(dji)
colnames(dji) <- c("Open", "High", "Low", "Close", "Volume", "Adj.Close")
dji$Date <- rownames(dji)
dji <- dji[order(dji$Date, decreasing = TRUE), ]
dji <- dji[c("Date", "Open", "High", "Low", "Close", "Volume", "Adj.Close")]
rownames(dji) <- NULL
head(dji)
## Date Open High Low Close Volume Adj.Close
## 1 2016-10-14 18177 18261 18138 18138 87050000 18138
## 2 2016-10-13 18088 18138 17960 18099 83160000 18099
## 3 2016-10-12 18133 18194 18082 18144 72230000 18144
## 4 2016-10-11 18308 18312 18062 18129 88610000 18129
## 5 2016-10-10 18283 18400 18283 18329 72110000 18329
## 6 2016-10-07 18295 18320 18149 18240 82680000 18240
请注意在本书后面的示例中我们会经常用到snp
和dji
这两个关于股票市场指数的数据集。
1.5.4 数据库
关系型数据库以标准化的格式存储数据,为了进行统计分析,我们需要编写复杂的高级查询指令。但R能连接各种数据库(如MySQL、Oracle、SQL Server等),很容易提取数据表并将其转为数据框格式。一旦数据变为数据框格式,就可以利用R中内置函数和扩展R包对数据进行统计分析。
在本小节中,我们以MySQL数据库为例进行说明。R现有的程序包RMySQL
提供和MySQL数据库的连接。通过如下命令(安装并)加载R数据库接口程序包DBI
包和相应的RMySQL
包:
# install.packages(c("DBI", "RMySQL"))
library(DBI)
library(RMySQL)
安装并载入相应的程序包后,我们就可以创建一个和数据库建立连接的对象。它以用户名、密码、数据库名、本地主机名作为输入,示例如下:
mysqlconnection <- dbConnect( MySQL(), user = "...", password = "...",
dbname = "...", host = "..." )
当创建数据库连接之后,我们可执行下面的命令将该数据库中的表列示出来:
dbListTables(mysqlconnection)
我们可用dbSendQuery()
函数对数据库进行查询,查询结果用fetch()
函数返回给R并存储为数据框:
result <- dbSendQuery(mysqlconnection, "select * from <table name>")
result_df <- fetch(result)
result_df
我们还可以通过dbSendQuery()
函数给数据库发送指令,完成诸如过滤、更新行、插入数据、创建表、删除表等各种操作。
1.6 编写表达式
在本节中,我们先讨论如何编写基础的表达式,这是编写程序的核心要素。接着,我们还会讨论如何编写自定义函数。
1.6.1 表达式
R代码由一个或多个表达式(expression)组成,表达式是指执行特定任务的语句。比如,下面的表达式计算两个数之和:
4 + 5
## [1] 9
如果程序中存在多个表达式,它们会按照出现的顺序逐一执行。
现在,我们讨论几种基本的表达式。
1.常数表达式
最简单的表达式为常数表达式,其取值可为字符型或数值型。比如,100
是数值型常数表达式,"Hello World"是字符型常数表达式。
2.算术表达式
R语言支持标准的算术运算符,其中部分算术运算符如表1-1所示。
表1-1 R支持的部分算术运算符
运算符 | 运算 |
---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ | 除法 |
^ | 乘方 |
使用上述算术运算符,我们可生成算术表达式,示例如下(输出结果从略):
4 + 5
4 - 5
4 * 5
R遵循BODMAS规则,即“先计算括号内的以及先乘除后加减”的运算优先规则。在创建算术表达式时,人们可使用括号来避免歧义。
3.条件表达式
条件表达式对两个取值进行比较并返回逻辑值(TRUE
或FALSE
),R支持标准的比较运算符和条件连接运算符(表1-2)。
表1-2 R支持的比较运算符和条件连接运算符
运算符 | 运算 |
---|---|
== | 等于 |
> (>=) | 大于(大于等于) |
< (<=) | 小于(小于等于) |
!= | 不等于 |
&& | 逻辑和 |
|| | 逻辑或 |
! | 逻辑否 |
比如:10 > 5
,执行后返回TRUE
;5 > 10
,执行后返回FALSE
。
4.函数调用表达式
R中最常见也最有用的表达式是函数调用表达式。R中存在很多内置函数,用户也可以自定义函数。在本小节中,我们说明调用函数的基本结构。
函数调用表达式由函数名、括号以及括号内用逗号分隔的参数构成。参数是给函数执行特定任务时提供必要信息的表达式。在下文讨论如何构建自定义函数时,我们会给出一个函数调用表达式的例子。
1.6.2 符号和赋值
R代码中包含关键词(keyword)和符号(symbol)。
符号是内存中存储对象的标签。当执行程序时,程序会从内存中取得存储对象的取值。R有很多已经预先定义好取值的符号,可在程序中直接调用。比如,letters
是会返回26个小写英文字母的向量。
通过赋值运算符<-
可将表达式的结果赋值给某个符号。比如,value <- 4 + 6
将加法运算的结果10赋值给符号value
并存储在内存中。
1.6.3 关键词
有些符号用来表示某些特殊的取值,这些符号无法被重新赋值,如下所示。
NA
:用来表示缺失值。Inf
:用来表示无穷。比如,1/0
就会返回Inf
。NaN
:用来表示无法定义的算术表达式的结果。比如,0/0
就会返回NaN
。NULL
:用来表示空值。TRUE
和FALSE
:这是布尔逻辑值,通常是比较变量取值的返回值。
1.6.4 变量命名
当编写R代码时,我们需要用很多符号来存储不同的信息。为了让代码更容易理解,我们要尽量给这些符号取有意义的名字。符号命名应该是不言自明的,太短的符号名会使代码更难以理解。
比如,我们可用DateOfBirth
或DOB
来存储生日的信息存储,但显然前者更好,让人更容易理解。
1.7 函数
在本节中,我们将提供关于R中内置函数的若干例子,并编写一个完成特定任务的自定义函数。
函数(function)是为执行特定任务而放在一起的一组语句。R中内置有很多函数,用户也可以自定义函数。在R中,解释器根据要求将控制以及为完成任务而设置的函数参数交给函数对象。在完成任务之后,函数会将控制交还给解释器。
定义函数的语法如下:
function_name <- function(arg1, arg2, ...) {
function_body
}
具体解释如下所示。
- 函数名(function_name):这是函数的名字。定义的函数对象将用该名字存储在内存中。
- 参数(arg1、arg2…):参数是函数完成特定任务所需的信息。参数是可选的。
- 函数体(function_body):函数完成指定任务的一系列语句。
- 返回值:函数的返回值通常为函数体内最后一个表达式的返回值。
这里提供两个内置函数及其返回值的示例:
mean(25:82)
## [1] 53.5
sum(41:68)
## [1] 1526
现在,让我们看看如何自定义函数。我们想要计算并打印出给定整数的平方序列,函数名为findingSqrFunc
,参数为value
:
findingSqrFunc <- function(value) {
for (i in 1:value) {
sqr <- i^2
print(sqr)
}
}
在执行上述代码之后,我们就可以调用该函数:
findingSqrFunc(4)
## [1] 1
## [1] 4
## [1] 9
## [1] 16
1.7.1 调用函数(无需参数)
定义并调用一个无需参数的函数示例如下:
func_wo_args <- function() {
for (i in 1:3) {
print(i * 5)
}
}
func_wo_args()
## [1] 5
## [1] 10
## [1] 15
1.7.2 调用函数(需要参数)
我们可按照定义函数时参数的顺序来给函数传递参数取值。但如果使用参数名,就可以不按顺序来传递参数的取值。下面给出定义并调用函数的示例:
- 定义函数
func_w_args <- function(a, b, c) {
result <- a * b + c
print(result)
}
- 按顺序传递参数取值
func_w_args(2, 3, 4)
## [1] 10
- 用参数名传递参数取值
func_w_args(c = 4, b = 3, a = 4)
## [1] 16
1.8 如何执行R程序
在本节中,我们讨论运行R程序的不同方式。
1.8.1 在R代码窗中运行存盘的脚本文档
遵循如下步骤在R代码窗口中运行程序。
1.打开R软件(双击桌面图标或从开始程序菜单打开)。
2.点击File菜单下的打开脚本(Open Script),然后定位到脚本文档所在的目录。
3.选定并打开你要运行的脚本文档,它会在R编辑器窗口中打开。
4.右键菜单->全选(Select All)(或使用快捷键Ctrl + A)。
5.右键菜单->运行代码行或选定代码(Run LineorSelection)(或使用快捷键Ctrl + R)。
6.程序的运行结果将出现在R控制台窗口中。
1.8.2 加载R脚本文档
如果你想让R无须等待指令而直接执行多行代码,你可以使用source()
函数来加载整个脚本文档,步骤如下。
1.在R编辑器窗口中编写全部代码,然后存盘为目标文件夹下的脚本文档(如"D:/Rcode/first_prog.R"
)。代码示例如下:
a <- 5
print(a)
2.使用绝对路径加载R脚本文档,代码示例如下:
source("D:/Rcode/first_prog.R")
当然,我们也可先用setwd()
函数修改R工作目录再直接加载R脚本文档。加载脚本文档first_prog.R
会在R控制台窗口中输出5。
注释是程序的一部分,但在执行代码时解释器会忽略注释语句。注释用#
加以标注,如:
# 这是程序中的一句注释
1.9 循环与条件
循环(loop)是将需要重复的操作分组并安排执行顺序从而自动执行多步过程的指令。所有的编程语言都有内置的方式来实现重复执行指令或指令块。条件决策也是编程语言的重要构件,在R语言中这通过使用条件语句(conditional statement)if ... else
来实现。
本节先讨论if ... else
条件语句,接着再讨论循环。
1.9.1 if语句
让我们看看if
语句在R中是如何工作的。if
语句的通用语法如下:
if (表达式) {
语句
}
如果表达式成立,就会执行语句,否则就不执行语句。
表达式可以是逻辑或数值向量。当表达式为数值向量时,0被视作FALSE
,其他取值被视为TRUE
。
x <- 5
if (x > 0)
{
print("I am Positive")
}
执行上述代码,R将输出"I am Positive"
。
1.9.2 if … else语句
现在让我们看看if
和else
条件语句在R中是如何工作的。语法如下:
if (表达式) {
语句1
} else {
语句2
}
当if ()
内的表达式为FALSE
时,else
部分的语句2就会被执行,如:
x <- -5
if (x > 0)
{
print("I am Positive")
} else
{
print("I am Negative")
}
执行上述代码,R将输出"I am Negative"
。
1.9.3 for循环
通过计数器或索引,for
循环会重复执行预定的次数,每次循环后计数器或索引会自动增加。for
循环的语法如下:
for (val in sequence) {
语句
}
下面是个示例:
vals <- c(3, 6, 8, 9, 11, 16)
counter <- 0
for (val in vals) {
if (val %% 2 != 0) counter <- counter + 1
}
print(counter)
上述代码会计算向量vals
中奇数的个数,输出结果为3。
1.9.4 while循环
while
循环在每次循环开始前都会检验逻辑条件是否成立。while
循环的语法如下:
while (表达式) {
语句
}
在每次循环中,R都会对表达式进行求值,如果结果为TRUE
,则重复执行循环体中的语句。也就是说,while
循环会重复执行直至表达式的取值为FALSE
。示例如下:
helo <- "Hello"
counter <- 4
while (counter < 7) {
print(helo)
counter <- counter + 1
}
## [1] "Hello"
## [1] "Hello"
## [1] "Hello"
1.9.5 apply()函数
apply()
函数会对矩阵、向量、数组等数据对象的每行、每列或每个元素依次执行某项操作。例如我们可使用apply()
函数来计算矩阵每一行中各元素的和,代码及输出结果如下:
sample <- matrix(c(1:10), nrow = 5 , ncol = 2)
apply(sample, 1, sum)
## [1] 7 9 11 13 15
1.9.6 sapply()函数
sapply()
函数会对数据集(如列表或向量)中的每个元素调用指定函数,示例代码如下:
sapply(1:5, function(x) x^3)
## [1] 1 8 27 64 125
上述代码计算得到自然数序列1到5的三次方。
1.10 循环控制语句
循环控制语句(break
和next
)会变更循环执行的正常顺序,在此我们加以简要讨论。
1.10.1 break语句
break停止当前循环并将控制交给循环之后的下一个语句,例如:
helo <-c ("Hello")
counter <- 5
repeat {
print(helo)
counter <- counter + 1
if(counter > 8) {
break
}
}
由于break
语句的存在,上述代码只会打印"Hello"
4次,然后就会退出循环。在此,repeat
是另一类循环语句,它会重复执行直至循环体内触发停止循环的条件。
1.10.2 next语句
next
并不终止循环,而是跳过当前循环,直接进入下一个循环。示例如下:
vec <- c(2, 3, 4, 5, 6)
for (i in vec) {
if (i == 4) {
next
}
print(i)
}
## [1] 2
## [1] 3
## [1] 5
## [1] 6
在上述例子中,当循环至向量vec
的第3个元素4时,控制语句next
会跳过当前循环,进入下一个循环。因此,执行上述代码只会打印出向量vec
的元素2、3、5和6,而跳过元素4。
1.11 问题
1.R的原子对象包括哪些?
2.R的向量指的是什么?
3.向量和列表的区别是什么?
4.数组和矩阵的区别是什么?
5.什么是数据框?它在R中的重要性体现在哪里?
6.在R中怎样读取和存储CSV和XLSX文档?
7.在R中怎样读取和存储股票市场数据?
8.解释用R连接关系型数据库的步骤。
9.什么是函数?它在R中的重要性体现在哪里?
10.什么是R的赋值运算符?
11.在R中如何调用函数?
12.在R中如何加载R脚本文档?
13.在R中for循环和while循环有哪些不同?
1.12 小结
在本章中我们学到的内容概括如下。
- 对于那些打算在金融领域寻找职业机会的分析师来说,学习R语言很有用。
- 安装R软件和R程序包的方法。
- R的基本对象包括字符、数值、整数、复数和逻辑值。
- R中经常用到的数据类型包括向量、列表、矩阵、数组、因子和数据框。
- 用R从外部数据文档(如CSV和XLSX文档)、网络资源和数据库中读取数据。
- 用R存储数据到CSV和XLSX格式文档中。
- 编写不同类型的表达式,具体如常数、算术、逻辑、符号、赋值表达式等。
- 编写自定义函数。
- 调用自定义函数和内置函数。
- 在R控制台窗口中运行R程序和加载脚本文档。
- 使用条件控制语句(如
if
和else
)。 - 使用循环语句(如
for
和while
)。