查看“︁R/R语法”︁的源代码
←
R/R语法
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
= R的对象数据类型与数据结构 = <blockquote>R操作的实体在技术上来说都是对象(object)。当R在运行时,所有变量,数据,函数及结果都以对象的形式存在计算机的活动内存中,并有相应的名字对应。</blockquote> == R的对象 == R有五种基本(atomic)的数据类型: * 字符串 character * 数值型(实数)numeric * 整数 integer * 复合型 complex * 逻辑型 logistic (True/False) R最基本的对象是向量 * 向量(vertor)只能储存一种数据类型 * 列表(list)是个特例,用向量表示,可以存储不同数据类型的对象 <code>vector()</code> 函数可以创建一个空向量 <syntaxhighlight lang="r" line="1"> v <- vector() </syntaxhighlight> == 数值 == * 数值在R中储存为numeric对象(例如双精度实数) * 如果想明确的声明一个整数,添加<code>L</code> 后缀 <syntaxhighlight lang="r" line="1"> > class(1) [1] "numeric" > class(1L) [1] "integer" </syntaxhighlight> * 特殊数值 <code>Inf</code> 表示无限infinity,<code>Inf</code>也可以用于计算正常计算 <syntaxhighlight lang="r" line="1"> > 1/ 0 [1] Inf > 1 / Inf [1] 0 </syntaxhighlight> * <code>NaN</code>代表未定义的值 (“not a number”),可以看作一个缺失值 <syntaxhighlight lang="r" line="1"> > 0/0 [1] NaN </syntaxhighlight> == 属性 Attributes == R对象有不同的属性 * 名称,names;行列名,dimnames * 维度,dimensions (例如矩阵matrix,数组array) * 类型,class * 长度,length * 模式,mode * 其他自定义的属性attributes/metadata <code>attributes()</code>函数可以查看一个对象的属性。 <syntaxhighlight lang="r" line="1"> > x <-matrix(0,4,5) > x [,1] [,2] [,3] [,4] [,5] [1,] 0 0 0 0 0 [2,] 0 0 0 0 0 [3,] 0 0 0 0 0 [4,] 0 0 0 0 0 > class(x) [1] "matrix" > mode(x) [1] "numeric" > length(x) [1] 20 </syntaxhighlight> == 输入 == <code><-</code> 符号进行赋值操作。<syntaxhighlight lang="r" line="1"> > x <- 1 > print(x) [1] 1 > x [1] 1 > msg <- "hello" > msg [1] "hello" </syntaxhighlight>编程语言的语法决定表达式是否完成。<syntaxhighlight lang="r" line="1"> ## 未完成的表达式 > x <- # #字符开头表示注释,#字符右边的内容被忽略。 </syntaxhighlight> == 赋值计算Evaluation == 输入一个完整的表达式,R语言会计算表达式,并返回结果。<syntaxhighlight lang="r" line="1"> > x <- 5 ## 不打印 > x ## 自动打印 [1] 5 > print(x) ## 用print来输出结果 [1] 5 </syntaxhighlight> == 输出 Printing == <syntaxhighlight lang="r" line="1"> > x <- 1:20 > x [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [16] 16 17 18 19 20 </syntaxhighlight><code>:</code>操作符用来创建整数序列。 == R向量vector和列表list == === 创建向量vector === <code>c()</code>函数可以用来创建向量对象。 <syntaxhighlight lang="r" line="1"> > x <- c(0.5, 0.6) ## numeric > x <- c(TRUE, FALSE) ## logical > x <- c(T, F) ## logical > x <- c("a", "b", "c") ## character > x <- 9:29 ## integer > x <- c(1+0i, 2+4i) ## complex </syntaxhighlight>可以使用<code>vector()</code>函数创建向量<syntaxhighlight lang="r" line="1"> > x <- vector("numeric", length = 10) > x [1] 0 0 0 0 0 0 0 0 0 0 </syntaxhighlight> === 向量中创建不同数据类型的对象 === <syntaxhighlight lang="r" line="1"> # 将数值和字符声明到同一向量对象 > y <- c(1.7, "a") # 数值强制转换成字符串 > mode(y) [1] "character" # 将逻辑值和数值声明到一个向量对象中 > y <- c(TRUE, 2) # 逻辑型强制转换为数值型 > mode(y) [1] "numeric" # 在一个向量对象中储存字符串和逻辑值 > y <- c("a", TRUE) # 逻辑值强制转换为字符串 > mode(y) [1] "character" </syntaxhighlight>当在同一个向量对象中赋值不同数据类型属,''coercion''强制转换向量中的每个元素成同一种数据类型。 === 指定强制转换类型 === 通过<code>as.*</code>函数,可以将对象转换为指定的数据类型<syntaxhighlight lang="r" line="1"> # 生成一个整数型向量x > x <- 0:6 # 查看x的数据类型 > class(x) [1] "integer" # 转换成数值型 > as.numeric(x) [1] 0 1 2 3 4 5 6 # 转换成逻辑型 > as.logical(x) [1] FALSE TRUE TRUE TRUE TRUE TRUE TRUE # 转换成字符型 > as.character(x) [1] "0" "1" "2" "3" "4" "5" "6" </syntaxhighlight>无意义的转换产生<code>NA</code><syntaxhighlight lang="r" line="1"> # 生成一个字符串型向量x > x <- c("a", "b", "c") # 强制转换为数值型产生NA > as.numeric(x) [1] NA NA NA Warning message: NAs introduced by coercion # 强制转换为逻辑型产生NA > as.logical(x) [1] NA NA NA # 强制转换为复杂性型向量 > as.complex(x) [1] 0+0i 1+0i 2+0i 3+0i 4+0i 5+0i 6+0i </syntaxhighlight> == 矩阵matrix和列表list == === 矩阵matrix === 矩阵是具有二维''dimension'' (nrow, ncol)维度属性的向量。<syntaxhighlight lang="r" line="1"> > m <- matrix(nrow = 2, ncol = 3) > m [,1] [,2] [,3] [1,] NA NA NA [2,] NA NA NA > dim(m) [1] 2 3 > attributes(m) $dim [1] 2 3 > dim(m) </syntaxhighlight>矩阵通过扩展列''column-wise''构建,生成矩阵时,输入从左上角开始,顺列填充。<syntaxhighlight lang="r" line="1"> > m <- matrix(1:6, nrow = 2, ncol = 3) > m [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 </syntaxhighlight>矩阵可以通过向量添加维度属性来创建。<syntaxhighlight lang="r" line="1"> > m <- 1:10 > m [1] 1 2 3 4 5 6 7 8 9 10 > dim(m) <- c(2, 5) > m [,1] [,2] [,3] [,4] [,5] [1,] 1 3 5 7 9 [2,] 2 4 6 8 10 </syntaxhighlight> === cbind和rbind === 矩阵可以通过列合并''column-binding''函数<code>cbind()</code>及行合并''row-binding''函数<code>rbind()</code>来创建。<syntaxhighlight lang="r" line="1"> > x <- 1:3 > y <- 10:12 > cbind(x, y) x y [1,] 1 10 [2,] 2 11 [3,] 3 12 > rbind(x, y) [,1] [,2] [,3] x 1 2 3 y 10 11 12 </syntaxhighlight> === 列表list === 列表list是可以包含不同数据类型的特殊向量。列表是R中非常重要的数据类型。<syntaxhighlight lang="r" line="1"> > x <- list(1, "a", TRUE, 1 + 4i) > x [[1]] [1] 1 [[2]] [1] "a" [[3]] [1] TRUE [[4]] [1] 1+4i </syntaxhighlight> == 因子Factors == 因子用来表示数据分组,可以有序或无序。因子可以视作带标签''label''的整型向量。 * 因子可通过模型函数<code>lm()</code> 和<code>glm()</code>创建 * 使用标签的因子分组比使用数据更直观,“Male”和“Female”分组比1和2分组更易于理解 <syntaxhighlight lang="r" line="1"> > x <- factor(c("yes", "yes", "no", "yes", "no")) > x [1] yes yes no yes no Levels: no yes > table(x) x no yes 2 3 > unclass(x) [1] 2 2 1 2 1 attr(,"levels") [1] "no" "yes" </syntaxhighlight>水平的先后顺序可以使用<code>factor()</code>函数的<code>levels</code>参数来指定。这在线性模型中很重要,因为第一个水平常被用来作为对照。<syntaxhighlight lang="r" line="1"> > x <- factor(c("yes", "yes", "no", "yes", "no"), levels = c("yes", "no")) > x [1] yes yes no yes no Levels: yes no </syntaxhighlight> === 缺失值Missing Values === 缺失值<code>NA</code>和<code>NaN</code>代表未定义的数学操作。 * <code>is.na()</code>函数用来测试R对象是否为<code>NA</code> * <code>is.nan()</code>函数用来测试R对象是否为<code>NaN</code> * <code>NA</code>值也有数据类型,整型<code>NA</code>, 字符串character <code>NA</code>等等 * <code>NaN</code>值属于<code>NA</code>值 <syntaxhighlight lang="r" line="1"> > x <- c(1, 2, NA, 10, 3) > is.na(x) [1] FALSE FALSE TRUE FALSE FALSE > is.nan(x) [1] FALSE FALSE FALSE FALSE FALSE > x <- c(1, 2, NaN, NA, 4) > is.na(x) [1] FALSE FALSE TRUE TRUE FALSE > is.nan(x) [1] FALSE FALSE TRUE FALSE FALSE </syntaxhighlight> == 数据框dataframe与R对象的命名 == === 数据框dataframe === 数据框用来储存表格型的数据 * 数据框是一种特殊类型的多维列表,其中每个列表的长度必须相等 * 一个列表就是数据框的一列,列表的长度就是数据框的行数 * 与矩阵不同,数据框可以在一列中储存不同类型的对象(与list类似);矩阵中的每个元素都必须是相同的数据类型 * 数据框有一个特殊的属性行名<code>row.names</code> * 数据框一般通过调用<code>read.table()</code>或<code>read.csv()</code>函数构建 * 数据框可以通过调用<code>data.matrix()</code>函数转换为矩阵 <syntaxhighlight lang="r" line="1"> > x <- data.frame(foo = 1:4, bar = c(T, T, F, F)) > x foo bar 1 1 TRUE 2 2 TRUE 3 3 FALSE 4 4 FALSE > nrow(x) [1] 4 > ncol(x) [1] 2 </syntaxhighlight> === R对象的命名 === 对R对象进行命名,可以提升代码的可读性。<syntaxhighlight lang="r" line="1"> > x <- 1:3 > names(x) NULL > names(x) <- c("foo", "bar", "norf") > x foo bar norf 1 2 3 > names(x) [1] "foo" "bar" "norf" </syntaxhighlight>对列表list命名。<syntaxhighlight lang="r" line="1"> > x <- list(a = 1, b = 2, c = 3) > x $a [1] 1 $b [1] 2 $c [1] 3 </syntaxhighlight>矩阵matrix的命名。<syntaxhighlight lang="r" line="1"> > m <- matrix(1:4, nrow = 2, ncol = 2) > dimnames(m) <- list(c("a", "b"), c("c", "d")) > m c d a 1 3 b 2 4 </syntaxhighlight> == R数据类型与结构小结 == 数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。 * 基本类:数值numeric(用于直接计算、加减乘除), 逻辑logical(真假), 字符串character(连接、转换、提取),整型integer,复合型complex,日期等 * 向量vector, 列表list * 因子factor * 缺失值missing values * 数据框data frames * 命名names {| class="wikitable mw-collapsible" |+常见的数据类型及结构 !对象 !模式 !是否允许同一个对象中有多种模式 |- |向量 |数值型,字符型,复数型,逻辑型 |否 |- |因子 |数值型,字符型 |否 |- |数组 |数值型,字符型,复数型,逻辑型 |否 |- |矩阵 |数值型,字符型,复数型,逻辑型 |否 |- |数据框 |数值型,字符型,复数型,逻辑型 |是 |- |时间序列 |数值型,字符型,复数型,逻辑型 |否 |- |列表 |数值型,字符型,复数型,逻辑型,函数,表达式,… |是 |} = R文件操作 = == 获取数据的方式 == * 利用键盘输入数据 * 读取存储在磁盘上的数据文件 * 通过开放数据库连接(ODBC, Open database Connectivity)访问数据库系统来获取数据(RODBC包) <syntaxhighlight lang="r" line="1"> # 可以使用scan函数一个个输入来创建向量 > patientID <- scan() 1: 1 2: 2 3: 3 4: 4 5: Read 4 items # 也可以直接使用c()函数创建向量,结果是相同的 > patientID <- c(1, 2, 3, 4) > admdate <- c("10/15/2009", "11/01/2009", "10/21/2009", "10/28/2009") > age <- c(25, 34, 28, 52) > diabetes <- c("Type1", "Type2", "Type1", "Type1") > status <- c("Poor", "Improved", "Excellent", "Poor") > data <- data.frame(patientID, age, diabetes, status) > data patientID age diabetes status 1 1 25 Type1 Poor 2 2 34 Type2 Improved 3 3 28 Type1 Excellent 4 4 52 Type1 Poor data2 <- data.frame(patientID=character(0), age=numeric(0), diabetes=character(), status=character()) # 使用edit和fix函数来添加数据 > data2 <- edit(data2) > fix(data2) </syntaxhighlight>其他R编辑数据的函数,用法与edit和fix类似:<syntaxhighlight lang="r" line="1"> vi(name = NULL, file = "") emacs(name = NULL, file = "") pico(name = NULL, file = "") xemacs(name = NULL, file = "") xedit(name = NULL, file = "") </syntaxhighlight> == 读取数据 == R中有很多函数可以读取数据 * read.table, read.csv用来读取制表符分隔的数据 * readLines 读取文本文件的一行 * source 读取R代码文件 (与dump对应) * dget 读取R代码文件 (与dput对应 * load 读取保存的工作空间 * unserialize 读取一个serialize封装的二进制R对象 == 写入文件 == R中有很多功能类似的函数将数据写入文件 * write.table * writeLines * dump * dput * save * serialize == 使用read.table函数读取数据 == read.table函数是最长用的读取数据的函数。它有几个非常重要的参数:<syntaxhighlight lang="text" line="1"> file 文件的名字或者链接 header 逻辑值表示文件是否有表头 sep 分隔符,指定列分隔符是什么 colClasses 字符串向量表示数据集中每列的类 nrows 数据集的行数 comment.char 字符串表示注释 skip 忽略开始的多少行 stringsAsFactors 逻辑值,设置字符串变量是否用因子结构储存 </syntaxhighlight>对于中小型数据集,使用read.table函数的默认参数即可<syntaxhighlight lang="r" line="1"> data<-read.table("foo.txt") </syntaxhighlight> * R会自动忽略以“#”开头的行 * 设置数据集的行数(需要占用多少内存)和每列数据的变量类型可以加快R的运行效率f read.csv函数除了默认分隔符是逗号以外,其他参数和read.table函数相同。 == 使用read.table函数读取大数据集 == 对于大型数据集,首先大致估计一下需要使用多少内存来储存数据集,如果数据所需要的内存大于计算机的物理内存,那就需要使用其他方式处理数据。 * 如果数据集中没有注释行将参数comment.char = "" * 使用colClasses参数可以提高一倍的读取速度,这要求指定数据集中每一列的数据类型。如果每列都是数值,可以直接设置参数colClasses = "numeric"。另一个快速设置每列的类型的方法如下: <syntaxhighlight lang="r" line="1"> initial<-read.table("datatable.txt",nrows=100) classes<-sapply(initial,class) tabAll<-read.table("datatable.txt",colClasses=classes) </syntaxhighlight> * 设置nrows参数。不能提速当能够帮助R优化内存的使用,可以使用Linux的wc命令来计算数据集的行数。 == 了解一些操作系统 == 使用R处理大数据集时,需要了解一些操作系统的情况。 * 电脑的内存多大 * 有什么应用程序在运行 * 是否有其他用户登陆到该操作系统 * 什么操作系统 * 32还是64位操作系统 == 计算内存使用 == 一个1,500,000行和120列的数值型数据框占用内存的计算: 1,500,000 × 120 × 8 bytes/numeric = 1440000000 bytes = 1440000000 / bytes/MB = 1,373.29 MB = 1.34 GB == 文本格式 == * <code>dump</code>和dput函数的是文本格式,可以直接编辑,在文件出错时,可以恢复。 * <code>dump</code>和<code>dput</code>保存了对象的''metadata''(R对象的属性信息),这降低了结果的可读性,但读入数据时,不需要在对该数据集进行额外的处理。 * 文本格式文件方便进行版本控制,git等命令只能追踪文本文件的改变。 * 文件格式用处更广泛,如果文本中出现错误,相比二进制文件,更容易被修复。 * 文本格式更符合Unix哲学 * 缺点:占用更多的空间(相比于二进制文件) == dput操作R对象 == 通过dput函数将R对象写入文件,使用<code>dget</code>函数将文件读入R。<syntaxhighlight lang="r" line="1"> > y <- data.frame(a = 1, b = "a") > dput(y) structure(list(a = 1, b = structure(1L, .Label = "a", class = "factor")), .Names = c("a", "b"), row.names = c(NA, -1L), class = "data.frame") > dput(y, file = "y.R") > new.y <- dget("y.R") > new.y a b 1 1 a </syntaxhighlight> == dump函数操作R对象 == dump函数可以同时打包多个R对象写入文件,可以使用<code>source</code>函数将文件读回R。<syntaxhighlight lang="r" line="1"> > x <- "foo" > y <- data.frame(a = 1, b = "a") > dump(c("x", "y"), file = "data.R") > rm(x, y) > source("data.R") > y a b 1 1 a > x [1] "foo" </syntaxhighlight> == 其他数据操作的函数 == 数据操作可以通过创建一个链接(其他语言称为文件句柄)来实现。 * <code>file</code> 创建一个普通文件的链接 * <code>gzfile</code> 创建一个gzip格式压缩文件的链接 * <code>bzfile</code> 创建一个bzip2格式压缩文件的链接 * <code>url</code> 创建一个读取网页的链接 == 文件链接 == <syntaxhighlight lang="r" line="1"> > str(file) function (description = "", open = "", blocking = TRUE, encoding = getOption("encoding")) </syntaxhighlight> * <code>description</code>参数设置读取文件的名称 * <code>open</code>参数设置文件的操作权限 ** “r” 只读 ** “w” 可写并初始化一个新文件 ** “a” 追加 ** “rb”, “wb”, “ab” 读、写、追加二进制格式文件 文件链接可以帮助用户更灵活地操作文件或外部对象,我们不用直接对该链接进行操作,R中的函数可以直接处理。<syntaxhighlight lang="r" line="1"> con <- file("foo.txt", "r") data <- read.csv(con) close(con) </syntaxhighlight>等同于<syntaxhighlight lang="r" line="1"> data <- read.csv("foo.txt") </syntaxhighlight> == 按行读取文件 == <syntaxhighlight lang="r" line="1"> > con <- gzfile("words.gz") > x <- readLines(con, 10) > x [1] "1080" "10-point" "10th" "11-point" [5] "12-point" "16-point" "18-point" "1st" [9] "2" "20-point" </syntaxhighlight><code>writeLines</code>读取字符串向量,将向量中每行对象按行写入文件。 ----<code>readLines</code>在读取网页数据十分有用<syntaxhighlight lang="r" line="1"> > con <- url("http://www.baidu.com", "r") > x <- readLines(con) > head(x) [1] "<!DOCTYPE html>" "<!--STATUS OK-->" "" "" [5] "" </syntaxhighlight> = 提取R对象的子集 = R中有很多操作可以提取R对象的子集。 * <code>[</code> 操作返回跟原R对象类相同的对象;可以同时提取多个对象(例外) * <code>[[</code> 用来提取列表list或数据框dataframe对象;该操作只能用来提取单个元素,返回的对象不一定是list或数据框 * <code>$</code> 通过list和dataframe的命名name来提取元素,语义上类似于 <code>[[</code> <syntaxhighlight lang="r" line="1"> > x <- c("a", "b", "c", "c", "d", "a") > x[1] [1] "a" > x[2] [1] "b" > x[1:4] [1] "a" "b" "c" "c" > x[x > "a"] [1] "b" "c" "c" "d" > u <- x > "a" > u [1] FALSE TRUE TRUE TRUE TRUE FALSE > x[u] [1] "b" "c" "c" "d" </syntaxhighlight> == 提取矩阵的子集 == 矩阵的子集的提取通常通过 (''i,j'')来索引。<syntaxhighlight lang="r" line="1"> > x <- matrix(1:6, 2, 3) > x [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 > x[1, 2] [1] 3 > x[2, 1] [1] 2 </syntaxhighlight>索引可以缺失。<syntaxhighlight lang="r" line="1"> > x[1, ] [1] 1 3 5 > x[, 2] [1] 3 4 </syntaxhighlight>当提取矩阵的单个元素时,默认返回一个长度为1的向量,而不是一个1 × 1的矩阵。可以通过设置参数<code>drop = FALSE</code>来改变。<syntaxhighlight lang="r" line="1"> > x <- matrix(1:6, 2, 3) > x[1, 2] [1] 3 > x[1, 2, drop = FALSE] [,1] [1,] 3 </syntaxhighlight>类似的,提取矩阵的一列或一行时默认返回向量,而不是矩阵。<syntaxhighlight lang="r" line="1"> > x <- matrix(1:6, 2, 3) > x[1, ] [1] 1 3 5 > x[1, , drop = FALSE] [,1] [,2] [,3] [1,] 1 3 5 </syntaxhighlight> == 提取列表的子集 == 第一个例子<syntaxhighlight lang="r" line="1"> > x<-list(foo = 1:4, bar = 0.6) > x[1] $foo [1] 1 2 3 4 > x[[1]] [1] 1 2 3 4 > x$bar [1] 0.6 > x[["bar"]] [1] 0.6 > x["bar"] $bar [1] 0.6 </syntaxhighlight>第二个例子<syntaxhighlight lang="r" line="1"> > x <- list(foo = 1:4, bar = 0.6, baz = "hello") > x[c(1, 3)] $foo [1] 1 2 3 4 $baz [1] "hello" </syntaxhighlight><code>[[</code> 可以使用变量或表达式作为索引;<code>$</code> 只能按照命名的名称来索引。<syntaxhighlight lang="r" line="1"> > x <- list(foo = 1:4, bar = 0.6, baz = "hello") > name <- "foo" ## 使用变量索引 ‘foo’ > x[[name]] [1] 1 2 3 4 ## 不存在元素名称为 ‘name’ > x$name NULL ## ‘foo’存在 > x$foo [1] 1 2 3 4 </syntaxhighlight> == 提取嵌套列表(多维维列表)的子集 == <code>[[</code> 可以使用整数序列作为索引。<syntaxhighlight lang="r" line="1"> > x <- list(a = list(10, 12, 14), b = c(3.14, 2.81)) > x[[c(1, 3)]] [1] 14 > x[[1]][[3]] [1] 14 > x[[c(2, 1)]] [1] 3.14 </syntaxhighlight> == 局部匹配 == <code>[[</code> 和<code>$</code>允许名称的局部匹配来索引子集。<syntaxhighlight lang="r" line="1"> > x <- list(aardvark = 1:5) > x$a [1] 1 2 3 4 5 > x[["a"]] NULL > x[["a", exact = FALSE]] [1] 1 2 3 4 5 </syntaxhighlight> == 去除NA值 == 在进行数据分析的过程中,经常需要对缺失值(<code>NA</code>)进行处理。<syntaxhighlight lang="r" line="1"> > x <- c(1, 2, NA, 4, NA, 5) > bad <- is.na(x) > x[!bad] [1] 1 2 4 5 </syntaxhighlight>去除多个R对象的缺失值,并提取不含缺失值的子集。 第一个例子<syntaxhighlight lang="r" line="1"> > x <- c(1, 2, NA, 4, NA, 5) > y <- c("a", "b", NA, "d", NA, "f") > good <- complete.cases(x, y) > good [1] TRUE TRUE FALSE TRUE FALSE TRUE > x[good] [1] 1 2 4 5 > y[good] [1] "a" "b" "d" "f" </syntaxhighlight>第二个列子<syntaxhighlight lang="r" line="1"> > airquality[1:6, ] Ozone Solar.R Wind Temp Month Day 1 41 190 7.4 67 5 1 2 36 118 8.0 72 5 2 3 12 149 12.6 74 5 3 4 18 313 11.5 62 5 4 5 NA NA 14.3 56 5 5 6 28 NA 14.9 66 5 6 > good <- complete.cases(airquality) > airquality[good, ][1:6, ] Ozone Solar.R Wind Temp Month Day 1 41 190 7.4 67 5 1 2 36 118 8.0 72 5 2 3 12 149 12.6 74 5 3 4 18 313 11.5 62 5 4 7 23 299 8.6 65 5 7 8 19 99 13.8 59 5 8 </syntaxhighlight> = 向量化操作 = R中的很多操作都是针对向量的,这也使得R代码高效、简洁、可读性强。<syntaxhighlight lang="r" line="1"> > x <- 1:4; y <- 6:9 > x [1] 1 2 3 4 > y [1] 6 7 8 9 > x + y [1] 7 9 11 13 > x > 2 [1] FALSE FALSE TRUE TRUE > x >= 2 [1] FALSE TRUE TRUE TRUE > y == 8 [1] FALSE FALSE TRUE FALSE > x * y [1] 6 14 24 36 > x / y [1] 0.1666667 0.2857143 0.3750000 0.4444444 </syntaxhighlight> == 矩阵的向量化操作 == <syntaxhighlight lang="r" line="1"> > x <- matrix(1:4, 2, 2); y <- matrix(rep(10, 4), 2, 2) > x [,1] [,2] [1,] 1 3 [2,] 2 4 > y [,1] [,2] [1,] 10 10 [2,] 10 10 ## element-wise乘法(数组元素依次相乘) > x * y [,1] [,2] [1,] 10 30 [2,] 20 40 > x / y [,1] [,2] [1,] 0.1 0.3 [2,] 0.2 0.4 ## 真正的矩阵乘法 > x %*% y [,1] [,2] [1,] 40 40 [2,] 60 60 </syntaxhighlight> = R控制结构 = R中的控制结构允许用户在不同情况下设置程序的执行流程。常见的结构包括: * <code>if</code>, <code>else</code>: 判断条件 * <code>for</code>: 执行固定次数的循环 * <code>while</code>: 当 ''while'' 的条件为真时,执行循环 * <code>repeat</code>: 执行无限次循环 * <code>break</code>: 退出整个循环 * <code>next</code>: 跳过本次循环 * <code>return</code>: 退出函数 大多数控制结构一般不在R的交互命令对话中使用,主要应用在自定义函数或较长的表达式中。 == 控制结构:if == <syntaxhighlight lang="r" line="1"> if(<condition>) { ## do something } else { ## do something else } if(<condition1>) { ## do something } else if(<condition2>) { ## do something different } else { ## do something different } </syntaxhighlight>下面是一些有效的 if/else 结构示例。<syntaxhighlight lang="r" line="1"> if(x > 3) { y <- 10 } else { y <- 0 } </syntaxhighlight>等同于<syntaxhighlight lang="r" line="1"> y <- if(x > 3) { 10 } else { 0 } </syntaxhighlight>else语句不是必须的。<syntaxhighlight lang="r" line="1"> if(<condition1>) { } if(<condition2>) { } </syntaxhighlight> == for == <code>for</code> 循环接收可迭代的变量,一般是来自序列或向量的连续值。for循环经常使用的循环元素来自于列表、向量等R对象。<syntaxhighlight lang="r" line="1"> for(i in 1:10) { print(i) } </syntaxhighlight>该循环将变量 <code>i</code> 作为循环变量,循环依次赋值1, 2, 3, ..., 10,然后退出循环。 下面几个循环的功能相同。<syntaxhighlight lang="r" line="1"> x <- c("a", "b", "c", "d") for(i in 1:4) { print(x[i]) } for(i in seq_along(x)) { print(x[i]) } for(letter in x) { print(letter) } for(i in 1:4) print(x[i]) </syntaxhighlight> == 嵌套循环 == <code>for</code> 循环可以嵌套使用。<syntaxhighlight lang="r" line="1"> x <- matrix(1:6, 2, 3) for(i in seq_len(nrow(x))) { for(j in seq_len(ncol(x))) { print(x[i, j]) } } </syntaxhighlight>慎重使用嵌套循环,嵌套超过2-3层后会难以阅读和理解,也会拖慢程序的运行速度。 == while == while循环开始前先测试循环条件。如果值为真,执行循环体。当循环体运行完,再次测试循环条件,如此循环下去。<syntaxhighlight lang="r" line="1"> count <- 0 while(count < 10) { print(count) count <- count + 1 } </syntaxhighlight>while循环如果没有正确编写,可能会陷入无限循环(死循环),使用时要注意。 ----有时需要同时满足多个判断条件进行循环。<syntaxhighlight lang="r" line="1"> z <- 5 while(z >= 3 && z <= 10) { print(z) # 随机生成0或1 coin <- rbinom(1, 1, 0.5) if(coin == 1) { z <- z + 1 } else { z <- z - 1 } } </syntaxhighlight>判断条件是从左到右进行判断。 ---- == repeat == repeat初始化一个无限循环,有特殊用途,通常不应用在数据统计分析中,退出<code>repeat</code>循环的唯一方法是<code>break</code>。 以下循环是个repeat的无限循环,运行后需要强制终止。<syntaxhighlight lang="r" line="1"> x0 <- 1 tol <- 0 repeat { x1 <- rbinom(1, 1, 0.5) if(abs(x1 - x0) < tol) { break } else { x0 <- x1 } } </syntaxhighlight>上面的循环对于初学者不友好,容易陷入死循环。最好设置迭代次数限制(例如使用for循环),然后打印是否得到预期结果。 ---- == next, return == <code>next</code>用来跳过本次循环。<syntaxhighlight lang="r" line="1"> for(i in 1:100) { if(i <= 20) { ## 跳过前20次循环 next } ## Do something here } </syntaxhighlight><code>return</code> 表示一个函数的结果同时返回函数的运算结果。 ---- == 小结 == * R语言中<code>if</code>、<code>while</code>和<code>for</code> 循环和判断结构。 * 避免死循环,即使在理论上是合理的。 * 控制结构语句对R编程十分有用;对于R的交互式命令行操作,''apply''家族的函数更高效。 = 函数 = 通过<code>function()</code>可以自定义函数,函数的储存与其他的R对象相同,函数对象的类为 “function”。<syntaxhighlight lang="r" line="1"> f <- function(<参数>) { ## R语句 } </syntaxhighlight>R函数也是R对象,可以向其他R对象一样进行操作: * 函数可以作为参数传递给其他函数 * 函数可以嵌套,可以在函数中包含函数。 * 函数的返回值是函数体中最后一个表达式。 ** * == 函数的参数 == 函数的 ''参数'' 一般会有默认值。 * ''形式参数''指的是在函数内定义的参数 * <code>formals</code> 函数可以查看一个函数所有的形式参数 * 不是每个R函数都需要使用所有的参数 * 函数的参数可以省略或保持默认值。 == 参数匹配 == R函数参数可以通过position matching或name matching进行匹配。以下调用 <code>sd</code> 函数的操作都是等同的。<syntaxhighlight lang="r" line="1"> > mydata <- rnorm(100) > sd(mydata) [1] 0.9418245 > sd(x = mydata) [1] 0.9418245 > sd(x = mydata, na.rm = FALSE) [1] 0.9418245 > sd(na.rm = FALSE, x = mydata) [1] 0.9418245 > sd(na.rm = FALSE, mydata) [1] 0.9418245 </syntaxhighlight>虽然这些操作的结果都相同,但为避免造成误解,一般按照将要函数参数的默认顺序来赋值。 ----可以混合使用position matching和name matching。name matching的优先级高于position matching。<syntaxhighlight lang="r" line="1"> > args(lm) function (formula, data, subset, weights, na.action, method = "qr", model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, contrasts = NULL, offset, ...) NULL </syntaxhighlight>下面两种操作等同。<syntaxhighlight lang="r" line="1"> lm(data = mydata, y ~ x, model = FALSE, 1:100) lm(y ~ x, mydata, 1:100, model = FALSE) </syntaxhighlight> * 命名参数在交互式命令行中使用较多,尤其是参数较多时。 * 命名参数可以帮助记忆函数的参数名称,这在绘图中很有用。 函数参数可以部分匹配,有助于交互式操作。参数匹配的优先级的顺序如下: # 检查命名参数的精确匹配Check for exact match for a named argument # 检查局部匹配 # 检查位置匹配 ---- == 定义函数 == <syntaxhighlight lang="r" line="1"> f <- function(a, b = 1, c = 2, d = NULL) { } </syntaxhighlight>如果不想对函数的某个参数设置默认值,可以将 <code>NULL</code> 赋值给该参数。 == 惰性求值(延后计算) == R函数的参数的计算遵循惰性原则,只在需要时进行计算。<syntaxhighlight lang="r" line="1"> f <- function(a, b) { a^2 } f(2) ## [1] 4 </syntaxhighlight>该函数实际没有调用参数 <code>b</code> ,因此调用 <code>f(2)</code> 不会报错,根据位置匹配,将2赋值给2 <code>a</code>。<syntaxhighlight lang="r" line="1"> f <- function(a, b) { print(a) print(b) } f(45) ## [1] 45 ## Error: argument "b" is missing, with no default </syntaxhighlight>函数首先打印了“45”,然后报错,因为在执行 <code>print(a)</code> 时,参数 <code>b</code> 未调用。执行 <code>print(b)</code> 时程序报错 ---- == “...” 参数 == ... 参数用来传递数目不确定的参数给其他函数。 * ... 常被用来扩展一个函数,避免原函数的所有参数列表再次声明 <syntaxhighlight lang="r" line="1"> myplot <- function(x, y, type = "l", ...) { plot(x, y, type = type, ...) } </syntaxhighlight> * 一般函数使用 ... 传递额外的参数给方法(Method) <syntaxhighlight lang="r" line="1"> > mean function (x, ...) UseMethod("mean") </syntaxhighlight>如果无法提前知道需要传递给函数的参数数目,需要使用“...”参数。<syntaxhighlight lang="r" line="1"> > args(paste) function (..., sep = " ", collapse = NULL) > args(cat) function (..., file = "", sep = " ", fill = FALSE, labels = NULL, append = FALSE) </syntaxhighlight> == “...” 参数后的参数 == “...” 参数后的参数必须通过名称精确匹配,不能局部匹配。<syntaxhighlight lang="r" line="1"> > args(paste) function (..., sep = " ", collapse = NULL) > paste("a", "b", sep = ":") [1] "a:b" > paste("a", "b", se = ":") [1] "a b :" </syntaxhighlight> = 变量的作用域 = == 变量与变量名 == 对相同的变量名多次赋值时,R如何识别该变量名所对应的值? 一个例子:<syntaxhighlight lang="r" line="1"> > lm function (formula, data, subset, weights, na.action, method = "qr", model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, contrasts = NULL, offset, ...) {...... } <bytecode: 0x7feae2a23638> <environment: namespace:stats> > lm <- function(x) { x * x } > lm function(x) { x * x } </syntaxhighlight>当对 <code>lm</code> 赋值后,打印的值发生了变化,不再返回 ''stats'' 包中的 <code>lm</code> 所对应的值。 ----当对一个变量赋值时,R会搜索一系列的环境。当R取值时,环境的优先级从高到低如下: # 搜索全局环境中该变量名对应的值。 # 搜索每个扩展包中命名空间中的变量列表。 <code>search</code> 函数可以查看R的变量搜索列表。 > search() [1] ".GlobalEnv" "package:stats" "package:graphics" [4] "package:grDevices" "package:utils" "package:datasets" [7] "package:methods" "Autoloads" "package:base" * ''全局变量global environment''或用户的工作空间在列表的最前面,''base''扩展包排在最后。 * 扩展包的前后顺序很重要。 * 用户可以设置R启动时加载的扩展包。 * 使用 <code>library</code> 函数加载扩展包时,该扩展包的命名空间会默认排在搜索列表的第二位,其他变量列表依次后移。 * R中函数与非函数的命名空间是分离的,可以同时存在名称为c的R对象和函数。 == 变量的作用域 == R语言的作用域规则与S语言截然不同。 * 作用域规则决定函数中值如何与自由变量的关联。 * R使用的是静态作用域,一般称为lexical scoping,与之对应的是动态作用域。 * 作用域规则就是R在如何在变量列表中搜寻变量的规则。 * Lexical scoping有助于简化统计计算。 == Lexical Scoping == 一个示例:<syntaxhighlight lang="r" line="1"> f <- function(x, y) { x^2 + y / z } </syntaxhighlight>该函数有两个形式参数<code>x</code> 和 <code>y</code>,函数体内的 <code>z</code> 就是一个''自由变量''。编程语言的作用域规则决定值如何赋值给自由变量。自由变量既不是形式参数,也不是本地变量(在函数体内声明的变量)。 ----R的作用域规则:''在定义函数的环境中搜索自由变量的值'' 环境: * 环境就是一系列对应的变量名符号和值,如 <code>x</code> 是变量名符号,<code>3.14</code>是它对应的值。 * 每个环境都有一个母环境;一个环境可以有多个子环境。 * 没有母环境的环境是空环境。 * 函数 + 环境 = ''闭包'' 或 ''函数闭包''(函数可以使用函数之外定义的自由变量)。 搜索自由变量的值: * 如果在函数定义的环境中没有找到变量名对应的值,接着搜索母环境的变量。 * 依次搜索环境的母环境,一直到''顶层环境'';顶层环境一般是全局环境(工作空间)或者扩展包的命名空间。 * 顶层环境后,继续搜索直到碰到''空环境''。如果到达空环境,还没找到变量名对应的值,R就会报错。 如果在全局环境中定义函数,自由变量的值可以在用户的工作空间中找到,这是大多数情况下的正确做法。然而在R中,允许在函数中定义函数(类似C的编程语言不允许这样做)。在这种情况下,函数的定义环境就是其他函数的函数体。 ----在函数中定义另一个函数:<syntaxhighlight lang="r" line="1"> make.power <- function(n) { pow <- function(x) { x^n } pow } </syntaxhighlight>该函数返回函数体内定义的另一个函数作为返回值。<syntaxhighlight lang="r" line="1"> > cube <- make.power(3) > square <- make.power(2) > cube(3) [1] 27 > square(3) [1] 9 </syntaxhighlight> == 探索函数闭包 == 函数的环境:<syntaxhighlight lang="r" line="1"> > ls(environment(cube)) [1] "n" "pow" > get("n", environment(cube)) [1] 3 > ls(environment(square)) [1] "n" "pow" > get("n", environment(square)) [1] 2 </syntaxhighlight> == 静态作用域vs动态作用域 == 声明两个函数:<syntaxhighlight lang="r" line="1"> y <- 10 f <- function(x) { y <- 2 y^2 + g(x) } g <- function(x) { x*y } > f(3) [1] 34 </syntaxhighlight> * <code>g</code> 函数中 <code>y</code> 在lexical scoping的规则下,在函数定义的环境中(在本例中为全局环境)搜索 <code>y</code> 对应的值为10。 * 在动态作用域规则下, <code>y</code> 对应的值应该在函数被调用的环境中搜索。 ** R中的调用环境称为''parent frame''。 ** 根据动态作用规则 <code>y</code> 值应当为2。 当一个函数在全局环境环境中声明并调用时,定义环境和调用环境是相同的,有时表现出动态作用的特征。<syntaxhighlight lang="r" line="1"> > rm(list=ls()) > g <- function(x) { a <- 3 x+a+y } > g(2) Error in g(2) : object "y" not found > y <- 3 > g(2) [1] 8 </syntaxhighlight>其他支持lexical scoping的编程语言 * Scheme * Perl * Python * Common Lisp == Lexical Scoping的重要性 == * R中的所有对象都存储在内存中,所有函数都需要一个指向该函数定义环境的指针(可以在任何地方)。 * S-PLUS一般在全局工作空间中搜索自由变量,因此所有对象可以储存在磁盘上,因为所有函数的定义环境都相同。 == 应用:优化 == * R中的优化函数 <code>optim</code>, <code>nlm</code>, and <code>optimize</code> 要求传递一个参数的向量 (如log-likelihood) * 目标函数可能依赖于除参数之外的许多东西(如 ''data'') * 当对程序进行优化,用户更关注特定的参数 == 最大化标准似然 == 构建函数:<syntaxhighlight lang="r" line="1"> make.NegLogLik <- function(data, fixed=c(FALSE,FALSE)) { params <- fixed function(p) { params[!fixed] <- p mu <- params[1] sigma <- params[2] a <- -0.5*length(data)*log(2*pi*sigma^2) b <- -0.5*sum((data-mu)^2) / (sigma^2) -(a + b) } } </syntaxhighlight>''注意'':R中的优化函数都是最小化函数,需要使用负对数似然求最大化<syntaxhighlight lang="r" line="1"> > set.seed(1); normals <- rnorm(100, 1, 2) > nLL <- make.NegLogLik(normals) > nLL function(p) { params[!fixed] <- p mu <- params[1] sigma <- params[2] a <- -0.5*length(data)*log(2*pi*sigma^2) b <- -0.5*sum((data-mu)^2) / (sigma^2) -(a + b) } <bytecode: 0x7feaed346eb0> <environment: 0x7feae35d1bc8> > ls(environment(nLL)) [1] "data" "fixed" "params" </syntaxhighlight> == 参数估计 == <syntaxhighlight lang="r" line="1"> > optim(c(mu = 0, sigma = 1), nLL)$par mu sigma 1.218239 1.787343 </syntaxhighlight>当σ = 2时<syntaxhighlight lang="r" line="1"> > nLL <- make.NegLogLik(normals, c(FALSE, 2)) > optimize(nLL, c(-1, 3))$minimum [1] 1.217775 </syntaxhighlight>当μ = 1时<syntaxhighlight lang="r" line="1"> > nLL <- make.NegLogLik(normals, c(1, FALSE)) > optimize(nLL, c(1e-6, 10))$minimum [1] 1.800596 </syntaxhighlight> == 绘制最大似然图 == <syntaxhighlight lang="r" line="1"> nLL <- make.NegLogLik(normals, c(1, FALSE)) x <- seq(1.7, 1.9, len = 100) y <- sapply(x, nLL) plot(x, exp(-(y - min(y))), type = "l") </syntaxhighlight>[[File:R最大似然图.png|无框]][[File:R最大似然图2.png|无框]]<syntaxhighlight lang="r" line="1"> nLL <- make.NegLogLik(normals, c(FALSE, 2)) x <- seq(0.5, 1.5, len = 100) y <- sapply(x, nLL) plot(x, exp(-(y - min(y))), type = "l") </syntaxhighlight> == 小结 == * 目标函数可以包含评估该函数的所有必须数据 * 对于交互式和探索的工作不需要提供太长的参数列表 * 代码可以更简洁 扩展阅读: Robert Gentleman and Ross Ihaka (2000). “Lexical Scope and Statistical Computing,” ''JCGS'', 9, 491–508. = 编写R代码 = # 使用文本文件或编辑器 Always use text files / text editor # 适当的缩进 # 限制代码的宽度 # 限制自定义函数的长度 ---- == 缩进 == * 缩进提高代码的可读性 * 限制代码的长度,避免过多的嵌套和太长的函数 * 最少缩进4个空格,8个更完美 = 日期与时间 = R有一套特殊日期和时间的表示方法: * 日期使用 <code>Date</code> 类来表示 * 时间是通过 <code>POSIXct</code> 或 <code>POSIXlt</code> 类来表示 * R中储存的日期从1970-01-01这天开始的 * R中储存的时间是从1970-01-01的第一秒开始的 == 日期 == 日期使用Date类来表示,可以使用 <code>as.Date()</code> 函数从字符串转换成日期。<syntaxhighlight lang="r" line="1"> > x <- as.Date("1970-01-01") > x [1] "1970-01-01" > unclass(x) [1] 0 > unclass(as.Date("1970-01-02")) [1] 1 </syntaxhighlight> == 时间 == 时间使用 <code>POSIXct</code> 或 <code>POSIXlt</code> 类来表示。 * <code>POSIXct</code> 实际是一个十分巨大的整数,当使用数据框来储存时间时十分方便。 * <code>POSIXlt</code> 是一个列表,存储了年月周的哪一天等额外信息 有很多基本函数可以操作日期和时间 * <code>weekdays</code>: 返回一周的第几天 * <code>months</code>: 返回月份名称 * <code>quarters</code>: 返回季度信息(“Q1”, “Q2”, “Q3”, or “Q4”) 通过 <code>as.POSIXlt</code> 或 <code>as.POSIXct</code> 函数将字符串转换为日期。<syntaxhighlight lang="r" line="1"> > x <- Sys.time() > x [1] "2019-05-08 21:24:57 CST" > p <- as.POSIXlt(x) > names(unclass(p)) [1] "sec" "min" "hour" "mday" "mon" "year" "wday" "yday" [9] "isdst" "zone" "gmtoff" > p$sec [1] 57.742 </syntaxhighlight>使用 <code>POSIXct</code> 格式表示日期。<syntaxhighlight lang="r" line="1"> # Sys.time()生成的时间默认为 ‘POSIXct’ 格式 > x [1] "2019-05-08 21:24:57 CST" > unclass(x) [1] 1557321898 > x$sec Error in x$sec : $ operator is invalid for atomic vectors > p <- as.POSIXlt(x) > p$sec [1] 57.742 </syntaxhighlight>使用 <code>strptime</code> 函数改变日期的格式。<syntaxhighlight lang="r" line="1"> > datestring <- c("May 8, 2019 10:30", "May 9, 2019 09:10") > x <- strptime(datestring, "%B %d, %Y %H:%M") > x [1] "2019-05-08 10:30:00 CST" "2019-05-09 09:10:00 CST" > class(x) [1] "POSIXlt" "POSIXt" # 查看更多时间格式的帮助文档 > ?strptime </syntaxhighlight> == 日期和时间的操作 == 日期和时间也可以用于数学计算(如+, -),也可以做比较 (如 ==, <=)。<syntaxhighlight lang="r" line="1"> > x <- as.Date("2020-05-08") > y <- strptime("8 May 2019 10:34:21", "%d %b %Y %H:%M:%S") > x-y Error in x - y : non-numeric argument to binary operator In addition: Warning message: Incompatible methods ("-.Date", "-.POSIXt") for "-" > x <- as.POSIXlt(x) > x-y Time difference of 365.8928 days </syntaxhighlight>也可以计算甚至可以跟踪闰年、闰秒、夏令时和时区。<syntaxhighlight lang="r" line="1"> > x <- as.Date("2019-03-01") > y <- as.Date("2019-02-28") > x-y Time difference of 1 days > x <- as.POSIXct("2019-05-08 01:00:00") > y <- as.POSIXct("2019-05-08 06:00:00", tz = "GMT") > y-x Time difference of 13 hours </syntaxhighlight> == 小结 == * 日期和时间是R中特殊的类,允许数值和统计计算 * 日期使用 <code>Date</code> 类 * 时间使用 <code>POSIXct</code> 和 <code>POSIXlt</code> 类 * 可以使用 <code>strptime</code>, <code>as.Date</code>, <code>as.POSIXlt</code>, <code>as.POSIXct</code> 函数将字符串转换为日期/时间类 = apply函数家族 = == 命令行的循环 == 循环对于编程十分重要,但在R交互式命令行中编写循环结构不太方便,R提供了一系列函数来简化循环操作。 * <code>lapply</code>: 对一个列表进行循环,对列表中的,每个元素执行指定的函数操作,返回与原列表等长的结果 * <code>sapply</code>: 与 <code>lapply</code> 相同,简化结果 * <code>apply</code>: 对数组或矩阵执行指定的函数,返回向量、数组或列表 * <code>tapply</code>: 对向量的子集进行操作 * <code>mapply</code>: <code>lapply</code> 和 <code>sapply</code> 的升级版 <code>split</code> 函数辅助 <code>lapply</code> 会产生一些神操作。 ---- == lapply == <code>lapply</code> 需要三个参数: (1) 列表 <code>X</code>; (2) 函数或函数名<code>FUN</code>; (3) 其他参数通过 ... 参数传递。 如果 <code>X</code> 不是列表,会通过 <code>as.list</code> 函数强制转换为列表。<syntaxhighlight lang="r" line="1"> > lapply function (X, FUN, ...) { FUN <- match.fun(FUN) if (!is.vector(X) || is.object(X)) X <- as.list(X) .Internal(lapply(X, FUN)) } <bytecode: 0x7fd35e9dc718> <environment: namespace:base> </syntaxhighlight>实际循环操作是通过内部的C代码完成。 ----<code>lapply</code> 函数或返回一个列表,但会忽略输入数据的类型。<syntaxhighlight lang="r" line="1"> > x <- list(a = 1:5, b = rnorm(10)) > lapply(x, mean) $a [1] 3 $b [1] -0.1843325 </syntaxhighlight><syntaxhighlight lang="r" line="1"> > x <- list(a = 1:4, b = rnorm(10), c = rnorm(20, 1), d = rnorm(100, 5)) > lapply(x, mean) $a [1] 2.5 $b [1] -0.1599965 $c [1] 1.068789 $d [1] 4.837933 </syntaxhighlight><syntaxhighlight lang="r" line="1"> > x <- 1:4 > lapply(x, runif) [[1]] [1] 0.9785864 [[2]] [1] 0.5644791 0.9242951 [[3]] [1] 0.9274006 0.3646827 0.2551950 [[4]] [1] 0.3987640 0.5774553 0.7631348 0.7837444 </syntaxhighlight><syntaxhighlight lang="r" line="1"> > x <- 1:4 > lapply(x, runif, min = 0, max = 10) [[1]] [1] 4.615299 [[2]] [1] 3.011078 5.549246 [[3]] [1] 8.5230253 3.4520337 0.1495026 [[4]] [1] 5.9855820 7.7427082 2.9215029 0.3520867 </syntaxhighlight><code>lapply</code> 也可以使用匿名函数<syntaxhighlight lang="r" line="1"> # 声明包含两个矩阵的列表 > x <- list(a = matrix(1:4, 2, 2), b = matrix(1:6, 3, 2)) > x $a [,1] [,2] [1,] 1 3 [2,] 2 4 $b [,1] [,2] [1,] 1 4 [2,] 2 5 [3,] 3 6 # 提取每个矩阵的第一列的匿名函数 > lapply(x, function(elt) elt[,1]) $a [1] 1 2 $b [1] 1 2 3 </syntaxhighlight> == sapply == <code>sapply</code> 会尽可能的简化 <code>lapply</code> 函数的结果。 * 如果列表中的每个元素的长度为1,结果会返回一个向量。 * 如果列表中的每个元素都是长度大于1的等长向量,结果会返回一个矩阵。 * 如果无法简化,返回列表。 <syntaxhighlight lang="r" line="1"> > x <- list(a = 1:4, b = rnorm(10), c = rnorm(20, 1), d = rnorm(100, 5)) > lapply(x, mean) $a [1] 2.5 $b [1] 0.3727818 $c [1] 1.17464 $d [1] 5.07108 > sapply(x, mean) a b c d 2.5000000 0.3727818 1.1746396 5.0710795 > mean(x) [1] NA Warning message: In mean.default(x) : argument is not numeric or logical: returning NA </syntaxhighlight> == apply == <code>apply</code> 对数组或矩阵执行指定的函数(通常是匿名函数)。 * 通常对矩阵的一行或一列操作 * 对一组数进行操作,如计算矩阵的行平均值或列平均值。 * 不一定比循环快,但只要一行。 <syntaxhighlight lang="r" line="1"> > str(apply) function (X, MARGIN, FUN, ...) </syntaxhighlight> * <code>X</code> 是一个数组 * <code>MARGIN</code> 是整数型向量,指定对哪一维(如矩阵的行或列)进行操作。 * <code>FUN</code> 是用哪个函数进行操作 * ... 是传递给 <code>FUN</code> 的其他参数 <syntaxhighlight lang="r" line="1"> > x <- matrix(rnorm(200), 20, 10) > apply(x, 2, mean) [1] 0.167162527 -0.079293974 -0.062300596 -0.328406829 0.290078933 [6] 0.480642185 0.009369719 -0.018753792 0.194263160 -0.042819273 > apply(x, 1, sum) [1] -0.6314381 1.3082838 -0.9322577 9.2538844 -6.0182467 4.2462860 [7] 1.3619095 -1.6376867 -2.0452763 -3.1957812 -2.6102388 3.8403223 [13] -1.0428887 3.0235110 1.1093232 3.0340000 0.5430936 1.1590106 [19] 0.4819350 0.9510959 </syntaxhighlight> == 列/行求和与平均值 == 对于计算矩阵维度的和与平均值,有更快捷的函数。 * <code>rowSums</code> = <code>apply(x, 1, sum)</code> * <code>rowMeans</code> = <code>apply(x, 1, mean)</code> * <code>colSums</code> = <code>apply(x, 2, sum)</code> * <code>colMeans</code> = <code>apply(x, 2, mean)</code> 这些函数速度很快,在不处理大矩阵的时,没有区别。 ---- == 其他使用apply的方法 == 计算一个矩阵行的分位数。<syntaxhighlight lang="r" line="1"> > x <- matrix(rnorm(200), 20, 10) > apply(x, 1, quantile, probs = c(0.25, 0.75)) [,1] [,2] [,3] [,4] [,5] [,6] [,7] 25% 0.09678483 -1.252172 -0.5594222 0.3003727 -0.5394311 -0.7213852 -0.6946071 75% 1.21133570 1.125509 0.4887024 1.2867236 0.4701446 0.3500056 0.1762477 [,8] [,9] [,10] [,11] [,12] [,13] [,14] 25% -0.2561037 -0.2304411 -0.9268922 -1.079129 -0.7953414 -0.4770530 -0.379590 75% 0.6587894 1.5569296 1.2895396 1.142885 -0.1241847 0.7192662 0.545214 [,15] [,16] [,17] [,18] [,19] [,20] 25% -0.008474735 -0.3288624 -0.5923715 -0.3822122 -0.6172781 -1.2056816 75% 0.998829133 1.0367678 0.8497671 0.6897986 0.3691122 0.1918069 </syntaxhighlight>求数组中矩阵的平均值<syntaxhighlight lang="r" line="1"> > a <- array(rnorm(2 * 2 * 10), c(2, 2, 10)) > apply(a, c(1, 2), mean) [,1] [,2] [1,] 0.006563965 -0.4093383 [2,] 0.057019258 0.1777483 > rowMeans(a, dims = 2) [,1] [,2] [1,] 0.006563965 -0.4093383 [2,] 0.057019258 0.1777483 </syntaxhighlight> == mapply == <code>mapply</code> 称为多变量(multivariate)apply可以接收指定函数的一组参数并行计算。<syntaxhighlight lang="r" line="1"> > str(mapply) function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) </syntaxhighlight> * <code>FUN</code> 是用来批处理的函数 * ... 用来批处理的参数 * <code>MoreArgs</code> 是 <code>FUN</code>函数的其他参数 * <code>SIMPLIFY</code> 设置是否简化参数 例如要生成包含四列的列表,分别包含4个1,3个2,2个3,1个4四个向量。 <code>list(rep(1, 4), rep(2, 3), rep(3, 2), rep(4, 1))</code> 可以使用mapply来简化操作<syntaxhighlight lang="r" line="1"> > mapply(rep, 1:4, 4:1) [[1]] [1] 1 1 1 1 [[2]] [1] 2 2 2 [[3]] [1] 3 3 [[4]] [1] 4 </syntaxhighlight> == 函数的向量化操作 == <syntaxhighlight lang="r" line="1"> # 声明一个函数noise > noise <- function(n, mean, sd) { rnorm(n, mean, sd) } # 使用单个参数操作 > noise(5, 1, 2) [1] 0.1629689 2.0816275 2.4775372 -0.9368394 0.9255463 # 使用多个参数操作,结果不是预期的 > noise(1:5, 1:5, 2) [1] 1.643462 2.794333 2.914787 5.082487 5.377841 </syntaxhighlight> == 向量化操作 == <syntaxhighlight lang="r" line="1"> > mapply(noise, 1:5, 1:5, 2) [[1]] [1] 2.591011 [[2]] [1] 1.851819 1.861633 [[3]] [1] 2.7667496 0.4649369 5.8556238 [[4]] [1] 5.275667 2.682882 4.043813 4.366316 [[5]] [1] 6.257788 3.618693 4.407559 6.736056 6.720434 </syntaxhighlight>等同于<syntaxhighlight lang="r" line="1"> list(noise(1, 1, 2), noise(2, 2, 2), noise(3, 3, 2), noise(4, 4, 2), noise(5, 5, 2)) </syntaxhighlight> == tapply == <code>tapply</code> 对向量的子集执行批处理操作。<syntaxhighlight lang="r" line="1"> > str(tapply) function (X, INDEX, FUN = NULL, ..., simplify = TRUE) </syntaxhighlight> * <code>X</code> 是一个向量 * <code>INDEX</code> 因子或因子的列表(或与因子相关) * <code>FUN</code> 批处理的函数 * ... 其他传递给 <code>FUN</code> 函数 * <code>simplify</code> 是否简化结果 分组取平均值。<syntaxhighlight lang="r" line="1"> > x <- c(rnorm(10), runif(10), rnorm(10, 1)) > f <- gl(3, 10) > f [1] 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 Levels: 1 2 3 > tapply(x, f, mean) 1 2 3 0.1045255 0.4867243 0.9131191 </syntaxhighlight>不简化分组取平均值的结果<syntaxhighlight lang="r" line="1"> > tapply(x, f, mean, simplify = FALSE) $`1` [1] 0.1045255 $`2` [1] 0.4867243 $`3` [1] 0.9131191 </syntaxhighlight>找到每组的数值范围。<syntaxhighlight lang="r" line="1"> > tapply(x, f, range) $`1` [1] -0.8040998 1.0022698 $`2` [1] 0.04577595 0.95238798 $`3` [1] -0.4422177 2.3863979 </syntaxhighlight> == split == <code>split</code> 根据因子向量或因子列表分组。<syntaxhighlight lang="r" line="1"> > str(split) function (x, f, drop = FALSE, ...) </syntaxhighlight> * <code>x</code> 可以是向量、列表、数据框 * <code>f</code> 因子或因子列表 * <code>drop</code> 是否去除因子水平为空的结果 <syntaxhighlight lang="r" line="1"> > split(x, f) $`1` [1] 0.06417511 0.77601085 1.66855356 1.38744423 [5] -0.90908770 0.39727163 -2.13528805 0.29087121 [9] 0.82936584 0.53773723 $`2` [1] 0.6646064 0.4408925 0.3199122 0.2156969 0.8358507 [6] 0.1408568 0.4088236 0.2258691 0.9606134 0.7945027 $`3` [1] 0.65276220 2.46645556 2.72756544 1.77246304 [5] 2.94941952 0.11977102 -0.04283368 2.36610370 [9] 0.44573942 2.31295594 </syntaxhighlight><code>lapply</code> 和 <code>split</code> 配合使用的例子。<syntaxhighlight lang="r" line="1"> > lapply(split(x, f), mean) $`1` [1] 0.2907054 $`2` [1] 0.5007624 $`3` [1] 1.57704 </syntaxhighlight> == 拆分数据框 == <syntaxhighlight lang="r" line="1"> > library(datasets) > head(airquality) Ozone Solar.R Wind Temp Month Day 1 41 190 7.4 67 5 1 2 36 118 8.0 72 5 2 3 12 149 12.6 74 5 3 4 18 313 11.5 62 5 4 5 NA NA 14.3 56 5 5 6 28 NA 14.9 66 5 6 > s <- split(airquality, airquality$Month) > lapply(s, function(x) colMeans(x[, c("Ozone", "Solar.R", "Wind")])) $`5` Ozone Solar.R Wind NA NA 11.62258 $`6` Ozone Solar.R Wind NA 190.16667 10.26667 $`7` Ozone Solar.R Wind NA 216.483871 8.941935 $`8` Ozone Solar.R Wind NA NA 8.793548 $`9` Ozone Solar.R Wind NA 167.4333 10.1800 > sapply(s, function(x) colMeans(x[, c("Ozone", "Solar.R", "Wind")])) 5 6 7 8 9 Ozone NA NA NA NA NA Solar.R NA 190.16667 216.483871 NA 167.4333 Wind 11.62258 10.26667 8.941935 8.793548 10.1800 > sapply(s, function(x) colMeans(x[, c("Ozone", "Solar.R", "Wind")], na.rm = TRUE)) 5 6 7 8 9 Ozone 23.61538 29.44444 59.115385 59.961538 31.44828 Solar.R 181.29630 190.16667 216.483871 171.857143 167.43333 Wind 11.62258 10.26667 8.941935 8.793548 10.18000 </syntaxhighlight> == 将数据分割到多个水平 == <syntaxhighlight lang="r" line="1"> > x <- rnorm(10) > f1 <- gl(2, 5) > f2 <- gl(5, 2) > f1 [1] 1 1 1 1 1 2 2 2 2 2 Levels: 1 2 > f2 [1] 1 1 2 2 3 3 4 4 5 5 Levels: 1 2 3 4 5 > interaction(f1, f2) [1] 1.1 1.1 1.2 1.2 1.3 2.3 2.4 2.4 2.5 2.5 Levels: 1.1 2.1 1.2 2.2 1.3 2.3 1.4 2.4 1.5 2.5 </syntaxhighlight><code>interaction</code> 函数可以创建没有值的水平。<syntaxhighlight lang="r" line="1"> > str(split(x, list(f1, f2))) List of 10 $ 1.1: num [1:2] -1.073 -0.572 $ 2.1: num(0) $ 1.2: num [1:2] -0.435 -0.976 $ 2.2: num(0) $ 1.3: num 0.201 $ 2.3: num 0.691 $ 1.4: num(0) $ 2.4: num [1:2] 0.498 0.333 $ 1.5: num(0) $ 2.5: num [1:2] -0.00797 -0.1332 </syntaxhighlight>去除无值的分组。<syntaxhighlight lang="r" line="1"> > str(split(x, list(f1, f2), drop = TRUE)) List of 6 $ 1.1: num [1:2] -1.073 -0.572 $ 1.2: num [1:2] -0.435 -0.976 $ 1.3: num 0.201 $ 2.3: num 0.691 $ 2.4: num [1:2] 0.498 0.333 $ 2.5: num [1:2] -0.00797 -0.1332 </syntaxhighlight> = 异常处理 = 有时R会返回一些信息 * <code>message</code>: <code>message</code> 函数生成的一般提示或诊断信息 * <code>warning</code>: 有些代码书写不恰当,但不会对结果造成太大影响(可忽略);函数执行期间的提示信息;通过 <code>warning</code> 函数生成警告信息 * <code>error</code>: 程序运行出现错误,运行终止,通过 <code>stop</code> 函数输出 * <code>condition</code>: 选项,用于不能预先知道某些结果时;程序员可以创建自定义条件 == Warning == <syntaxhighlight lang="r" line="1"> > log(-1) [1] NaN Warning message: In log(-1) : NaNs produced </syntaxhighlight><syntaxhighlight lang="r" line="1"> > printmessage <- function(x) { if(x > 0) print("x is greater than zero") else print("x is less than or equal to zero") invisible(x) } > printmessage(1) [1] "x is greater than zero" > printmessage(NA) Error in if (x > 0) print("x is greater than zero") else print("x is less than or equal to zero") : missing value where TRUE/FALSE needed > printmessage2 <- function(x) { if(is.na(x)) print("x is a missing value!") else if(x > 0) print("x is greater than zero") else print("x is less than or equal to zero") invisible(x) } > x <- log(-1) Warning message: In log(-1) : NaNs produced > printmessage2(x) [1] "x is a missing value!" </syntaxhighlight>处理函数的报错 * 注意输入与函数的调用 * 哪些输出,信息或结果是正确的 * 注意当前的输出 * 当前输出与预期结果的差异 * 一开始预想的预期结果是否正确 * 什么情况下会再次出现该问题 == R中的Debug调试工具 == R自带的调试函数: * <code>traceback</code>: 当error产生时,调用该函数,输出调用日志 * <code>debug</code>: 将一个函数标记为 “debug” 模式,允许一行一行运行函数就行调试 * <code>browser</code>: 挂起一个函数的运行(无论该函数是否被调用),将该函数加入调试模式 * <code>trace</code>: 将调试代码插入函数的指定位置 * <code>recover</code>: 调整报错的信息,更快地定位函数 这些函数是专门为交互式编程调试设计,将这些调试工具封装为函数。含有一些更为直接的方法,通过调用print/cat函数输出提示信息。 ---- == traceback == <syntaxhighlight lang="r" line="1"> > mean(x) Error in mean(x) : object 'x' not found > traceback() 1: mean(x) </syntaxhighlight><syntaxhighlight lang="r" line="1"> > lm(y ~ x) Error in eval(predvars, data, env) : object 'y' not found > traceback() 7: eval(predvars, data, env) 6: eval(predvars, data, env) 5: model.frame.default(formula = y ~ x, drop.unused.levels = TRUE) 4: stats::model.frame(formula = y ~ x, drop.unused.levels = TRUE) 3: eval(mf, parent.frame()) 2: eval(mf, parent.frame()) 1: lm(y ~ x) </syntaxhighlight> == 调试 == <syntaxhighlight lang="r" line="1"> > debug(lm) > lm(y ~ x) debugging in: lm(y ~ x) debug: { ret.x <- x ret.y <- y cl <- match.call() mf <- match.call(expand.dots = FALSE) m <- match(c("formula", "data", "subset", "weights", "na.action", "offset"), names(mf), 0L) mf <- mf[c(1L, m)] mf$drop.unused.levels <- TRUE mf[[1L]] <- quote(stats::model.frame) mf <- eval(mf, parent.frame()) if (method == "model.frame") return(mf) else if (method != "qr") warning(gettextf("method = '%s' is not supported. Using 'qr'", method), domain = NA) mt <- attr(mf, "terms") y <- model.response(mf, "numeric") w <- as.vector(model.weights(mf)) if (!is.null(w) && !is.numeric(w)) stop("'weights' must be a numeric vector") offset <- as.vector(model.offset(mf)) if (!is.null(offset)) { if (length(offset) != NROW(y)) stop(gettextf("number of offsets is %d, should equal %d (number of observations)", length(offset), NROW(y)), domain = NA) } if (is.empty.model(mt)) { x <- NULL z <- list(coefficients = if (is.matrix(y)) matrix(NA_real_, 0, ncol(y)) else numeric(), residuals = y, fitted.values = 0 * y, weights = w, rank = 0L, df.residual = if (!is.null(w)) sum(w != 0) else if (is.matrix(y)) nrow(y) else length(y)) if (!is.null(offset)) { z$fitted.values <- offset z$residuals <- y - offset } } else { x <- model.matrix(mt, mf, contrasts) z <- if (is.null(w)) lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) else lm.wfit(x, y, w, offset = offset, singular.ok = singular.ok, ...) } class(z) <- c(if (is.matrix(y)) "mlm", "lm") z$na.action <- attr(mf, "na.action") z$offset <- offset z$contrasts <- attr(x, "contrasts") z$xlevels <- .getXlevels(mt, mf) z$call <- cl z$terms <- mt if (model) z$model <- mf if (ret.x) z$x <- x if (ret.y) z$y <- y if (!qr) z$qr <- NULL z } Browse[2]> Browse[2]> n debug: ret.x <- x Browse[2]> ret.x <- x Browse[2]> n debug: ret.y <- y Browse[2]> ret.y <- y Browse[2]> n debug: cl <- match.call() Browse[2]> cl <- match.call() Browse[2]> n debug: mf <- match.call(expand.dots = FALSE) Browse[2]> mf <- match.call(expand.dots = FALSE) Browse[2]> n debug: m <- match(c("formula", "data", "subset", "weights", "na.action", "offset"), names(mf), 0L) # 退出调试模式 Browse[2]> Q </syntaxhighlight> == recover == <syntaxhighlight lang="r" line="1"> > options(error = recover) > read.csv("nosuchfile") Error in file(file, "rt") : cannot open the connection In addition: Warning message: In file(file, "rt") : cannot open file 'nosuchfile': No such file or directory Enter a frame number, or 0 to exit 1: read.csv("nosuchfile") 2: read.table(file = file, header = header, sep = sep, quote = quote, dec = dec, f 3: file(file, "rt") Selection: Selection: 0 > </syntaxhighlight> == 小结 == * R有三个主要的显示错误、提示信息的函数,分别为:<code>message</code>, <code>warning</code>, <code>error</code> ** 程序员的世界只有 <code>error</code> ,只有 <code>error</code> 需要调试 * 在分析报错的函数时,首先确认问题的可重复性,明确期望结果、输出与期望结果的差异 * 交互式调试工具 <code>traceback</code>, <code>debug</code>, <code>browser</code>, <code>trace</code> 和 <code>recover</code> 可以帮助判断函数中错误代码 * 调试工具不能取代思考 = 生成随机数 = R中的概率分布函数 * <code>rnorm</code>: 根据给定的平均值和标准偏差生成随机正态变量 * <code>dnorm</code>: 计算一个点或点向量的正态概率密度(根据给定的平均值/ 标准偏差) * <code>pnorm</code>: 生成正态累积分布函数 * <code>rpois</code>: 根据给定的比率生成随机泊松分布随机数 每种概率分布函数通常有四种前缀 * <code>d</code> 密度 * <code>r</code> 生成随机数 * <code>p</code> 累积分布 * <code>q</code> 分位数函数 生成正态分布可以使用以下四个函数<syntaxhighlight lang="r" line="1"> dnorm(x, mean = 0, sd = 1, log = FALSE) pnorm(q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE) qnorm(p, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE) rnorm(n, mean = 0, sd = 1) </syntaxhighlight>如果<math>\Phi</math>是标准正态累积分布i, 那么<code>pnorm(q)</code> = <math>\Phi(q)</math> , <code>qnorm(p)</code> = <math>\phi^{-1}(p)</math>。<syntaxhighlight lang="r" line="1"> > x <- rnorm(10) > x [1] 0.3357161 -0.4786192 0.3952794 -1.5230122 -0.6496318 -1.2714863 0.6367861 [8] -0.8809022 -0.4377379 -0.3063769 > x <- rnorm(10, 20, 2) > x [1] 16.15086 15.89892 23.22139 20.60856 25.15596 18.85948 19.50671 20.81849 [9] 17.82214 18.43590 > summary(x) Min. 1st Qu. Median Mean 3rd Qu. Max. 15.90 17.98 19.18 19.65 20.77 25.16 </syntaxhighlight>使用 <code>set.seed</code> 函数设定随机数种子以保证结果的可重复性<syntaxhighlight lang="r" line="1"> > set.seed(1) > rnorm(5) [1] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 > rnorm(5) [1] -0.8204684 0.4874291 0.7383247 0.5757814 -0.3053884 > set.seed(1) > rnorm(5) [1] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 </syntaxhighlight>在进行模拟时最好设置随机数种子 == 生成泊松分布数据 == <syntaxhighlight lang="r" line="1"> > rpois(10, 1) [1] 0 0 1 1 2 1 1 4 1 2 > rpois(10, 2) [1] 4 1 2 0 1 1 0 1 4 1 > rpois(10, 20) [1] 19 19 24 23 22 24 23 20 11 22 ## 累积分布‘ ## x <= 2的概率分布 > ppois(2, 2) [1] 0.6766764 ## x <= 4的概率分布 > ppois(4, 2) [1] 0.947347 ## x <= 6的概率分布 > ppois(6, 2) [1] 0.9954662 </syntaxhighlight> == 通过线性模型生成随机数 == 通过<math>y = \beta_0 + \beta_1 x + \varepsilon</math>模型生成随机数。 已知<math>\varepsilon\sim\mathcal{N}(0, 2^2)</math>. Assume <math>x\sim\mathcal{N}(0,1^2)</math>, <math>\beta_0 = 0.5</math> , <math>\beta_1 = 2</math>。 [[File:线性模型生成随机数1.png|缩略图|线性模型生成随机数1]] <syntaxhighlight lang="r" line="1"> > set.seed(20) > x <- rnorm(100) > e <- rnorm(100, 0, 2) > y <- 0.5 + 2 * x + e > summary(y) Min. 1st Qu. Median Mean 3rd Qu. Max. -6.4084 -1.5402 0.6789 0.6893 2.9303 6.5052 > plot(x, y) </syntaxhighlight>当 <code>x</code> 为0或1时 [[File:线性模型生成随机数2.png|缩略图|线性模型生成随机数2]] <syntaxhighlight lang="r" line="1"> set.seed(10) x <- rbinom(100, 1, 0.5) e <- rnorm(100, 0, 2) y <- 0.5 + 2 * x + e plot(x, y) </syntaxhighlight> == 通过广义线性模型生成随机数 == 模拟泊松模型:Y ~ Poisson(μ) log μ = <math>\beta_0 + \beta_1x</math> 已知<math>\beta_0 = 0.5</math>和<math>\beta_1 = 0.3</math>。 使用 <code>rpois</code> 函数生成随机数 [[File:泊松分布随机数.png|缩略图]] <syntaxhighlight lang="r" line="1"> set.seed(1) x <- rnorm(100) log.mu <- 0.5 + 0.3 * x y <- rpois(100, exp(log.mu)) summary(y) plot(x, y) </syntaxhighlight> == 生成随机样本 == <code>sample</code> 函数可以从一个指定的组合中生成随机样本。<syntaxhighlight lang="r" line="1"> > set.seed(1) > sample(1:10, 4) [1] 3 4 5 7 > sample(1:10, 4) [1] 3 9 8 5 > sample(letters, 5) [1] "q" "b" "e" "x" "p" ## 随机排列组合 > sample(1:10) [1] 4 7 10 6 9 2 8 3 1 5 > sample(1:10) [1] 2 3 4 1 9 5 10 8 6 7 ## 随机替换,生成可重复的样本 > sample(1:10, replace = TRUE) ## Sample w/replacement [1] 2 9 7 8 2 8 5 9 7 8 </syntaxhighlight> == 小结 == * <code>r*</code> 系列函数根据特殊的概率分布生成随机数 * 内置的正态分布:标准,泊松,二项式,指数, 伽马等 * <code>sample</code> 函数提取随机样本 * 通过set.seed函数生成随机数生成种子,保证结果的可重复性 = 程序设计 = * 检查程序代码不同部分的执行时间对于代码优化很有用。 * 通常代码运行一次会表现良好,但如果你将其放如1000次循环中,运行效率是否受到影响,这时分析运行时间很有用。 == 优化代码 == * 影响代码执行速度的最大因素是代码花费最多时间的部分 * 不通过程序执行时间分析很难完成 <blockquote>We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil(过早最优化是万恶的根源)--Donald Knuth</blockquote> ---- == 优化的一般目标 == * 先设计后优化 * 过早优化是万恶的根源 * 操作(收集数据),不要猜测 * 科学家的基本素养 == 使用 <code>system.time()</code> == * 接收任意R表达是作为输入,返回运行该表达式所需要的时间 * 计算执行表达所需要的时间(秒) ** 如果有错误,返回报错前的时间 * 返回 <code>proc_time</code> 类的对象 ** '''user time''': CPU时间 ** '''elapsed time''': 总流逝时间 * 对于直接的计算任务,user time和elapsed time很接近 * 如果CPU花费大量的等待时间,elapsed time会比user time大很多 * 如果机器拥有多线程elapsted time会比user time小很多 ** 多线程BLAS库 (vecLib/Accelerate, ATLAS, ACML, MKL) ** 多线程包'''parallel''' <syntaxhighlight lang="r" line="1"> > system.time(readLines("http://www.baidu.com")) user system elapsed 0.026 0.010 1.231 > hilbert <- function(n) { i <- 1:n 1 / outer(i - 1, i, "+") } > x <- hilbert(1000) > system.time(svd(x)) user system elapsed 2.722 0.029 2.792 </syntaxhighlight> == 计算更长表达式的运行时间 == <syntaxhighlight lang="r" line="1"> > system.time({ n <- 1000 r <- numeric(n) for (i in 1:n) { x <- rnorm(n) r[i] <- mean(x) } }) user system elapsed 0.079 0.005 0.086 </syntaxhighlight> == <code>system.time()</code>的局限 == <code>system.time()</code> 允许测试特定的函数或代码块的运行时间,这是在知道问题在哪的时候,但如果不知道问题在哪呢? ---- == R 分析器 == <code>Rprof()</code> 函数可以启动分析,<code>summaryRprof()</code> 函数可以总结 <code>Rprof()</code> 的输出结果,不要同时使用 <code>system.time()</code> 和 <code>Rprof()</code> 函数 * Rprof() 有规律地追踪各个函数的调用,采样收集每个函数所花费的时间 * 默认采样间隔为0.02秒 * 如果代码已经运行很快,你就不需要使用这些分析函数 == R分析的原始输出 == <syntaxhighlight lang="r" line="1"> ## lm(y ~ x) sample.interval=10000 "list" "eval" "eval" "model.frame.default" "model.frame" "eval" "eval" "lm" "list" "eval" "eval" "model.frame.default" "model.frame" "eval" "eval" "lm" "list" "eval" "eval" "model.frame.default" "model.frame" "eval" "eval" "lm" "list" "eval" "eval" "model.frame.default" "model.frame" "eval" "eval" "lm" "na.omit" "model.frame.default" "model.frame" "eval" "eval" "lm" "na.omit" "model.frame.default" "model.frame" "eval" "eval" "lm" "na.omit" "model.frame.default" "model.frame" "eval" "eval" "lm" "na.omit" "model.frame.default" "model.frame" "eval" "eval" "lm" "na.omit" "model.frame.default" "model.frame" "eval" "eval" "lm" "na.omit" "model.frame.default" "model.frame" "eval" "eval" "lm" "na.omit" "model.frame.default" "model.frame" "eval" "eval" "lm" "lm.fit" "lm" "lm.fit" "lm" "lm.fit" "lm" </syntaxhighlight> == 使用 <code>summaryRprof()</code> == * <code>summaryRprof()</code> 计算每个函数的运行时间 * 两种汇总方法 ** "by.total" 使用每个函数运行时间除以总运行时间 ** "by.self" 减去调用的时间 == 小结 == * <code>Rprof()</code> 评估R代码的运行 * <code>summaryRprof()</code> 汇总<code>Rprof()</code>的结果,给出每个函数运行的时间百分比(两种汇总方法)
返回
R/R语法
。
导航菜单
个人工具
登录
命名空间
页面
讨论
不转换
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
特殊页面
工具
链入页面
相关更改
页面信息