这是 R(“GNU S”)的简介,R 是一种用于统计计算和图形的语言和环境。R 与屡获殊荣的1 S 系统类似,该系统由贝尔实验室的 John Chambers 等人开发。它提供了各种统计和图形技术(线性与非线性建模、统计检验、时间序列分析、分类、聚类,...)。
本手册提供了有关数据类型、编程元素、统计建模和图形的信息。
本手册适用于 R 4.3.3 版(2024-02-29)。
版权所有 © 1990 W. N. Venables
版权所有 © 1992 W. N. Venables 和 D. M. Smith
版权所有 © 1997 R. Gentleman 和 R. Ihaka
版权所有 © 1997、1998 M. Maechler
版权所有 © 1999–2023 R 核心团队
在所有副本上保留版权声明和此许可声明的前提下,允许制作和分发本手册的逐字副本。
在逐字复制的条件下,允许复制和分发本手册的修改版本,前提是整个派生作品在与本声明相同的许可声明的条款下进行分发。
在上述修改版本条件下,允许复制和分发本手册的翻译版本,但此许可声明可以由 R 核心团队批准的翻译中陈述。
这份 R 简介源自比尔·韦纳布尔斯和大卫·M·史密斯在 1990-2 年在阿德莱德大学时编写的描述 S 和 S-PLUS 环境的原始笔记。我们做了一些小的更改以反映 R 和 S 程序之间的差异,并扩展了一些内容。
我们要向比尔·韦纳布尔斯(和大卫·史密斯)表示衷心的感谢,感谢他们允许以这种方式分发此修改版的笔记,并一直支持 R。
我们始终欢迎评论和更正。请将电子邮件发送至 [email protected]。
大多数 R 新手都会从附录 A 中的介绍性会话开始。这应该有助于熟悉 R 会话的风格,更重要的是,可以立即反馈实际发生的情况。
许多用户主要会使用 R 的图形功能。请参见 图形过程,几乎可以在任何时候阅读,不必等到消化完所有前面的部分。
R 是一套用于数据处理、计算和图形显示的集成软件工具。除其他功能外,它还具有
术语“环境”旨在将其描述为一个经过全面规划和连贯的系统,而不是像其他数据分析软件那样,是逐渐积累的非常具体且不灵活的工具。
R 在很大程度上是用于开发交互式数据分析新方法的工具。它发展迅速,并已通过大量程序包进行了扩展。但是,大多数用 R 编写的程序本质上都是短暂的,是为单一数据分析编写的。
R 可以看作是 S 语言的一种实现,该语言由贝尔实验室的 Rick Becker、John Chambers 和 Allan Wilks 开发,也是S-PLUS 系统的基础。
S 语言的演变由 John Chambers 和合作者撰写的四本书来表征。对于 R,基本参考书是 Richard A. Becker、John M. Chambers 和 Allan R. Wilks 撰写的新 S 语言:数据分析和图形的编程环境。S 1991 年版本的新功能由 John M. Chambers 和 Trevor J. Hastie 编辑的S 中的统计模型中进行了介绍。方法包的正式方法和类基于 John M. Chambers 在数据编程中描述的内容。有关确切参考信息,请参见参考信息。
现在有很多书描述如何使用 R 进行数据分析和统计,并且 S/S-PLUS 的文档通常可以与 R 一起使用,同时牢记 S 实现之间的差异。请参见R 统计系统常见问题解答中的R 有哪些文档?。
我们对 R 环境的介绍并未提及统计,但许多人将 R 用作统计系统。我们更愿意将它视为一个环境,其中已实现许多经典和现代统计技术。其中一些内置于 R 基本环境中,但许多以包的形式提供。R 附带约 25 个包(称为“标准”和“推荐”包),还有更多包可通过CRAN系列互联网网站(通过https://CRAN.R-project.org)和其他地方获得。稍后将提供有关包的更多详细信息(请参见包)。
大多数经典统计和许多最新方法都可以与 R 一起使用,但用户可能需要做好一些准备工作来查找它们。
S(因此还有 R)与其他主要统计系统在理念上存在着重要的差异。在 S 中,统计分析通常作为一系列步骤来完成,中间结果存储在对象中。因此,虽然 SAS 和 SPSS 会从回归或判别分析中给出大量输出,但 R 会给出最少量的输出,并将结果存储在拟合对象中,以便通过其他 R 函数进行后续查询。
使用 R 最方便的方式是在运行窗口系统的图形工作站上。本指南针对拥有此类设施的用户。特别是,我们偶尔会提到在 X 窗口系统上使用 R,尽管所述内容的大部分通常适用于 R 环境的任何实现。
大多数用户会发现,有时有必要直接与计算机上的操作系统进行交互。在本指南中,我们主要讨论与 UNIX 机器上的操作系统的交互。如果你在 Windows 或 macOS 下运行 R,则需要进行一些小的调整。
设置工作站以充分利用 R 的可自定义特性是一个直接但有些繁琐的过程,此处将不再进一步考虑。遇到困难的用户应寻求当地专家的帮助。
当你使用 R 程序时,它会在需要输入命令时发出提示。默认提示为“>
”,在 UNIX 中它可能与 shell 提示相同,因此可能看起来什么都没有发生。但是,正如我们所看到的,如果你愿意,可以轻松更改为不同的 R 提示。我们将假设 UNIX shell 提示为“$
”。
在 UNIX 下使用 R 时,建议首次执行以下过程
$ mkdir work $ cd work
$ R
> q()
此时系统会询问您是否要保存 R 会话中的数据。在某些系统上,这会弹出一个对话框,而在其他系统上,您将收到一个文本提示,您可以回复 yes、no 或 cancel(使用单个字母缩写即可)来在退出前保存数据、不保存而退出或返回 R 会话。保存的数据将在将来的 R 会话中可用。
后续 R 会话很简单。
$ cd work $ R
q()
命令终止。
要在 Windows 下使用 R,遵循的过程基本上是相同的。创建一个文件夹作为工作目录,并在 R 快捷方式的 开始于 字段中设置该文件夹。然后双击该图标启动 R。
R 具有类似于 UNIX 的 man
功能的内置帮助功能。要获取有关任何特定命名函数(例如 solve
)的更多信息,命令是
> help(solve)
另一种方法是
> ?solve
对于由特殊字符指定的特性,参数必须用双引号或单引号括起来,使其成为“字符字符串”:对于一些具有语法含义的单词,包括 if
、for
和 function
,这也是必需的。
> help("[[")
两种形式的引号都可以用来转义对方,就像字符串 "It's important"
中一样。我们的惯例是优先使用双引号。
在大多数 R 安装中,可以通过运行以下命令以 HTML 格式获得帮助
> help.start()
这将启动一个 Web 浏览器,允许使用超链接浏览帮助页面。在 UNIX 上,后续帮助请求将发送到基于 HTML 的帮助系统。由 help.start()
加载的页面中的“搜索引擎和关键字”链接特别有用,因为它包含一个高级概念列表,用于搜索可用函数。这可能是一种快速了解情况并理解 R 提供的广度的绝佳方式。
help.search
命令(或 ??
)允许以多种方式搜索帮助。例如,
> ??solve
尝试 ?help.search
以获取详细信息和更多示例。
通常可以通过以下方式运行帮助主题中的示例
> example(topic)
R 的 Windows 版本有其他可选的帮助系统:使用
> ?help
了解更多详细信息。
从技术角度来看,R 是一种表达式语言,语法非常简单。它区分大小写,就像大多数基于 UNIX 的软件包一样,因此A
和a
是不同的符号,它们表示不同的变量。可以在 R 名称中使用的符号集取决于 R 运行所在的操作系统和国家/地区(从技术角度上讲,取决于所使用的区域设置)。通常允许使用所有字母数字符号2(在某些国家/地区,还包括带重音符号的字母)以及“.
”和“_
”,但有一个限制,即名称必须以“.
”或字母开头,如果以“.
”开头,则第二个字符不能是数字。名称的长度实际上不受限制。
基本命令由表达式或赋值组成。如果表达式作为命令给出,则会对其求值、打印(除非专门将其设为不可见),并且会丢失该值。赋值也会对表达式求值,并将该值传递给变量,但不会自动打印结果。
命令由分号(“;
”)或换行符分隔。可以通过大括号(“{
”和“}
”)将基本命令组合成一个复合表达式。注释几乎可以放在3任何地方,以井号(“#
”)开头,该行末尾的所有内容都是注释。
如果一行末尾的命令不完整,R 会给出不同的提示,默认情况下
+
在第二行及后续行,并继续读取输入,直到命令在语法上完整为止。用户可以更改此提示。我们通常会省略续行提示,并通过简单的缩进来表示续行。
在控制台中输入的命令行限制4为大约 4095 个字节(不是字符)。
在许多版本的 UNIX 和 Windows 上,R 提供了一种机制,用于召回和重新执行之前的命令。可以使用键盘上的垂直箭头键向前和向后滚动命令历史记录。通过这种方式找到命令后,可以使用水平箭头键在命令中移动光标,并可以使用DEL键删除字符,或使用其他键添加字符。稍后会提供更多详细信息:请参阅命令行编辑器。
UNIX 下的召回和编辑功能具有高度可定制性。你可以通过阅读 readline 库的手册条目来了解如何执行此操作。
或者,Emacs 文本编辑器通过 ESS(Emacs Speaks Statistics)提供了更通用的支持机制,以便与 R 交互式地工作。请参阅 R 统计系统常见问题解答 中的 R 和 Emacs。
如果命令5存储在外部文件中,比如工作目录 work 中的 commands.R,则可以使用以下命令在 R 会话中随时执行这些命令
> source("commands.R")
对于 Windows,Source 也可在 File 菜单中找到。函数 sink
,
> sink("record.lis")
会将控制台的所有后续输出转至外部文件 record.lis。命令
> sink()
会将其再次还原到控制台。
R 创建和处理的实体称为对象。这些对象可以是变量、数字数组、字符字符串、函数或由这些组件构建的更通用的结构。
在 R 会话期间,对象将按名称创建并存储(我们将在下一部分讨论此过程)。R 命令
> objects()
(或者 ls()
) 可用于显示当前存储在 R 中的(大多数)对象的名称。当前存储的对象集合称为工作空间。
要移除对象,可以使用函数 rm
> rm(x, y, z, ink, junk, temp, foo, bar)
在 R 会话期间创建的所有对象都可以永久存储在文件中,以便在将来的 R 会话中使用。在每个 R 会话结束时,您都有机会保存当前所有可用的对象。如果您表示要执行此操作,则对象将写入名为 .RData6 的文件(位于当前目录中),并且会话中使用的命令行将保存到名为 .Rhistory 的文件中。
当稍后从同一目录启动 R 时,它会从该文件重新加载工作空间。同时,将重新加载关联的命令历史记录。
建议您为使用 R 进行的分析使用单独的工作目录。在分析期间,通常会创建名称为 x
和 y
的对象。此类名称在单个分析的上下文中通常有意义,但在同一目录中进行多次分析时,很难确定它们可能是什么。
R 对命名的数据结构进行操作。最简单的此类结构是数字向量,它是一个由有序数字集合组成的单一实体。要设置一个名为 x
的向量(比如包含五个数字 10.4、5.6、3.1、6.4 和 21.7),请使用 R 命令
> x <- c(10.4, 5.6, 3.1, 6.4, 21.7)
这是一个赋值语句,使用函数 c()
,在此上下文中,它可以采用任意数量的向量参数,其值是通过将参数首尾相连而获得的向量。7
表达式中单独出现的数字被视为长度为一的向量。
请注意赋值运算符(‘<-
’),它由两个字符‘<
’(“小于”)和‘-
’(“减号”)严格并排组成,它“指向”接收表达式值的 对象。在大多数情况下,‘=
’运算符可用作替代项。
还可以使用函数 assign()
进行赋值。与上述相同的赋值的等效方式如下
> assign("x", c(10.4, 5.6, 3.1, 6.4, 21.7))
通常的运算符 <-
可以被认为是此语法的一个快捷方式。
还可以使用赋值运算符的明显更改向其他方向进行赋值。因此,可以使用以下方式进行相同的赋值
> c(10.4, 5.6, 3.1, 6.4, 21.7) -> x
如果表达式用作完整命令,则该值将被打印并丢失8。因此,如果现在我们使用命令
> 1/x
五个值的倒数将打印在终端(当然,x
的值保持不变)。
进一步的赋值
> y <- c(x, 0, x)
将创建一个向量 y
,其中包含 11 个条目,由两个 x
副本和中间位置的零组成。
向量可用于算术表达式中,在这种情况下,逐个元素执行操作。出现在同一表达式中的向量不必全部具有相同的长度。如果它们不同,则表达式的值为与表达式中出现的最长向量具有相同长度的向量。表达式中较短的向量会根据需要(可能按分数)被循环利用,直到它们与最长向量的长度匹配。特别是常量只是被简单地重复。因此,对于以上赋值,命令
> v <- 2*x + y + 1
通过逐个元素相加生成一个新的长度为 11 的向量 v
,其中包括重复 2.2 次的 2*x
、重复一次的 y
和重复 11 次的 1
。
基本算术运算符是通常的 +
、-
、*
、/
和 ^
(用于求幂)。 此外,所有常见的算术函数都可用。log
、exp
、sin
、cos
、tan
、sqrt
等都具有其通常的含义。 max
和 min
分别选择向量的最大元素和最小元素。 range
是一个函数,其值是一个长度为 2 的向量,即 c(min(x), max(x))
。 length(x)
是 x
中的元素数, sum(x)
给出 x
中元素的总和, prod(x)
给出它们的乘积。
两个统计函数是 mean(x)
,它计算样本均值,与 sum(x)/length(x)
相同, 和 var(x)
,它给出
sum((x-mean(x))^2)/(length(x)-1)
或样本方差。如果 var()
的参数是一个 n 乘以 p 的矩阵,则该值是一个 p 乘以 p 的样本协方差矩阵,通过将行视为独立的 p 元样本向量得到。
sort(x)
返回一个与 x
大小相同的向量,其中元素按递增顺序排列;但是,还有其他更灵活的排序工具可用(请参见 order()
或 sort.list()
,它们生成一个用于排序的排列)。
请注意,max
和 min
选择其参数中的最大值和最小值,即使给出了多个向量。并行最大值和最小值函数 pmax
和 pmin
返回一个向量(长度等于其最长的参数),其中每个元素包含任何输入向量中该位置的最大(最小)元素。
对于大多数目的,用户不必关心数字向量中的“数字”是整数、实数还是复数。在内部,计算以双精度实数或(如果输入数据为复数)双精度复数进行。
要处理复数,请提供一个明确的复数部分。因此
sqrt(-17)
将给出 NaN
和一个警告,但
sqrt(-17+0i)
将以复数形式进行计算。
R 有许多用于生成常用数字序列的工具。例如 1:30
是向量 c(1, 2, …, 29, 30)
。 冒号运算符在表达式中具有较高的优先级,因此,例如 2*1:15
是向量 c(2, 4, …, 28, 30)
。将 n <- 10
,然后比较序列 1:n-1
和 1:(n-1)
。
构造 30:1
可用于反向生成序列。
函数 seq()
是用于生成序列的更通用的工具。它有五个参数,在任何一次调用中只能指定其中一些参数。如果给出了前两个参数,则指定序列的开头和结尾,如果这两个参数是给出的唯一两个参数,则结果与冒号运算符相同。即 seq(2,10)
与向量 2:10
相同。
传递给 seq()
和许多其他 R 函数的参数也可以以命名形式给出,在这种情况下,它们出现的顺序无关紧要。前两个参数可以命名为 from=value
和 to=value
;因此 seq(1,30)
、seq(from=1, to=30)
和 seq(to=30, from=1)
都与 1:30
相同。传递给 seq()
的后两个参数可以命名为 by=value
和 length=value
,它们分别指定序列的步长和长度。如果未给出这两个参数,则假定默认 by=1
。
例如
> seq(-5, 5, by=.2) -> s3
在 s3
中生成向量 c(-5.0, -4.8, -4.6, …, 4.6, 4.8, 5.0)
。类似地
> s4 <- seq(length=51, from=-5, by=.2)
在 s4
中生成相同的向量。
第五个参数可以命名为 along=vector
,通常用作创建序列 1, 2, …, length(vector)
的唯一参数,如果向量为空(它可以为空),则创建空序列。
一个相关的函数是 rep()
,它可以用于以各种复杂的方式复制对象。最简单的形式是
> s5 <- rep(x, times=5)
它将在 s5
中将 x
的五个副本首尾相连地放置。另一个有用的版本是
> s6 <- rep(x, each=5)
它在继续下一个元素之前重复 x
的每个元素五次。
除了数字向量,R 还允许操作逻辑量。逻辑向量的元素可以具有值 TRUE
、FALSE
和 NA
(表示“不可用”,见下文)。前两个通常分别缩写为 T
和 F
。但请注意,T
和 F
只是默认设置为 TRUE
和 FALSE
的变量,但不是保留字,因此可以被用户覆盖。因此,您应始终使用 TRUE
和 FALSE
。
逻辑向量由条件生成。例如
> temp <- x > 13
将 temp
设置为与 x
长度相同的向量,其中 FALSE
值对应于 x
中不满足条件的元素,TRUE
值对应于满足条件的元素。
逻辑运算符为 <
、<=
、>
、>=
、==
(表示精确相等)和 !=
(表示不相等)。 此外,如果 c1
和 c2
是逻辑表达式,则 c1 & c2
是它们的交集(“与”),c1 | c2
是它们的并集(“或”),!c1
是 c1
的否定。
逻辑向量可用于普通算术中,在这种情况下,它们会强制转换为数字向量,FALSE
变成 0
,TRUE
变成 1
。但是,在某些情况下,逻辑向量及其强制转换的数字对应项并不等效,例如,请参阅下一小节。
在某些情况下,向量的分量可能不完全已知。当一个元素或值“不可用”或在统计意义上为“缺失值”时,可以通过将特殊值 NA
分配给它来为其在向量中保留一个位置。 通常,对 NA
的任何操作都会变成 NA
。此规则的动机很简单,即如果操作的规范不完整,则无法知道结果,因此不可用。
函数 is.na(x)
会生成一个与 x
大小相同的逻辑向量,当且仅当 x
中的相应元素为 NA
时,该向量的值为 TRUE
。
> z <- c(1:3,NA); ind <- is.na(z)
请注意,逻辑表达式 x == NA
与 is.na(x)
有很大不同,因为 NA
实际上不是一个值,而是一个标记,表示一个不可用的量。因此,x == NA
是一个与 x
长度相同的向量,所有 值都是 NA
,因为逻辑表达式本身是不完整的,因此无法确定。
请注意,还有第二种“缺失”值,是由数值计算产生的,即所谓的 非数字,NaN
, 值。示例如下:
> 0/0
或
> Inf - Inf
由于结果无法合理定义,因此两者都给出 NaN
。
总之,is.na(xx)
对 NA
和 NaN
值都为 TRUE
both。为了区分它们,is.nan(xx)
仅对 NaN
为 TRUE
。
在不带引号打印字符向量时,缺失值有时会打印为 <NA>
。
字符量和字符向量在 R 中经常使用,例如作为绘图标签。在需要的地方,它们由双引号字符分隔的一系列字符表示,例如 "x-values"
、"New iteration results"
。
字符字符串使用匹配的双 ("
) 或单 ('
) 引号输入,但使用双引号(或有时不带引号)打印。它们使用 C 样式转义序列,使用 \
作为转义字符,因此 \
输入并打印为 \\
,在双引号内 "
输入为 \"
。其他有用的转义序列有 \n
,换行符,\t
,制表符和 \b
,退格符——有关完整列表,请参见 ?Quotes
。
字符向量可以通过 c()
函数连接成一个向量;其用法示例将经常出现。
paste()
函数接受任意数量的参数,并将它们逐个连接成字符串。参数中给出的任何数字都会以明显的方式强制转换为字符串,也就是说,转换方式与打印它们的方式相同。默认情况下,结果中的参数由单个空格分隔,但可以通过命名参数 sep=string
更改分隔符,将其更改为 string
,甚至可以为空。
例如
> labs <- paste(c("X","Y"), 1:10, sep="")
将 labs
变成字符向量
c("X1", "Y2", "X3", "Y4", "X5", "Y6", "X7", "Y8", "X9", "Y10")
特别注意,短列表的回收也在这里发生;因此 c("X", "Y")
重复 5 次以匹配序列 1:10
。 9
可以通过在向量名称后附加方括号中的索引向量来选择向量的元素子集。更一般地,任何求值为向量的表达式都可以通过在表达式后立即附加方括号中的索引向量来选择其元素的子集。
此类索引向量可以是四种不同类型中的任何一种。
TRUE
对应的值,而省略与 FALSE
对应的值。例如
> y <- x[!is.na(x)]
创建(或重新创建)一个对象 y
,其中将按相同顺序包含 x
的非缺失值。请注意,如果 x
有缺失值,则 y
将比 x
短。此外
> (x+1)[(!is.na(x)) & x>0] -> z
创建一个对象 z
,并将向量 x+1
的值放入其中,其中 x
中的对应值既非缺失值,又为正值。
length(x)
} 中。向量的相应元素将按该顺序选择并在结果中连接。索引向量的长度可以是任意长度,结果的长度与索引向量的长度相同。例如,x[6]
是 x
的第六个分量,而
> x[1:10]
选择 x
的前 10 个元素(假设 length(x)
不小于 10)。此外
> c("x","y")[rep(c(1,2,2,1), times=4)]
(这件不太可能的事情)会生成一个长度为 16 的字符向量,其中包含重复四次的 "x", "y", "y", "x"
。
> y <- x[-(1:5)]
给予 y
所有元素,但 x
的前五个元素除外。
names
属性以识别其组件的情况。在这种情况下,名称向量的子向量可以与上面第 2 项中的正整数标签以相同的方式使用。
> fruit <- c(5, 10, 1, 20) > names(fruit) <- c("orange", "banana", "apple", "peach") > lunch <- fruit[c("apple","orange")]
优点是字母数字 名称 通常比 数字索引 更容易记住。此选项与数据框特别有用,我们稍后会看到。
索引表达式也可以出现在赋值的接收端,在这种情况下,赋值操作仅对向量的 那些元素 执行。表达式必须采用 vector[index_vector]
的形式,因为在此处用任意表达式代替向量名称没有多大意义。
例如
> x[is.na(x)] <- 0
用零替换 x
中的任何缺失值,并且
> y[y < 0] <- -y[y < 0]
具有与
> y <- abs(y)
向量是 R 中最重要的对象类型,但还有其他几种类型,我们将在后面的章节中正式了解它们。
R 操作的实体在技术上称为对象。示例包括数值(实数)或复数值向量、逻辑值向量和字符串向量。这些被称为“原子”结构,因为它们的组件都是同种类型或模式,即数值10、复数、逻辑、字符和原始。
向量必须具有所有相同模式的值。因此,任何给定的向量都必须明确地是逻辑、数值、复数、字符或原始。(此规则唯一的明显例外是将不可用数量列为特殊“值”NA
,但实际上有几种类型的NA
)。请注意,向量可以为空,但仍然具有模式。例如,空字符字符串向量列为character(0)
,空数值向量列为numeric(0)
。
R 还会操作称为 列表 的对象,其模式为 列表。这些是有序的对象序列,每个对象可以是任何模式。列表 被称为“递归”而不是原子结构,因为它们的组件本身也可以是列表。
其他递归结构是模式为 函数 和 表达式 的结构。函数是构成 R 系统一部分的对象,还有类似的用户编写函数,我们将在后面详细讨论。作为对象的表达式构成了 R 的高级部分,本指南不会讨论,除非在讨论 R 中用于建模的 公式 时间接讨论。
通过对象的 模式,我们指的是其基本组成部分的基本类型。这是对象“属性”的一个特例。每个对象的另一个属性是其 长度。函数 mode(object)
和 length(object)
可用于找出任何已定义结构的模式和长度 11。
对象的进一步属性通常由 attributes(object)
提供,请参阅 获取和设置属性。因此,模式 和 长度 也称为对象的“内在属性”。
例如,如果 z
是长度为 100 的复数向量,那么在表达式 mode(z)
中,字符字符串为 "complex"
,length(z)
为 100
。
R 几乎在任何可以被认为合理的地方处理模式更改(以及一些可能不合理的地方)。例如,使用
> z <- 0:9
我们可以输入
> digits <- as.character(z)
之后,digits
是字符向量 c("0", "1", "2", …, "9")
。进一步的 强制转换 或模式更改会再次重建数值向量
> d <- as.integer(digits)
现在 d
和 z
相同。12 有大量形式为 as.something()
的函数,用于从一种模式强制转换为另一种模式,或用于赋予对象它可能尚未拥有的其他一些属性。读者应查阅不同的帮助文件以熟悉它们。
“空”对象仍可能具有模式。例如
> e <- numeric()
使 e
成为模式为数字的空向量结构。类似地,character()
是一个空字符向量,依此类推。一旦创建了任何大小的对象,只需为其提供超出其先前范围的索引值,即可向其中添加新组件。因此
> e[3] <- 17
现在将 e
设为长度为 3 的向量(其前两个分量此时均为 NA
)。这适用于任何结构,前提是附加分量的模式与对象在第一位置的模式一致。
这种自动调整对象长度的方法经常使用,例如在输入的 scan()
函数中。(参见 The scan()
function。)
相反,截断对象的大小只需进行赋值即可。因此,如果 alpha
是长度为 10 的对象,则
> alpha <- alpha[2 * 1:5]
将其设为长度为 5 的对象,仅包含索引为偶数的前分量。(当然,旧索引不会保留。)然后,我们可以通过以下方式仅保留前三个值
> length(alpha) <- 3
并且可以以相同的方式扩展向量(通过缺失值)。
函数 attributes(object)
返回当前为该对象定义的所有非固有属性的列表。函数 attr(object, name)
可用于选择特定属性。这些函数很少使用,除非在某些特殊情况下为某些特定目的创建新属性时,例如将创建日期或操作员与 R 对象关联起来。但是,这个概念非常重要。
分配或删除属性时应小心,因为它们是 R 中使用的对象系统的一个组成部分。
当它用在赋值的左侧时,它可以用来将新属性与 object
关联起来,或更改现有属性。例如
> attr(z, "dim") <- c(10,10)
允许 R 将 z
视为 10x10 矩阵。
R 中的所有对象都有一个 类,由函数 class
报告。对于简单的向量,这只是模式,例如 "numeric"
、"logical"
、"character"
或 "list"
,但 "matrix"
、"array"
、"factor"
和 "data.frame"
是其他可能的值。
一个称为对象的特殊属性class 用于允许面向对象样式13的 R 编程。例如,如果一个对象具有 class "data.frame"
,它将以某种方式打印,plot()
函数将以某种方式以图形方式显示它,而其他所谓的通用函数,如 summary()
将以对其 class 敏感的方式对其作为参数做出反应。
要暂时移除 class 的影响,请使用函数 unclass()
。 例如,如果 winter
具有 class "data.frame"
,则
> winter
将以数据框形式打印它,这有点像矩阵,而
> unclass(winter)
将以普通列表的形式打印它。只有在非常特殊的情况下,您才需要使用此功能,但其中一种情况是当您正在学习了解 class 和通用函数的概念时。
通用函数和 class 将在 Class、通用函数和对象面向 中进一步讨论,但只是简要讨论。
一个因子是一个向量对象,用于指定相同长度的其他向量的分量的离散分类(分组)。R 提供有序和无序因子。虽然因子的“实际”应用是模型公式(参见对比),但我们在此查看一个具体示例。
例如,假设我们有一个来自澳大利亚所有州和领地的 30 名税务会计师样本14,并且他们的原籍州由一个字符向量指定,如下所示,其中州助记符为
> state <- c("tas", "sa", "qld", "nsw", "nsw", "nt", "wa", "wa", "qld", "vic", "nsw", "vic", "qld", "qld", "sa", "tas", "sa", "nt", "wa", "vic", "qld", "nsw", "nsw", "wa", "sa", "act", "nsw", "vic", "vic", "act")
请注意,对于字符向量,“已排序”表示按字母顺序排序。
> statef <- factor(state)
print()
函数处理因子的方式与处理其他对象略有不同
> statef [1] tas sa qld nsw nsw nt wa wa qld vic nsw vic qld qld sa [16] tas sa nt wa vic qld nsw nsw wa sa act nsw vic vic act Levels: act nsw nt qld sa tas vic wa
> levels(statef) [1] "act" "nsw" "nt" "qld" "sa" "tas" "vic" "wa"
tapply()
和参差不齐的数组 ¶继续前面的示例,假设我们在另一个向量中拥有相同税务会计师的收入(以适当的大货币单位表示)
> incomes <- c(60, 49, 40, 61, 64, 60, 59, 54, 62, 69, 70, 42, 56, 61, 61, 61, 58, 51, 48, 65, 49, 49, 41, 48, 52, 46, 59, 46, 58, 43)
现在,我们可以使用特殊函数 tapply()
来计算每个州的样本平均收入
> incmeans <- tapply(incomes, statef, mean)
给出带有由级别标记的组件的均值向量
act nsw nt qld sa tas vic wa 44.500 57.333 55.500 53.600 55.000 60.500 56.000 52.250
函数 tapply()
用于将函数(此处为 mean()
)应用于第一个参数的每个组件组(此处为 incomes
),该组由第二个组件的级别(此处为 statef
15)定义,就好像它们是单独的向量结构一样。结果是一个结构,其长度与包含结果的因子的级别属性相同。读者应查阅帮助文档以了解更多详细信息。
进一步假设我们需要计算州收入均值的标准误差。为此,我们需要编写一个 R 函数来计算任何给定向量的标准误差。由于有一个内置函数 var()
来计算样本方差,因此此类函数是一个非常简单的单行函数,由赋值指定
> stdError <- function(x) sqrt(var(x)/length(x))
(稍后将在 编写自己的函数 中考虑编写函数。请注意,R 的内置函数 sd()
是不同的。) 在此赋值之后,通过以下方式计算标准误差
> incster <- tapply(incomes, statef, stdError)
然后计算的值为
> incster act nsw nt qld sa tas vic wa 1.5 4.3102 4.5 4.1061 2.7386 0.5 5.244 2.6575
作为练习,您可能需要找出州平均收入的通常 95% 置信区间。为此,您可以再次使用 tapply()
和 length()
函数来找出样本量,并使用 qt()
函数来找出适当 t 分布的百分位数。(您还可以调查 R 对 t 检验的工具。)
函数 tapply()
还可以用于处理通过多个类别对向量进行更复杂的索引。例如,我们可能希望按州和性别对税务会计师进行划分。然而,在这个简单的实例中(只有一个因子),可以将发生的事情视为如下。向量中的值被收集到与因子中的不同条目对应的组中。然后将该函数分别应用于这些组中的每一个。该值是一个函数结果向量,由因子的 levels
属性标记。
向量和标记因子的组合是一个有时称为交错数组的示例,因为子类大小可能不规则。当子类大小都相同时,索引可以隐式完成,并且效率更高,正如我们在下一节中看到的那样。
因子的级别按字母顺序存储,或按显式指定给 factor
的顺序存储(如果它们是显式指定的)。
有时,级别将具有我们想要记录并希望我们的统计分析利用的自然顺序。 ordered()
函数创建这样的有序因子,但其他方面与 factor
相同。对于大多数目的,有序因子和无序因子之间的唯一区别在于,前者在打印时显示级别的顺序,但为它们在拟合线性模型中生成的对比是不同的。
数组可以看作是多重标引的数据项集合,例如数字。R 提供了创建和处理数组的简单工具,尤其是矩阵这种特殊情况。
维度向量是非负整数向量。如果其长度为k,则数组为k维,例如矩阵是2维数组。维度从一索引到维度向量中给出的值。
只有当向量的dim属性为维度向量时,R 才能将该向量用作数组。例如,假设z
是包含 1500 个元素的向量。赋值
> dim(z) <- c(3,5,100)
为其提供了dim属性,使其可以被视为3 x 5 x 100 数组。
其他函数(例如 matrix()
和 array()
)可用于更简单、更直观的赋值,如我们在array()
函数中所看到的。
数据向量中的值按其在 FORTRAN 中出现的顺序给出数组中的值,即“列主序”,第一个下标移动最快,最后一个下标移动最慢。
例如,如果数组(例如 a
)的维度向量为 c(3,4,2)
,则 a
中有 3 * 4 * 2 = 24 个条目,数据向量按 a[1,1,1], a[2,1,1], …, a[2,4,2], a[3,4,2]
的顺序保存这些条目。
数组可以是一维的:此类数组通常与向量以相同的方式处理(包括打印时),但例外情况可能会引起混淆。
数组的各个元素可以通过给出数组名称,后跟方括号中的下标(用逗号分隔)来引用。
更一般地说,可以通过给出 索引向量 序列来指定数组的子部分,以代替下标;但是,如果任何索引位置给出了一个空索引向量,则取该下标的全部范围。
继续前面的示例,a[2,,]
是一个 4 * 2 数组,维度向量为 c(4,2)
,数据向量包含按以下顺序排列的值
c(a[2,1,1], a[2,2,1], a[2,3,1], a[2,4,1], a[2,1,2], a[2,2,2], a[2,3,2], a[2,4,2])
。 a[,,]
表示整个数组,这与完全省略下标并单独使用 a
相同。
对于任何数组(例如 Z
),维度向量可以明确地引用为 dim(Z)
(在赋值的任一侧)。
此外,如果数组名称仅给出 一个下标或索引向量,则仅使用数据向量的相应值;在这种情况下,维度向量将被忽略。但是,如果单个索引不是向量而是数组本身,则情况并非如此,我们接下来将对此进行讨论。
除了在任何下标位置使用索引向量外,还可以将矩阵与单个 索引矩阵 一起使用,以便将数量向量分配给数组中元素的不规则集合,或将不规则集合作为向量提取出来。
矩阵示例让这个过程变得清晰。对于双重索引数组,可以给出一个由两列和任意行数组成的索引矩阵。索引矩阵中的条目是双重索引数组的行索引和列索引。例如,假设我们有一个 4 乘 5 数组 X
,我们希望执行以下操作
X[1,3]
、X[2,2]
和 X[3,1]
作为矢量结构提取出来,并且
X
中的这些条目。
在这种情况下,我们需要一个 3 乘 2 下标数组,如下例所示。
> x <- array(1:20, dim=c(4,5)) # Generate a 4 by 5 array.
> x
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
> i <- array(c(1:3,3:1), dim=c(3,2))
> i # i
is a 3 by 2 index array.
[,1] [,2]
[1,] 1 3
[2,] 2 2
[3,] 3 1
> x[i] # Extract those elements
[1] 9 6 3
> x[i] <- 0 # Replace those elements by zeros.
> x
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 0 13 17
[2,] 2 0 10 14 18
[3,] 0 7 11 15 19
[4,] 4 8 12 16 20
>
索引矩阵中不允许出现负索引。允许出现 NA
和零值:包含零的行在索引矩阵中会被忽略,包含 NA
的行在结果中会产生一个 NA
。
作为一个不太简单的示例,假设我们希望为由因子 blocks
(b
个级别)和 varieties
(v
个级别)定义的块设计生成一个(未简化的)设计矩阵。此外,假设实验中有 n
个小区。我们可以按以下方式进行
> Xb <- matrix(0, n, b) > Xv <- matrix(0, n, v) > ib <- cbind(1:n, blocks) > iv <- cbind(1:n, varieties) > Xb[ib] <- 1 > Xv[iv] <- 1 > X <- cbind(Xb, Xv)
要构造关联矩阵(假设为 N
),我们可以使用
> N <- crossprod(Xb, Xv)
但是,生成此矩阵的一种更简单的直接方法是使用 table()
:
> N <- table(blocks, varieties)
索引矩阵必须是数值的:作为矩阵提供的任何其他形式的矩阵(例如逻辑矩阵或字符矩阵)都将被视为索引矢量。
array()
函数 ¶除了给矢量结构一个 dim
属性之外,还可以通过 array
函数从矢量构造数组,该函数的形式为
> Z <- array(data_vector, dim_vector)
例如,如果矢量 h
包含 24 个或更少的数字,则命令
> Z <- array(h, dim=c(3,4,2))
将使用 h
在 Z
中设置一个 3 乘 4 乘 2 数组。如果 h
的大小恰好为 24,则结果与
> Z <- h ; dim(Z) <- c(3,4,2)
相同。但是,如果 h
短于 24,则其值将从头开始循环使用以使其达到 24 的大小(参见 混合矢量和数组算术。循环使用规则),但 dim(h) <- c(3,4,2)
会发出关于长度不匹配的错误。作为一个极端的但常见的示例
> Z <- array(0, c(3,4,2))
使 Z
成为一个全零数组。
此时dim(Z)
表示维度向量c(3,4,2)
,Z[1:24]
表示数据向量,就像在h
中一样,Z[]
带空下标或Z
不带下标表示整个数组作为数组。
数组可用于算术表达式,结果是通过对数据向量进行逐元素运算形成的数组。dim
运算符的属性通常需要相同,这将成为结果的维度向量。因此,如果A
、B
和C
都是类似的数组,则
> D <- 2*A*B + C + 1
使D
成为类似的数组,其数据向量是给定逐元素运算的结果。但是,关于混合数组和向量计算的精确规则必须更仔细地考虑一下。
影响向量和数组逐元素混合计算的精确规则有些古怪,在参考中很难找到。根据经验,我们发现以下内容是一个可靠的指南。
dim
属性或产生错误。
dim
属性。
数组上的一个重要操作是外积。如果 a
和 b
是两个数值数组,它们的外积是一个数组,其维度向量是通过连接它们的两个维度向量(顺序很重要)获得的,其数据向量是通过形成 a
的数据向量的元素与 b
的数据向量的元素的所有可能乘积而获得的。外积由特殊运算符 %o%
形成:
> ab <- a %o% b
另一种方法是
> ab <- outer(a, b, "*")
乘法函数可以用两个变量的任意函数替换。例如,如果我们希望使用 R 向量 x
和 y
分别定义的 x 和 y 坐标的规则值网格对函数 f(x; y) = cos(y)/(1 + x^2) 进行求值,我们可以按如下方式进行
> f <- function(x, y) cos(y)/(1 + x^2) > z <- outer(x, y, f)
特别是,两个普通向量的外积是一个双下标数组(即一个秩最多为 1 的矩阵)。请注意,外积运算符当然是非交换的。在编写自己的函数中将进一步考虑定义您自己的 R 函数。
作为一个简单但可爱的示例,考虑行列式为 2 乘 2 的矩阵 [a, b; c, d],其中每个条目都是范围 0, 1, ..., 9 中的非负整数,即数字。
问题是找到此形式的所有可能矩阵的行列式 ad - bc,并以 高密度 图的形式表示每个值出现的频率。这相当于找到行列式的概率分布,如果每个数字都是独立且均匀随机选择的。
一种巧妙的方法是使用 outer()
函数两次
> d <- outer(0:9, 0:9) > fr <- table(outer(d, d, "-")) > plot(fr, xlab="Determinant", ylab="Frequency")
请注意,此处 plot()
使用直方图之类的绘图方法,因为它“看到” fr
是 "table"
类的。使用 for
循环解决此问题的“明显”方法将在 分组、循环和条件执行 中讨论,效率太低,不切实际。
大约 20 个此类矩阵中有一个是奇异矩阵,这也许令人惊讶。
函数 aperm(a, perm)
可用于排列数组 a
。参数 perm
必须是整数 {1, ..., k} 的排列,其中 k 是 a
中下标的数量。该函数的结果是一个与 a
大小相同的数组,但旧维度由 perm[j]
给出,成为新的第 j
维。考虑此操作的最简单方法是将其视为矩阵转置的概括。实际上,如果 A
是一个矩阵(即双下标数组),那么由下式给出的 B
> B <- aperm(A, c(2,1))
只是 A
的转置。对于此特殊情况,可以使用更简单的函数 t()
,因此我们可以使用 B <- t(A)
。
如上所述,矩阵只是一个具有两个下标的数组。然而,它是一个非常重要的特例,需要单独讨论。R 包含许多仅可用于矩阵的运算符和函数。例如,如上所述,t(X)
是矩阵转置函数。函数 nrow(A)
和 ncol(A)
分别给出矩阵 A
中的行数和列数。
运算符 %*%
用于矩阵乘法。 当然,n 乘 1 或 1 乘 n 矩阵可以用作 n 向量,如果在上下文中合适的话。相反,出现在矩阵乘法表达式中的向量会自动提升为行向量或列向量,无论哪种方式在乘法上是一致的,如果可能的话(尽管这并不总是明确可能的,正如我们稍后看到的)。
例如,如果 A
和 B
是相同大小的方阵,那么
> A * B
是元素乘积矩阵,
> A %*% B
是矩阵乘积。如果 x
是一个向量,那么
> x %*% A %*% x
是一个二次型。16
函数 crossprod()
形成“交叉乘积”,这意味着 crossprod(X, y)
与 t(X) %*% y
相同,但操作效率更高。如果省略 crossprod()
的第二个参数,则将其视为与第一个参数相同。
diag()
的含义取决于其参数。diag(v)
,其中 v
是一个向量,给出一个对角矩阵,其中向量的元素作为对角线条目。另一方面,diag(M)
,其中 M
是一个矩阵,给出了 M
的主对角线条目的向量。这与 MATLAB 中 diag()
使用的约定相同。此外,有点令人困惑的是,如果 k
是一个单一的数值,那么 diag(k)
就是 k
乘 k
的单位矩阵!
求解线性方程是矩阵乘法的逆运算。当在
> b <- A %*% x
仅提供 A
和 b
时,向量 x
是该线性方程组的解。在 R 中,
> solve(A,b)
求解该方程组,返回 x
(可能会损失一些精度)。请注意,在线性代数中,形式上 x = A^{-1} %*% b
,其中 A^{-1}
表示 A
的逆,可通过以下方式计算:
solve(A)
但很少需要。从数值上讲,计算 x <- solve(A) %*% b
而不是 solve(A,b)
既效率低下,又可能不稳定。
多元计算中使用的二次形式 x %*% A^{-1} %*% x
应通过类似于17 x %*% solve(A,x)
的方式计算,而不是计算 A
的逆。
函数 eigen(Sm)
计算对称矩阵 Sm
的特征值和特征向量。此函数的结果是一个包含两个组件的列表,分别名为 values
和 vectors
。分配
> ev <- eigen(Sm)
将把此列表分配给 ev
。然后,ev$val
是 Sm
的特征值向量,ev$vec
是相应特征向量的矩阵。如果我们只需要特征值,则可以使用分配
> evals <- eigen(Sm)$values
evals
现在保存特征值向量,第二个组件被丢弃。如果表达式
> eigen(Sm)
本身用作命令,则会打印这两个组件及其名称。对于大型矩阵,最好避免计算不需要的特征向量,方法是使用表达式
> evals <- eigen(Sm, only.values = TRUE)$values
函数 svd(M)
采用任意矩阵参数 M
,并计算 M
的奇异值分解。这包括一个正交列矩阵 U
,它与 M
具有相同的列空间,一个正交列矩阵 V
,其列空间是 M
的行空间,以及一个正项对角矩阵 D
,使得 M = U %*% D %*% t(V)
。 D
实际上作为对角元素的向量返回。 svd(M)
的结果实际上是一个包含三个组件的列表,分别命名为 d
、u
和 v
,含义显而易见。
如果 M
实际上是方阵,那么很容易看出
> absdetM <- prod(svd(M)$d)
计算 M
的行列式的绝对值。如果需要使用各种矩阵经常进行此计算,则可以将其定义为 R 函数
> absdet <- function(M) prod(svd(M)$d)
之后,我们可以将 absdet()
作为另一个 R 函数使用。作为一个进一步的简单但可能很有用的示例,您可能需要考虑编写一个函数,比如 tr()
,来计算方阵的迹。[提示:您不需要使用显式循环。请再次查看 diag()
函数。]
R 有一个内置函数 det
来计算行列式,包括符号,另一个函数 determinant
来给出符号和模数(可以选择对数刻度),
函数 lsfit()
返回一个列表,给出最小二乘拟合过程的结果。这样的赋值
> ans <- lsfit(X, y)
给出最小二乘拟合的结果,其中 y
是观测值向量,X
是设计矩阵。有关更多详细信息,请参阅帮助工具,以及用于回归诊断的后续函数 ls.diag()
。请注意,自动包含总均值项,无需将其明确包含为 X
的一列。此外,请注意,您几乎总是更愿意使用 lm(.)
(请参阅 线性模型)而不是 lsfit()
进行回归建模。
另一个密切相关的函数是 qr()
及其相关函数。考虑以下赋值
> Xplus <- qr(X) > b <- qr.coef(Xplus, y) > fit <- qr.fitted(Xplus, y) > res <- qr.resid(Xplus, y)
这些计算 y
在 fit
中对 X
范围的正交投影,在 res
中对正交补的投影以及在 b
中的投影系数向量,即 b
基本上是 MATLAB “反斜杠”运算符的结果。
不假设 X
具有满列秩。冗余将被发现并删除,因为它们被发现。
此替代方法是执行最小二乘计算的较旧、低级方法。虽然在某些情况下仍然有用,但现在通常会被统计模型功能所取代,如 R 中的统计模型 中所讨论的。
cbind()
和 rbind()
¶正如我们已经非正式地看到的那样,可以通过函数 cbind()
和 rbind()
从其他向量和矩阵构建矩阵。大致上 cbind()
通过水平或按列方式将矩阵绑定在一起来形成矩阵,而 rbind()
则通过垂直或按行方式绑定在一起来形成矩阵。
在赋值中
> X <- cbind(arg_1, arg_2, arg_3, ...)
对 cbind()
的参数必须是任意长度的向量或具有相同列大小的矩阵,即相同数量的行。结果是一个矩阵,其中连接的参数 arg_1、arg_2、… 形成列。
如果对 cbind()
的某些参数是向量,则它们可能比任何现有矩阵的列大小短,在这种情况下,它们将被循环扩展以匹配矩阵列大小(如果没有给出矩阵,则匹配最长向量的长度)。
函数 rbind()
对行执行相应的操作。在这种情况下,任何向量参数(可能循环扩展)当然都被视为行向量。
假设 X1
和 X2
具有相同数量的行。为了通过列将它们组合到矩阵 X
中,连同 1
的初始列,我们可以使用
> X <- cbind(1, X1, X2)
rbind()
或 cbind()
的结果始终具有矩阵状态。因此,cbind(x)
和 rbind(x)
可能分别允许向量 x
被视为列或行矩阵的最简单方法。
c()
与数组 ¶值得注意的是,虽然 cbind()
和 rbind()
是尊重 dim
属性的连接函数,但基本 c()
函数则不是,而是清除所有 dim
和 dimnames
属性的数字对象。这偶尔会很有用。
将数组强制转换回简单向量对象的官方方法是使用 as.vector()
> vec <- as.vector(X)
然而,可以通过仅使用一个参数来使用 c()
来实现类似的结果,仅仅是为了这个副作用
> vec <- c(X)
两者之间有细微的差别,但最终它们之间的选择在很大程度上取决于风格(前者更可取)。
回想一下,因子定义了分组划分。类似地,一对因子定义了一个双向交叉分类,依此类推。 函数 table()
允许从等长因子计算频率表。如果有 k 个因子参数,结果是一个 k 维频率数组。
例如,假设 statef
是一个因子,它为数据向量中的每个条目提供状态代码。赋值
> statefr <- table(statef)
在 statefr
中给出了样本中每个状态的频率表。频率按因子的 levels
属性排序并标记。这个简单的情况等同于以下情况,但更方便:
> statefr <- tapply(statef, statef, length)
进一步假设 incomef
是一个因子,它为数据向量中的每个条目提供了一个适当定义的“收入等级”,例如使用 cut()
函数
> factor(cut(incomes, breaks = 35+10*(0:7))) -> incomef
然后计算频率的双向表
> table(incomef,statef) statef incomef act nsw nt qld sa tas vic wa (35,45] 1 1 0 1 0 0 1 0 (45,55] 1 1 1 1 2 0 1 3 (55,65] 0 3 1 3 2 2 2 1 (65,75] 0 1 0 0 0 0 1 0
立即扩展到更高阶的频率表。
R 中的列表是一个对象,它由一个有序的对象集合组成,称为其组件。
组件没有特别的需要具有相同的模式或类型,例如,一个列表可以由一个数字向量、一个逻辑值、一个矩阵、一个复数向量、一个字符数组、一个函数等组成。下面是一个创建列表的简单示例
> Lst <- list(name="Fred", wife="Mary", no.children=3, child.ages=c(4,7,9))
组件始终编号,并且始终可以这样引用。因此,如果Lst
是一个有四个组件的列表的名称,则可以单独引用它们为Lst[[1]]
、Lst[[2]]
、Lst[[3]]
和Lst[[4]]
。此外,如果Lst[[4]]
是一个向量下标数组,则Lst[[4]][1]
是它的第一个条目。
如果Lst
是一个列表,则函数length(Lst)
给出它具有的(顶级)组件数。
列表的组件也可以命名,在这种情况下,组件可以通过在双方括号中用字符字符串代替数字来引用,或者更方便地通过给出以下形式的表达式来引用
> name$component_name
表示相同的事物。
这是一个非常有用的约定,因为它可以让你在忘记数字时更容易获得正确的组件。
因此,在上面给出的简单示例中
Lst$name
与Lst[[1]]
相同,是字符串"Fred"
,
Lst$wife
与Lst[[2]]
相同,是字符串"Mary"
,
Lst$child.ages[1]
与Lst[[4]][1]
相同,是数字4
。
此外,还可以使用双重方括号中的列表组件名称,即 Lst[["name"]]
与 Lst$name
相同。当要提取的组件名称存储在另一个变量中时,这特别有用,如
> x <- "name"; Lst[[x]]
区分 Lst[[1]]
和 Lst[1]
非常重要。‘[[…]]
’ 是用于选择单个元素的操作符,而 ‘[…]
’ 是一个通用下标操作符。因此前者是 列表 Lst
中的第一个对象,如果它是一个命名列表,则 不 包含名称。后者是 列表 Lst
的一个子列表,仅包含第一个条目。如果它是一个命名列表,则名称将被转移到子列表中。
组件的名称可以缩写为唯一标识它们所需的最小字母数。因此 Lst$coefficients
可以最小指定为 Lst$coe
,Lst$covariance
可以最小指定为 Lst$cov
。
名称向量实际上只是列表的一个属性,就像其他任何属性一样,可以作为这样的属性进行处理。当然,除了列表之外的其他结构也可以赋予一个 名称 属性。
可以通过函数 list()
从现有对象中形成新列表。形式为
> Lst <- list(name_1=object_1, ..., name_m=object_m)
使用 object_1、…、object_m 为组件设置列表 Lst
,并根据参数名称(可以自由选择)为这些组件指定名称。如果省略这些名称,则组件仅编号。用于形成列表的组件在形成新列表时会复制,而不会影响原始组件。
列表与任何带下标的对象一样,可以通过指定附加组件进行扩展。例如
> Lst[5] <- list(matrix=Mat)
当连接函数 c()
给出列表参数时,结果也是模式列表的对象,其组件是按顺序连接在一起的参数列表的组件。
> list.ABC <- c(list.A, list.B, list.C)
回想一下,当使用矢量对象作为参数时,连接函数同样将所有参数连接到单个矢量结构中。在这种情况下,所有其他属性(例如 dim
属性)都将被丢弃。
数据框是具有类 "data.frame"
的列表。对于可以制成数据框的列表有一些限制,即
对于许多目的,数据框可以看作是列可能具有不同模式和属性的矩阵。它可以以矩阵形式显示,并使用矩阵索引约定提取其行和列。
满足数据框列(组件)限制的对象可以使用 data.frame
函数来形成一个数据框:
> accountants <- data.frame(home=statef, loot=incomes, shot=incomef)
组件符合数据框限制的列表可以使用 as.data.frame()
函数强制转换为数据框
从头开始构建数据框的最简单方法是使用 read.table()
函数从外部文件读取整个数据框。这将在 从文件读取数据 中进一步讨论。
attach()
和 detach()
¶列表组件的 $
符号,如 accountants$home
,并不总是很方便。一个有用的功能是,以某种方式使列表或数据框的组件在不需要每次都明确引用列表名称的情况下,以其组件名称的形式暂时显示为变量。
attach()
函数以列表或数据框等“数据库”作为其参数。因此,假设 lentils
是一个具有三个变量 lentils$u
、lentils$v
、lentils$w
的数据框。attach
> attach(lentils)
将数据框置于搜索路径的第 2 位,并且如果在第 1 位没有变量 u
、v
或 w
,则 u
、v
和 w
可作为数据框中的变量本身使用。此时,诸如
> u <- v+w
这样的赋值不会替换数据框的组件 u
,而是使用搜索路径上第 1 位的工作区中的另一个变量 u
对其进行屏蔽。要对数据框本身进行永久更改,最简单的方法是再次使用 $
符号
> lentils$u <- v+w
但是,组件 u
的新值在数据框分离并重新附加之前不可见。
要分离数据框,请使用函数
> detach()
更准确地说,此语句从搜索路径中分离当前位于第 2 个位置的实体。因此,在当前上下文中,变量 u
、v
和 w
将不再可见,除非使用列表表示法,如 lentils$u
等。搜索路径中位置大于 2 的实体可以通过将它们的编号提供给 detach
来分离,但始终使用名称要安全得多,例如 detach(lentils)
或 detach("lentils")
注意:在 R 中,列表和数据框只能附加在第 2 个位置或更高位置,并且附加的是原始对象的副本。你可以通过
assign
更改附加的值via,但原始列表或数据框保持不变。
一个有用的约定,它允许你在同一个工作区中舒适地处理许多不同的问题,那就是
$
形式的赋值将你希望保留以供将来参考的任何变量添加到数据框中,然后 detach()
;
通过这种方式,在同一目录中处理许多问题非常简单,例如,所有问题都具有名为 x
、y
和 z
的变量。
attach()
是一个通用函数,它不仅允许将目录和数据框附加到搜索路径,还允许附加其他类对象。特别是,任何模式为 "list"
的对象都可以以相同的方式附加
> attach(any.old.list)
任何已附加的内容都可以通过 detach
按位置编号或(最好)按名称分离。
函数 search
显示当前搜索路径,因此是一种非常有用的方式来跟踪已附加和分离的数据框和列表(以及包)。最初它给出
> search() [1] ".GlobalEnv" "Autoloads" "package:base"
其中 .GlobalEnv
是工作区。18
附加 lentils
后,我们有
> search() [1] ".GlobalEnv" "lentils" "Autoloads" "package:base" > ls(2) [1] "u" "v" "w"
正如我们所见,ls
(或 objects
)可用于检查搜索路径上任何位置的内容。
最后,我们分离数据框并确认它已从搜索路径中删除。
> detach("lentils") > search() [1] ".GlobalEnv" "Autoloads" "package:base"
大型数据对象通常会从外部文件读取值,而不是在 R 会话期间通过键盘输入。R 输入工具很简单,其要求相当严格,甚至相当不灵活。R 的设计者明确地认为,您将能够使用其他工具(例如文件编辑器或 Perl19)修改您的输入文件,以满足 R 的要求。通常,这非常简单。
如果变量主要保存在数据框中(我们强烈建议这样做),则可以使用 read.table()
函数直接读取整个数据框。还有一个更原始的输入函数 scan()
,可以直接调用它。
有关将数据导入 R 以及导出数据的更多详细信息,请参阅R 数据导入/导出手册。
read.table()
函数 ¶要直接读取整个数据框,外部文件通常具有特殊形式。
如果文件的第一行比第二行少一个项目,则假定此排列有效。因此,要作为数据框读取的文件的前几行可能如下所示。
Input file form with names and row labels: Price Floor Area Rooms Age Cent.heat 01 52.00 111.0 830 5 6.2 no 02 54.75 128.0 710 5 7.5 no 03 57.50 101.0 1000 5 4.2 no 04 57.50 131.0 690 6 8.8 no 05 59.75 93.0 900 5 1.9 yes ...
默认情况下,数字项(行标签除外)将作为数字变量读取,而非数字变量(如示例中的 Cent.heat
)将作为字符变量读取。如有必要,可以更改此设置。
然后可以使用函数 read.table()
直接读取数据框
> HousePrice <- read.table("houses.data")
通常,您希望直接省略包括行标签并使用默认标签。在这种情况下,文件可以省略行标签列,如下所示。
Input file form without row labels: Price Floor Area Rooms Age Cent.heat 52.00 111.0 830 5 6.2 no 54.75 128.0 710 5 7.5 no 57.50 101.0 1000 5 4.2 no 57.50 131.0 690 6 8.8 no 59.75 93.0 900 5 1.9 yes ...
然后可以读取数据框,如下所示
> HousePrice <- read.table("houses.data", header=TRUE)
其中,header=TRUE
选项指定第一行是标题行,因此,从文件形式中可以推断出没有给出明确的行标签。
scan()
函数 ¶假设数据向量长度相等,并且要并行读取。此外,假设有三个向量,第一个模式为字符,其余两个模式为数字,并且文件为 input.dat。第一步是使用 scan()
将三个向量作为列表读入,如下所示
> inp <- scan("input.dat", list("",0,0))
第二个参数是一个虚拟列表结构,用于建立要读取的三个向量的模式。存储在 inp
中的结果是一个列表,其组件是读入的三个向量。要将数据项分隔为三个单独的向量,请使用类似这样的赋值
> label <- inp[[1]]; x <- inp[[2]]; y <- inp[[3]]
更方便的是,虚拟列表可以具有命名组件,在这种情况下,可以使用名称来访问读入的向量。例如
> inp <- scan("input.dat", list(id="", x=0, y=0))
如果您希望分别访问变量,则可以将它们重新分配给工作框架中的变量
> label <- inp$id; x <- inp$x; y <- inp$y
或者列表可以附加到搜索路径的第 2 个位置(请参阅附加任意列表)。
如果第二个参数是单个值而不是列表,则读入单个向量,其所有组件的模式必须与虚拟值相同。
> X <- matrix(scan("light.dat", 0), ncol=5, byrow=TRUE)
有更多精细的输入工具,这些工具在手册中进行了详细说明。
R 提供了大约 100 个数据集(在 datasets 包中),其他数据集可在包中获得(包括 R 提供的推荐包)。要查看当前可用的数据集列表,请使用
data()
R 提供的所有数据集都可直接按名称获取。但是,许多包仍使用已过时的惯例,其中 data
也用于将数据集加载到 R 中,例如
data(infert)
这仍可与标准包一起使用(如本示例中所示)。在大多数情况下,这将加载同名 R 对象。但是,在少数情况下,它会加载多个对象,因此请参阅对象的在线帮助以了解预期结果。
要访问特定包中的数据,请使用 package
参数,例如
data(package="rpart") data(Puromycin, package="datasets")
如果已通过 library
附加包,则其数据集会自动包含在搜索中。
用户贡献的包可以是数据集的丰富来源。
当在数据框或矩阵上调用 edit
时,它会调出一个类似电子表格的单独环境用于编辑。这对于在读取数据集后进行小幅更改非常有用。命令
> xnew <- edit(xold)
将允许你编辑数据集 xold
,并且完成后,更改后的对象将分配给 xnew
。如果你想更改原始数据集 xold
,最简单的方法是使用 fix(xold)
,它等效于 xold <- edit(xold)
。
使用
> xnew <- edit(data.frame())
通过电子表格界面输入新数据。
R 的一个便利用途是提供一组全面的统计表。提供函数来评估累积分布函数 P(X <= x)、概率密度函数和分位数函数(给定q,最小的x,使得 P(X <= x) > q),并模拟分布。
分布 R 名称 其他参数 beta beta
shape1、shape2、ncp
binomial binom
size、prob
Cauchy cauchy
location、scale
chi-squared chisq
df、ncp
exponential exp
rate
F f
df1、df2、ncp
gamma gamma
shape、scale
geometric geom
prob
hypergeometric hyper
m、n、k
log-normal lnorm
meanlog、sdlog
logistic logis
location、scale
negative binomial nbinom
size、prob
normal norm
mean、sd
Poisson pois
lambda
signed rank signrank
n
Student’s t t
df、ncp
uniform unif
min、max
Weibull weibull
shape、scale
Wilcoxon wilcox
m、n
在此给出的名称前加上“d”表示密度,“p”表示 CDF,“q”表示分位数函数,“r”表示模拟(random deviates)。第一个参数对于 dxxx
是 x
,对于 pxxx
是 q
,对于 qxxx
是 p
,对于 rxxx
是 n
(rhyper
、rsignrank
和 rwilcox
除外,对于它们是 nn
)。并非在所有情况下都提供非中心参数 ncp
:有关详细信息,请参见在线帮助。
所有 pxxx
和 qxxx
函数都具有逻辑参数 lower.tail
和 log.p
,而 dxxx
函数具有 log
。这允许通过以下方式获取累积(或“积分”)风险函数 H(t) = - log(1 - F(t)):
- pxxx(t, ..., lower.tail = FALSE, log.p = TRUE)
或更准确的对数似然(通过 dxxx(..., log = TRUE)
),直接。
此外,还有用于正态分布样本的学生化范围分布的函数 ptukey
和 qtukey
,以及用于多项分布的函数 dmultinom
和 rmultinom
。其他分布可在贡献的软件包中获得,尤其是 SuppDists。
以下是一些示例
> ## 2-tailed p-value for t distribution > 2*pt(-2.43, df = 13) > ## upper 1% point for an F(2, 7) distribution > qf(0.01, 2, 7, lower.tail = FALSE)
请参阅 RNG
的在线帮助,了解如何在 R 中进行随机数生成。
给定一组(单变量)数据,我们可以通过多种方式检查其分布。最简单的方法是检查数字。summary
和 fivenum
给出了两个略有不同的摘要 ,而 stem
(“茎叶”图)显示了数字。
> attach(faithful) > summary(eruptions) Min. 1st Qu. Median Mean 3rd Qu. Max. 1.600 2.163 4.000 3.488 4.454 5.100 > fivenum(eruptions) [1] 1.6000 2.1585 4.0000 4.4585 5.1000 > stem(eruptions) The decimal point is 1 digit(s) to the left of the | 16 | 070355555588 18 | 000022233333335577777777888822335777888 20 | 00002223378800035778 22 | 0002335578023578 24 | 00228 26 | 23 28 | 080 30 | 7 32 | 2337 34 | 250077 36 | 0000823577 38 | 2333335582225577 40 | 0000003357788888002233555577778 42 | 03335555778800233333555577778 44 | 02222335557780000000023333357778888 46 | 0000233357700000023578 48 | 00000022335800333 50 | 0370
茎叶图类似于直方图,R 有一个函数 hist
来绘制直方图。
> hist(eruptions) ## make the bins smaller, make a plot of density > hist(eruptions, seq(1.6, 5.2, 0.2), prob=TRUE) > lines(density(eruptions, bw=0.1)) > rug(eruptions) # show the actual data points
可以使用 density
绘制更精美的密度图,并且在此示例中,我们添加了 density
生成的线。带宽 bw
是通过反复试验选择的,因为默认值会产生过多的平滑(对于“有趣”的密度通常如此)。(可以使用更好的自动带宽选择方法,在此示例中,bw = "SJ"
给出了一个好的结果。)
> plot(ecdf(eruptions), do.points=FALSE, verticals=TRUE)
显然,此分布与任何标准分布都相差甚远。较右侧的模式怎么样,比如持续时间超过 3 分钟的喷发?让我们拟合一个正态分布并叠加拟合的 CDF。
> long <- eruptions[eruptions > 3] > plot(ecdf(long), do.points=FALSE, verticals=TRUE) > x <- seq(3, 5.4, 0.01) > lines(x, pnorm(x, mean=mean(long), sd=sqrt(var(long))), lty=3)
par(pty="s") # arrange for a square figure region qqnorm(long); qqline(long)
这显示了合理的拟合,但右尾比正态分布的预期要短。让我们将此与 t 分布的模拟数据进行比较
x <- rt(250, df = 5) qqnorm(x); qqline(x)
如果它是随机样本,通常会显示比正态分布预期更长的尾部。我们可以通过以下方式针对生成分布绘制 Q-Q 图
qqplot(qt(ppoints(250), df = 5), x, xlab = "Q-Q plot for t dsn") qqline(x)
最后,我们可能需要对正态性(或非正态性)进行更正式的检验。R 提供 Shapiro-Wilk 检验
> shapiro.test(long) Shapiro-Wilk normality test data: long W = 0.9793, p-value = 0.01052
> ks.test(long, "pnorm", mean = mean(long), sd = sqrt(var(long))) One-sample Kolmogorov-Smirnov test data: long D = 0.0661, p-value = 0.4284 alternative hypothesis: two.sided
(请注意,由于我们从同一样本中估计了正态分布的参数,因此分布理论在此处无效。)
到目前为止,我们已经将单个样本与正态分布进行了比较。更常见的操作是比较两个样本的各个方面。请注意,在 R 中,所有“经典”检验(包括下面使用的检验)都在包 stats 中,该包通常已加载。
考虑 Rice (1995, p.490) 中关于冰的熔化潜热(cal/gm)的以下数据集
Method A: 79.98 80.04 80.02 80.04 80.03 80.03 80.04 79.97 80.05 80.03 80.02 80.00 80.02 Method B: 80.02 79.94 79.98 79.97 79.97 80.03 79.95 79.97
箱形图提供了两个样本的简单图形比较。
A <- scan() 79.98 80.04 80.02 80.04 80.03 80.03 80.04 79.97 80.05 80.03 80.02 80.00 80.02 B <- scan() 80.02 79.94 79.98 79.97 79.97 80.03 79.95 79.97 boxplot(A, B)
这表明第一组倾向于给出比第二组更高的结果。
要检验两个样本均值的相等性,我们可以使用 未配对 t 检验,方法是
> t.test(A, B) Welch Two Sample t-test data: A and B t = 3.2499, df = 12.027, p-value = 0.00694 alternative hypothesis: true difference in means is not equal to 0 95 percent confidence interval: 0.01385526 0.07018320 sample estimates: mean of x mean of y 80.02077 79.97875
如果假设正态分布,则确实表明存在显着差异。默认情况下,R 函数不假设两个样本中方差相等。我们可以使用 F 检验来检验方差是否相等,前提是两个样本来自正态总体。
> var.test(A, B) F test to compare two variances data: A and B F = 0.5837, num df = 12, denom df = 7, p-value = 0.3938 alternative hypothesis: true ratio of variances is not equal to 1 95 percent confidence interval: 0.1251097 2.1052687 sample estimates: ratio of variances 0.5837405
这表明没有显着差异的证据,因此我们可以使用假设方差相等的经典 t 检验。
> t.test(A, B, var.equal=TRUE) Two Sample t-test data: A and B t = 3.4722, df = 19, p-value = 0.002551 alternative hypothesis: true difference in means is not equal to 0 95 percent confidence interval: 0.01669058 0.06734788 sample estimates: mean of x mean of y 80.02077 79.97875
所有这些测试都假设两个样本的正态性。双样本 Wilcoxon(或 Mann-Whitney)检验仅假设零假设下的公共连续分布。
> wilcox.test(A, B) Wilcoxon rank sum test with continuity correction data: A and B W = 89, p-value = 0.007497 alternative hypothesis: true location shift is not equal to 0 Warning message: Cannot compute exact p-value with ties in: wilcox.test(A, B)
注意警告:每个样本中都有多个平局,这强烈表明这些数据来自离散分布(可能是由于舍入)。
有几种方法可以直观地比较两个样本。我们已经看到了一对箱线图。以下
> plot(ecdf(A), do.points=FALSE, verticals=TRUE, xlim=range(A, B)) > plot(ecdf(B), do.points=FALSE, verticals=TRUE, add=TRUE)
将显示两个经验 CDF,而 qqplot
将执行两个样本的 Q-Q 图。假设公共连续分布,Kolmogorov-Smirnov 检验是两个 ecdf 之间最大垂直距离
> ks.test(A, B) Two-sample Kolmogorov-Smirnov test data: A and B D = 0.5962, p-value = 0.05919 alternative hypothesis: two-sided Warning message: cannot compute correct p-values with ties in: ks.test(A, B)
R 是一种表达式语言,其唯一命令类型是返回结果的函数或表达式。即使是赋值也是一个表达式,其结果是赋值的值,并且可以在任何可以使用表达式的任何地方使用它;特别是,可以进行多个赋值。
命令可以分组在大括号中,{expr_1; …; expr_m}
,在这种情况下,组的值是组中最后一个表达式的结果评估。由于这样的组也是一个表达式,因此它可以(例如)本身包含在括号中并用作更大表达式的部分,依此类推。
if
语句 ¶语言提供了一个形式为条件结构
> if (expr_1) expr_2 else expr_3
其中 expr_1 必须计算为单个逻辑值,然后整个表达式的结果显而易见。
“短路”运算符 &&
和 ||
通常用作 if
语句中条件的一部分。虽然 &
和 |
按元素应用于向量,但 &&
和 ||
应用于长度为一的向量,并且仅在必要时计算其第二个参数。
有一个 if
/else
结构的向量化版本,即 ifelse
函数。它的形式为 ifelse(condition, a, b)
,并返回一个与 condition
长度相同的向量,其中元素为 a[i]
(如果 condition[i]
为真),否则为 b[i]
(其中 a
和 b
根据需要进行回收)。
for
循环、repeat
和 while
¶还有一个 for
循环结构,形式为
> for (name
in expr_1) expr_2
其中 name
是循环变量。 expr_1 是一个向量表达式(通常是类似 1:20
的序列),而 expr_2 通常是一个分组表达式,其子表达式用虚拟 name 编写。 expr_2 会重复计算,因为 name 遍历 expr_1 的向量结果中的值。
例如,假设 ind
是类指示符的向量,我们希望生成 y
相对于 x
的各个类别的单独绘图。这里的一种可能性是使用 coplot()
,20 它将生成与因子的每个级别相对应的绘图数组。另一种方法是将所有绘图放在一个显示中,如下所示
> xc <- split(x, ind) > yc <- split(y, ind) > for (i in 1:length(yc)) { plot(xc[[i]], yc[[i]]) abline(lsfit(xc[[i]], yc[[i]])) }
(请注意函数 split()
,它生成一个向量列表,该列表是通过根据因子指定的类别拆分一个较大的向量而获得的。这是一个有用的函数,主要用于与箱形图相关联。有关更多详细信息,请参阅 help
工具。)
警告:在 R 代码中,
for()
循环的使用频率远低于编译语言。采用“整个对象”视图的代码在 R 中可能既更清晰又更快。
其他循环工具包括
> repeat expr
语句和
> while (condition) expr
语句。
break
语句可用于终止任何循环,可能是异常终止。这是终止 repeat
循环的唯一方法。
控制语句最常与函数结合使用,这些函数在 编写您自己的函数 中讨论,并且会出现更多示例。
正如我们在沿途非正式地看到的那样,R 语言允许用户创建模式为函数的对象。这些是存储在特殊内部形式中的真正 R 函数,可以在进一步的表达式等中使用。在这个过程中,该语言在功能、便利性和优雅性方面获得了极大的提升,学习编写有用的函数是让您使用 R 变得舒适和高效的主要方法之一。
值得强调的是,R 系统中提供的大多数函数,例如 mean()
、var()
、postscript()
等,都是用 R 编写的,因此与用户编写的函数在实质上没有区别。
函数通过以下形式的赋值来定义
> name <- function(arg_1, arg_2, ...) expression
expression 是一个 R 表达式(通常是一个分组表达式),它使用参数 arg_i 来计算一个值。表达式的值是函数返回的值。
对函数的调用通常采用以下形式 name(expr_1, expr_2, …)
,并且可以在函数调用合法的地方出现。
作为一个第一个示例,考虑一个函数来计算两个样本 t 统计量,显示“所有步骤”。当然,这是一个人工示例,因为还有其他更简单的方法来实现相同目的。
函数定义如下
> twosam <- function(y1, y2) { n1 <- length(y1); n2 <- length(y2) yb1 <- mean(y1); yb2 <- mean(y2) s1 <- var(y1); s2 <- var(y2) s <- ((n1-1)*s1 + (n2-1)*s2)/(n1+n2-2) tst <- (yb1 - yb2)/sqrt(s*(1/n1 + 1/n2)) tst }
在此函数定义后,您可以使用如下调用执行两个样本 t 检验
> tstat <- twosam(data$male, data$female); tstat
作为一个第二个示例,考虑一个函数来直接模拟 MATLAB 反斜杠命令,该命令返回向量 y 在矩阵 X 的列空间上的正交投影的系数。(这通常称为回归系数的最小二乘估计。)通常使用 qr()
函数来完成此操作;但是,直接使用它有时有点棘手,并且值得拥有一个简单的函数(例如以下函数)来安全地使用它。
因此,给定一个 n 乘 1 向量 y 和一个 n 乘 p 矩阵 X,则 X \ y 定义为 (X’X)^{-}X’y,其中 (X’X)^{-} 是 X'X 的广义逆。
> bslash <- function(X, y) { X <- qr(X) qr.coef(X, y) }
创建此对象后,可以在语句中使用它,例如
> regcoeff <- bslash(Xmat, yvar)
等等。
经典 R 函数 lsfit()
可以很好地完成此工作,还有更多21。它反过来以略微违反直觉的方式使用函数 qr()
和 qr.coef()
来完成计算的这一部分。因此,如果经常使用,那么将这一部分单独隔离在一个易于使用的函数中可能具有一定价值。如果是这样,我们可能希望将其设为矩阵二元运算符,以便更方便地使用。
如果我们给 bslash()
函数一个不同的名称,即以下形式之一
%anything%
它可以用作表达式中的二元运算符,而不是函数形式。例如,假设我们选择 !
作为内部字符。然后,函数定义将以以下形式开始
> "%!%" <- function(X, y) { ... }
(注意引号的使用方式。)然后,该函数可以用作 X %!% y
。(反斜杠符号本身不是一个方便的选择,因为它在此上下文中会出现特殊问题。)
矩阵乘法运算符 %*%
和外积矩阵运算符 %o%
是以这种方式定义的其他二元运算符示例。
正如 生成常规序列 中首先指出的,如果以“name=object
”的形式给出对被调用函数的参数,则可以按任何顺序给出它们。此外,参数序列可以从未命名的位置形式开始,并在位置参数之后指定命名参数。
因此,如果有一个由以下内容定义的函数 fun1
> fun1 <- function(data, data.frame, graph, limit) {
[function body omitted]
}
那么可以以多种方式调用该函数,例如
> ans <- fun1(d, df, TRUE, 20) > ans <- fun1(d, df, graph=TRUE, limit=20) > ans <- fun1(data=d, limit=20, graph=TRUE, data.frame=df)
都是等效的。
在很多情况下,参数可以赋予通常合适的默认值,在这种情况下,当默认值合适时,可以完全从调用中省略它们。例如,如果将 fun1
定义为
> fun1 <- function(data, data.frame, graph=TRUE, limit=20) { ... }
可以将其调用为
> ans <- fun1(d, df)
这现在等效于上述三个情况,或者作为
> ans <- fun1(d, df, limit=10)
这会更改其中一个默认值。
需要注意的是,默认值可以是任意表达式,甚至涉及同一函数的其他参数;它们不必像我们这里简单的示例那样被限制为常量。
另一个常见要求是允许一个函数将参数设置传递给另一个函数。例如,许多图形函数使用函数 par()
,而 plot()
等函数允许用户将图形参数传递给 par()
以控制图形输出。(有关 par()
函数的更多详细信息,请参见永久更改:par()
函数。)这可以通过在函数中包含一个额外的参数(从字面上讲为 ‘…’)来完成,然后可以传递该参数。下面给出了一个概要示例。
fun1 <- function(data, data.frame, graph=TRUE, limit=20, ...) { [omitted statements] if (graph) par(pch="*", ...) [more omissions] }
不太常见的是,函数需要引用 ‘…’ 的组件。表达式 list(...)
会计算所有此类参数,并将它们以命名列表的形式返回,而 ..1
、..2
等会一次计算一个参数,其中 ‘..n’ 返回第 n 个未匹配的参数。
请注意,在函数中执行的任何普通赋值都是局部且临时的,在退出函数后将丢失。因此,赋值 X <- qr(X)
不会影响调用程序中参数的值。
要完全理解控制 R 赋值范围的规则,读者需要熟悉评估框架的概念。这是一个有点高级但并不难的主题,这里不再赘述。
如果在函数中打算进行全局且永久的赋值,则可以使用“超赋值”运算符 <<-
或函数 assign()
。有关详细信息,请参阅 help
文档。
作为一个更完整(尽管有点平淡)的函数示例,考虑查找块设计的效率因子。(此问题的某些方面已在 索引矩阵 中讨论。)
块设计由两个因子定义,例如 blocks
(b
级)和 varieties
(v
级)。如果 R 和 K 分别是 v 乘 v 和 b 乘 b 的重复和块大小矩阵,而 N 是 b 乘 v 的关联矩阵,则效率因子定义为矩阵 E 的特征值,其中 E = I_v - R^{-1/2}N’K^{-1}NR^{-1/2} = I_v - A’A,其中 A = K^{-1/2}NR^{-1/2}。下面给出了编写函数的一种方法。
> bdeff <- function(blocks, varieties) { blocks <- as.factor(blocks) # minor safety move b <- length(levels(blocks)) varieties <- as.factor(varieties) # minor safety move v <- length(levels(varieties)) K <- as.vector(table(blocks)) # remove dim attr R <- as.vector(table(varieties)) # remove dim attr N <- table(blocks, varieties) A <- 1/sqrt(K) * N * rep(1/sqrt(R), rep(b, v)) sv <- svd(A) list(eff=1 - sv$d^2, blockcv=sv$u, varietycv=sv$v) }
在此情况下,使用奇异值分解比使用特征值例程在数值上稍微好一些。
该函数的结果是一个列表,不仅提供效率因子作为第一个分量,还提供块和品种典型对比,因为有时这些会提供额外的有用定性信息。
对于大型矩阵或数组的打印目的,通常很有用以紧凑的块形式打印它们,而无需数组名称或数字。删除dimnames
属性不会产生此效果,而是必须为数组指定一个由空字符串组成的dimnames
属性。例如,要打印一个矩阵X
> temp <- X > dimnames(temp) <- list(rep("", nrow(X)), rep("", ncol(X))) > temp; rm(temp)
使用函数no.dimnames()
可以更方便地完成此操作,如下所示,作为“包装”以实现相同的结果。它还说明了一些有效且有用的用户函数可以非常短。
no.dimnames <- function(a) {
## Remove all dimension names from an array for compact printing.
d <- list()
l <- 0
for(i in dim(a)) {
d[[l <- l + 1]] <- rep("", i)
}
dimnames(a) <- d
a
}
定义此函数后,可以使用以下方法以紧凑格式打印数组
> no.dimnames(X)
这对于大型整数数组特别有用,其中模式是真正的兴趣,而不是值。
函数可以是递归的,并且可以在自身内定义函数。但是,请注意,此类函数或变量不会像在搜索路径上一样被更高评估框架中的调用函数继承。
下面的示例展示了一种执行一维数值积分的简单方法。被积函数在范围的端点和中间进行评估。如果单面板梯形规则答案足够接近双面板,则后者将作为值返回。否则,将对每个面板递归应用相同的过程。结果是一个自适应积分过程,它将函数评估集中在被积函数最远离线性的区域。但是,开销很大,并且仅当被积函数既平滑又非常难以评估时,该函数才与其他算法具有竞争力。
该示例也部分作为 R 编程中的一个小难题给出。
area <- function(f, a, b, eps = 1.0e-06, lim = 10) {
fun1 <- function(f, a, b, fa, fb, a0, eps, lim, fun) {
## function ‘fun1’ is only visible inside ‘area’
d <- (a + b)/2
h <- (b - a)/4
fd <- f(d)
a1 <- h * (fa + fd)
a2 <- h * (fd + fb)
if(abs(a0 - a1 - a2) < eps || lim == 0)
return(a1 + a2)
else {
return(fun(f, a, d, fa, fd, a1, eps, lim - 1, fun) +
fun(f, d, b, fd, fb, a2, eps, lim - 1, fun))
}
}
fa <- f(a)
fb <- f(b)
a0 <- ((fa + fb) * (b - a))/2
fun1(f, a, b, fa, fb, a0, eps, lim, fun1)
}
本节中的讨论比本文档其他部分的技术性更强。但是,它详细说明了 S-PLUS 和 R 之间的一个主要区别。
函数体中出现的符号可分为三类;形式参数、局部变量和自由变量。函数的形式参数是出现在函数参数列表中的那些。它们的值由将实际函数参数绑定到形式参数的过程确定。局部变量是其值由函数体中表达式的求值确定的那些。不是形式参数或局部变量的变量称为自由变量。如果自由变量被赋值,则它们将变为局部变量。考虑以下函数定义。
f <- function(x) { y <- 2*x print(x) print(y) print(z) }
在此函数中,x
是形式参数,y
是局部变量,z
是自由变量。
在 R 中,首先在创建函数的环境中查找来解析自由变量绑定。这称为词法作用域。首先,我们定义一个名为 cube
的函数。
cube <- function(n) { sq <- function() n*n n*sq() }
函数 sq
中的变量 n
不是该函数的参数。因此,它是一个自由变量,并且必须使用作用域规则来确定与它关联的值。在静态作用域 (S-PLUS) 下,该值与名为 n
的全局变量相关联。在词法作用域 (R) 下,它是函数 cube
的参数,因为这是定义函数 sq
时变量 n
的活动绑定。在 R 中求值和在 S-PLUS 中求值之间的区别在于,S-PLUS 查找名为 n
的全局变量,而 R 首先在调用 cube
时创建的环境中查找名为 n
的变量。
## first evaluation in S S> cube(2) Error in sq(): Object "n" not found Dumped S> n <- 3 S> cube(2) [1] 18 ## then the same function evaluated in R R> cube(2) [1] 8
词法作用域还可以用于为函数赋予可变状态。在以下示例中,我们将展示如何使用 R 模拟银行账户。一个有效的银行账户需要有余额或总额、一个用于取款的函数、一个用于存款的函数以及一个用于说明当前余额的函数。我们通过在 account
中创建这三个函数,然后返回包含它们的列表来实现这一点。当调用 account
时,它会采用一个数字参数 total
,并返回一个包含这三个函数的列表。由于这些函数是在包含 total
的环境中定义的,因此它们将能够访问其值。
特殊赋值运算符 <<-
, 用于更改与 total
关联的值。此运算符会在封闭环境中向后查找包含符号 total
的环境,并且当它找到这样的环境时,它会用右侧的值替换该环境中的值。如果在未找到符号 total
的情况下到达全局或顶级环境,那么将创建该变量并将其分配到那里。对于大多数用户,<<-
会创建一个全局变量,并将右侧的值分配给它22。只有当在作为另一个函数的值返回的函数中使用了 <<-
时,才会发生此处描述的特殊行为。
open.account <- function(total) { list( deposit = function(amount) { if(amount <= 0) stop("Deposits must be positive!\n") total <<- total + amount cat(amount, "deposited. Your balance is", total, "\n\n") }, withdraw = function(amount) { if(amount > total) stop("You don't have that much money!\n") total <<- total - amount cat(amount, "withdrawn. Your balance is", total, "\n\n") }, balance = function() { cat("Your balance is", total, "\n\n") } ) } ross <- open.account(100) robert <- open.account(200) ross$withdraw(30) ross$balance() robert$balance() ross$deposit(50) ross$balance() ross$withdraw(500)
用户可以通过多种不同的方式自定义其环境。有一个站点初始化文件,并且每个目录都可以有自己的特殊初始化文件。最后,可以使用特殊函数 .First
和 .Last
。
网站初始化文件的位置取自 R_PROFILE
环境变量的值。如果该变量未设置,则使用 R 主目录 etc 中的文件 Rprofile.site。此文件应包含每次在您的系统下启动 R 时要执行的命令。第二个个人配置文件名为 .Rprofile23 可以放置在任何目录中。如果在该目录中调用 R,则会引用该文件。此文件让各个用户可以控制其工作区,并允许在不同的工作目录中使用不同的启动过程。如果在启动目录中找不到 .Rprofile 文件,则 R 会在用户的个人目录中查找 .Rprofile 文件并使用该文件(如果存在)。如果设置了环境变量 R_PROFILE_USER
,则会使用它指向的文件,而不是 .Rprofile 文件。
在两个配置文件或 .RData 映像中命名的任何函数 .First()
都有特殊状态。它会在 R 会话开始时自动执行,可用于初始化环境。例如,以下示例中的定义将提示符更改为 $
,并设置会话其余部分可以视为理所当然的其他各种有用内容。
因此,执行文件的顺序为 Rprofile.site、用户配置文件、.RData,然后是 .First()
。后面文件中的定义将屏蔽前面文件中的定义。
> .First <- function() {
options(prompt="$ ", continue="+\t") # $
is the prompt
options(digits=5, length=999) # custom numbers and printout
x11() # for graphics
par(pch = "+") # plotting character
source(file.path(Sys.getenv("HOME"), "R", "mystuff.R"))
# my personal functions
library(MASS) # attach a package
}
类似地,如果定义了函数 .Last()
,则通常会在会话的最后执行该函数。下面给出了一个示例。
> .Last <- function() { graphics.off() # a small safety measure. cat(paste(date(),"\nAdios\n")) # Is it time for lunch? }
对象的类决定了它将如何被所谓的泛型函数处理。换句话说,泛型函数对其参数执行特定于参数本身类的任务或操作。如果参数没有任何 class
属性,或者没有针对该泛型函数专门提供的类,则始终提供默认操作。
一个示例可以更清楚地说明。类机制为用户提供了设计和编写特殊用途泛型函数的功能。其他泛型函数包括用于以图形方式显示对象的 plot()
、用于汇总各种类型分析的 summary()
,以及用于比较统计模型的 anova()
。
可以以特定方式处理类的泛型函数的数量可能很大。例如,可以适应类 "data.frame"
对象的函数包括
[ [[<- any as.matrix [<- mean plot summary
可以使用 methods()
函数获取当前完整列表
> methods(class="data.frame")
相反,泛型函数可以处理的类数量也可以非常大。例如,plot()
函数具有默认方法和针对 "data.frame"
、"density"
、"factor"
等类的对象的变体。可以通过使用 methods()
函数再次获取完整列表
> methods(plot)
对于许多泛型函数,函数主体非常短,例如
> coef function (object, ...) UseMethod("coef")
UseMethod
的存在表示这是一个泛型函数。要查看可用的方法,我们可以使用 methods()
> methods(coef) [1] coef.aov* coef.Arima* coef.default* coef.listof* [5] coef.nls* coef.summary.nls* Non-visible functions are asterisked
在此示例中,有六种方法,通过键入其名称无法看到任何一种方法。我们可以通过以下任一种方法来读取它们
> getAnywhere("coef.aov") A single object matching ‘coef.aov’ was found It was found in the following places registered S3 method for coef from namespace stats namespace:stats with value function (object, ...) { z <- object$coef z[!is.na(z)] } > getS3method("coef", "aov") function (object, ...) { z <- object$coef z[!is.na(z)] }
泛型 gen
将调用名为 gen.cl
的函数以获取类 cl
,因此不要以这种样式命名函数,除非它们打算成为方法。
建议读者参阅 R 语言定义 以更全面地讨论此机制。
本节假定读者对统计方法有一定程度的熟悉,特别是对回归分析和方差分析。稍后,我们做出了一些更大胆的假设,即对广义线性模型和非线性回归有所了解。
对统计模型进行拟合的要求定义得足够好,从而可以构建适用于广泛问题的通用工具。
R 提供了一套相互关联的工具,使得拟合统计模型非常简单。正如我们在引言中提到的,基本输出是最小的,需要通过调用提取器函数来询问详细信息。
统计模型的模板是具有独立同方差误差的线性回归模型
y_i = sum_{j=0}^p beta_j x_{ij} + e_i, i = 1, ..., n,
其中 e_i 是 NID(0, sigma^2)。用矩阵形式表示如下
y = X beta + e
其中 y 是响应向量,X 是 模型矩阵 或 设计矩阵,具有列 x_0, x_1, ..., x_p,即确定变量。通常 x_0 将是一列定义 截距 项的 1。
在给出正式规范之前,一些示例可能有助于设置图片。
假设 y
、x
、x0
、x1
、x2
等是数值变量,X
是一个矩阵,A
、B
、C
等是因子。下面左侧的公式指定了右侧描述的统计模型。
y ~ x
y ~ 1 + x
这两个公式都隐含了 y 对 x 的相同简单线性回归模型。第一个具有隐式截距项,第二个具有显式截距项。
y ~ 0 + x
y ~ -1 + x
y ~ x - 1
y 对 x 的简单线性回归通过原点(即没有截距项)。
log(y) ~ x1 + x2
对转换变量 log(y) 的多元回归,对 x1 和 x2(具有隐式截距项)。
y ~ poly(x,2)
y ~ 1 + x + I(x^2)
y 对 x 的 2 次多项式回归。第一种形式使用正交多项式,第二种形式使用显式幂作为基础。
y ~ X + poly(x,2)
多元回归 y,其模型矩阵由矩阵 X 以及 x 中的 2 次多项式项组成。
y ~ A
由 A 确定的类别的 y 的单分类方差分析模型。
y ~ A + x
由 A 确定的类别的 y 的单分类协方差分析模型,其中协变量为 x。
y ~ A*B
y ~ A + B + A:B
y ~ B %in% A
y ~ A/B
y 在 A 和 B 上的二因子非加性模型。前两个指定相同的交叉分类,后两个指定相同的嵌套分类。从抽象意义上讲,所有四个都指定相同的模型子空间。
y ~ (A + B + C)^2
y ~ A*B*C - A:B:C
三因子实验,但模型仅包含主效应和二因子交互作用。这两个公式指定相同的模型。
y ~ A * x
y ~ A/x
y ~ A/(1 + x) - 1
y 在 A 的级别内在 x 上的独立简单线性回归模型,具有不同的编码。最后一种形式生成与 A 中的级别一样多的不同截距和斜率的明确估计值。
y ~ A*B + Error(C)
一个具有两个处理因子(A 和 B)的实验,以及由因子 C 确定的误差层。例如,一个裂区实验,其中全区(因此还有子区)由因子 C 确定。
运算符 ~
用于在 R 中定义一个 模型公式。对于普通线性模型,形式为
response ~ op_1 term_1 op_2 term_2 op_3 term_3 ...
其中
是一个向量或矩阵(或求值为向量或矩阵的表达式),定义响应变量。
是一个运算符,即 +
或 -
,表示在模型中包含或排除一个项(第一个是可选的)。
要么是
1
,
在所有情况下,每个项都定义了一组要添加到模型矩阵或从中删除的列。一个 1
代表一个截距列,并且默认情况下包含在模型矩阵中,除非明确删除。
这些 公式运算符 的效果类似于 Glim 和 Genstat 等程序使用的 Wilkinson 和 Rogers 符号。一个不可避免的更改是运算符 ‘.
’ 变为 ‘:
’,因为句点是 R 中有效的名称字符。
符号总结如下(基于 Chambers & Hastie,1992 年,第 29 页)
Y ~ M
Y 被建模为 M。
M_1 + M_2
包含 M_1 和 M_2。
M_1 - M_2
包含 M_1,省略 M_2 的项。
M_1 : M_2
M_1 和 M_2 的张量积。如果两个项都是因子,则“子类”因子。
M_1 %in% M_2
类似于 M_1:M_2
,但编码不同。
M_1 * M_2
M_1 + M_2 + M_1:M_2
.
M_1 / M_2
M_1 + M_2 %in% M_1
.
M^n
M 中的所有项以及与 n 阶“交互”项
I(M)
隔离 M。在 M 内部,所有运算符都有其常规算术含义,并且该项出现在模型矩阵中。
请注意,在通常括起函数参数的括号内,所有运算符都有其常规算术含义。函数 I()
是一个恒等函数,用于允许使用算术运算符定义模型公式中的项。
特别注意,模型公式指定模型矩阵的列,参数的指定是隐式的。在其他情况下并非如此,例如在指定非线性模型时。
我们需要至少了解一些有关模型公式如何指定模型矩阵列的想法。如果我们有连续变量,这很容易,因为每个变量提供模型矩阵的一列(如果模型中包含截距,则截距将提供一列)。
关于k级因子A
怎么样?对于无序因子和有序因子,答案不同。对于无序因子,为因子的第二、…、k级指示符生成了k - 1列。(因此,隐式参数化是将每个级别的响应与第一级的响应进行对比。)对于有序因子,k - 1列是1, ..., k上的正交多项式,省略了常数项。
尽管答案已经很复杂,但这并不是全部。首先,如果在包含因子项的模型中省略截距,则第一个此类项将编码为k列,给出所有级别的指示符。其次,contrasts
的options
设置可以更改整个行为。R 中的默认设置是
options(contrasts = c("contr.treatment", "contr.poly"))
提及此原因的主要原因是 R 和 S 对无序因子有不同的默认值,S 使用 Helmert 对比。因此,如果您需要将您的结果与使用S-PLUS的教科书或论文的结果进行比较,您将需要设置
options(contrasts = c("contr.helmert", "contr.poly"))
这是一个故意的差异,因为处理对比(R 的默认值)被认为更容易让新手理解。
我们还没有完成,因为可以使用函数contrasts
和C
为模型中的每个项设置要使用的对比方案。
我们尚未考虑交互项:这些项生成为其组成项引入的列的乘积。
尽管细节很复杂,但 R 中的模型公式通常会生成专家统计学家期望的模型,前提是保留边际性。例如,拟合具有交互作用但没有相应主效应的模型通常会导致令人惊讶的结果,并且仅适用于专家。
用于拟合普通多元模型的基本函数是lm()
,并且调用的精简版本如下:
> fitted.model <- lm(formula, data = data.frame)
例如
> fm2 <- lm(y ~ x1 + x2, data = production)
将拟合y在x1和x2上的多元回归模型(具有隐式截距项)。
重要的(但在技术上是可选的)参数data = production
指定用于构建模型的任何变量都应首先来自production
数据框。 无论数据框production
是否已附加到搜索路径上,情况都是如此。
的值是一个拟合模型对象;从技术上讲,它是 lm()
类的结果列表。然后,可以使用面向 "lm"
类的对象的通用函数来显示、提取、绘制拟合模型的信息,依此类推。这些函数包括
"lm"
add1 deviance formula predict step alias drop1 kappa print summary anova effects labels proj vcov coef family plot residuals
下面简要介绍最常用的函数。
anova(object_1, object_2)
¶将子模型与外部模型进行比较,并生成方差分析表。
coef(object)
¶提取回归系数(矩阵)。
长格式:coefficients(object)
。
deviance(object)
¶残差平方和,如果适用,则加权。
formula(object)
¶提取模型公式。
plot(object)
¶生成四个图,显示残差、拟合值和一些诊断信息。
predict(object, newdata=data.frame)
¶提供的数据框必须具有与原始数据框具有相同标签的变量。该值是与 data.frame 中的决定变量值对应的预测值向量或矩阵。
print(object)
¶打印对象的简洁版本。最常隐式使用。
residuals(object)
¶提取(残差的)矩阵,并根据需要加权。
简短格式:resid(object)
。
step(object)
¶通过添加或删除项并保留层次结构来选择合适的模型。返回在逐步搜索中发现的 AIC(赤池信息准则)值最小的模型。
summary(object)
¶打印回归分析结果的综合摘要。
vcov(对象)
¶返回已拟合模型对象的各个主要参数的协方差矩阵。
模型拟合函数 aov(公式, data=数据框)
以非常类似于函数 lm()
的方式在最简单的层面上操作,并且 用于提取模型信息的通用函数 表格中列出的大多数通用函数都适用。
需要注意的是,除了 aov()
之外,还可以分析具有多个误差层级的模型,例如分割小区实验或具有块间信息恢复的平衡不完全区组设计。模型公式
response ~ mean.formula + Error(strata.formula)
指定了一个多层级实验,其误差层级由 层级公式 定义。在最简单的情况下,层级公式 只是一个因子,当它定义一个两层级实验时,即在因子的层级之间和内部。
例如,对于所有决定变量因子,类似于
> fm <- aov(yield ~ v + n*p*k + Error(farms/blocks), data=farm.data)
中的模型公式通常用于描述具有均值模型 v + n*p*k
和三个误差层级的实验,即“农场间”、“农场内,区组间”和“区组内”。
还要注意,方差分析表(或表格)是针对一系列拟合模型的。显示的平方和是残差平方和的减少,这是由于在序列中该项在模型中该位置包含而导致的。因此,只有对于正交实验,包含顺序才会无关紧要。
对于多层实验,该过程首先是将响应投影到误差层,同样是按顺序,并将均值模型拟合到每个投影。有关更多详细信息,请参阅 Chambers & Hastie (1992)。
与默认完整 ANOVA 表相比,一种更灵活的替代方法是使用 anova()
函数直接比较两个或更多模型。
> anova(fitted.model.1, fitted.model.2, ...)
然后,显示一个 ANOVA 表,显示按顺序拟合时拟合模型之间的差异。当然,正在比较的拟合模型通常是分层序列。这并不会提供与默认不同的信息,而是使其更容易理解和控制。
update()
函数在很大程度上是一个便利函数,它允许拟合一个与之前拟合的模型不同的模型,通常只是增加或删除一些项。它的形式是
> new.model <- update(old.model, new.formula)
在 new.formula 中,由一个句点组成的特殊名称“.
”, 只能用于表示“旧模型公式的对应部分”。例如,
> fm05 <- lm(y ~ x1 + x2 + x3 + x4 + x5, data = production) > fm6 <- update(fm05, . ~ . + x6) > smf6 <- update(fm6, sqrt(.) ~ .)
将拟合一个五变量多元回归,其中变量(可能)来自数据框 production
,拟合一个包含第六个回归变量的附加模型,并拟合一个响应应用了平方根变换的模型的变体。
特别注意,如果在对模型拟合函数的原始调用中指定了 data=
参数,则此信息将通过拟合模型对象传递给 update()
及其关联函数。
名称“.”还可以在其他上下文中使用,但含义略有不同。例如
> fmfull <- lm(y ~ . , data = production)
将拟合一个响应为 y
和回归变量为数据框 production
中所有其他变量的模型。
用于探索模型增量序列的其他函数是 add1()
、drop1()
和 step()
。 这些名称很好地提示了它们的目的,但有关完整详细信息,请参阅在线帮助。
广义线性建模是线性模型的开发,它以简洁直接的方式适应非正态响应分布和线性变换。广义线性模型可以通过以下一系列假设来描述
eta = beta_1 x_1 + beta_2 x_2 + ... + beta_p x_p,
因此,当且仅当 beta_i 为零时,x_i 对 y 的分布没有影响。
f_Y(y; mu, phi) = exp((A/phi) * (y lambda(mu) - gamma(lambda(mu))) + tau(y, phi))
其中 phi 是 尺度参数(可能已知),并且对于所有观测值都是常数,A 表示先验权重,假设已知但可能随观测值而变化,并且 $\mu$ 是 y 的均值。因此,假设 y 的分布由其均值和可能的尺度参数决定。
mu = m(eta), eta = m^{-1}(mu) = ell(mu)
并且此逆函数 ell() 称为 链接函数。
这些假设足够宽松,可以涵盖统计实践中有用的广泛模型,但又足够严格,可以开发出一种统一的估计和推理方法,至少是近似的。读者可以参阅任何当前关于该主题的参考著作以获取完整详细信息,例如 McCullagh & Nelder (1989) 或 Dobson (1990)。
R 中提供的工具处理的广义线性模型类别包括 gaussian、binomial、poisson、inverse gaussian 和 gamma 响应分布,还包括响应分布未明确指定的 quasi-likelihood 模型。在后一种情况下,方差函数 必须指定为均值的函数,但在其他情况下,此函数由响应分布隐含。
每个响应分布都允许使用各种链接函数将均值与线性预测器联系起来。自动可用的链接函数显示在以下表格中
族名称 链接函数 binomial
logit
、probit
、log
、cloglog
gaussian
identity
、log
、inverse
Gamma
identity
、inverse
、log
inverse.gaussian
1/mu^2
、identity
、inverse
、log
poisson
identity
、log
、sqrt
quasi
logit
、probit
、cloglog
、identity
、inverse
、log
、1/mu^2
、sqrt
响应分布、链接函数以及执行建模练习所需的其他各种信息的组合称为广义线性模型的 族。
glm()
函数 ¶由于响应的分布仅通过单个线性函数依赖于刺激变量,因此,用于线性模型的机制仍然可用于指定广义模型的线性部分。族必须以不同的方式指定。
用于拟合广义线性模型的 R 函数是 glm()
,它使用以下形式
> fitted.model <- glm(formula, family=family.generator, data=data.frame)
唯一的新特性是 family.generator,它是描述族的工具。它是生成函数和表达式的列表的函数的名称,这些函数和表达式共同定义和控制模型和估计过程。尽管乍看之下这似乎有点复杂,但它的用法非常简单。
标准、提供的族生成器的名称在 族 表中的“族名称”下给出。在存在链接选择的情况下,链接名称也可以作为参数用括号与族名称一起提供。对于 quasi
族,方差函数也可以用这种方式指定。
一些示例可以使流程清晰明了。
gaussian
族 ¶如下调用
> fm <- glm(y ~ x1 + x2, family = gaussian, data = sales)
与如下调用实现相同的结果
> fm <- lm(y ~ x1+x2, data=sales)
但效率低得多。请注意,gaussian 族不会自动提供链接选择,因此不允许参数。如果问题需要具有非标准链接的 gaussian 族,通常可以通过 quasi
族实现,我们稍后会看到。
binomial
族 ¶考虑 Silvey (1970) 中的一个小型人工示例。
在爱琴海的卡利索斯岛上,男性居民患有先天性眼疾,其影响会随着年龄的增长而加剧。对不同年龄的岛民男性进行了失明测试并记录了结果。数据如下所示
年龄 | 20 | 35 | 45 | 55 | 70 |
受试人数 | 50 | 50 | 50 | 50 | 50 |
失明人数 | 6 | 17 | 26 | 37 | 44 |
我们考虑的问题是为这些数据拟合逻辑回归和概率模型,并为每个模型估算 LD50,即男性居民失明几率为 50% 的年龄。
如果 y 是 x 岁的失明人数,n 是受试人数,则这两个模型的形式均为 y ~ B(n, F(beta_0 + beta_1 x)),其中对于概率情况,F(z) = Phi(z) 是标准正态分布函数,而在 logit 情况下(默认),F(z) = e^z/(1+e^z)。在这两种情况下,LD50 为 LD50 = - beta_0/beta_1,即分布函数参数为零的点。
第一步是将数据设置为数据框
> kalythos <- data.frame(x = c(20,35,45,55,70), n = rep(50,5), y = c(6,17,26,37,44))
要使用 glm()
拟合二项模型,响应有三种可能性
这里我们需要第二个约定,因此我们向数据帧添加一个矩阵
> kalythos$Ymat <- cbind(kalythos$y, kalythos$n - kalythos$y)
为了拟合模型,我们使用
> fmp <- glm(Ymat ~ x, family = binomial(link=probit), data = kalythos) > fml <- glm(Ymat ~ x, family = binomial, data = kalythos)
由于 logit 链接是默认值,因此可以在第二次调用时省略参数。要查看每个拟合的结果,我们可以使用
> summary(fmp) > summary(fml)
两个模型都非常适合(甚至太适合了)。要查找 LD50 估计值,我们可以使用一个简单函数
> ld50 <- function(b) -b[1]/b[2] > ldp <- ld50(coef(fmp)); ldl <- ld50(coef(fml)); c(ldp, ldl)
此数据中的实际估计值分别为 43.663 年和 43.601 年。
对于泊松族,默认链接是 log
,实际上,此族的用途主要在于拟合频率数据的替代泊松对数线性模型,其实际分布通常是多项式分布。这是一个庞大而重要的主题,我们在此不做进一步讨论。它甚至构成了非高斯广义模型整体使用的一个主要部分。
偶尔,泊松数据会在实践中真正出现,并且在过去,它通常在对数或平方根转换后作为高斯数据进行分析。作为后者的优雅替代方案,可以拟合泊松广义线性模型,如下例所示
> fmod <- glm(y ~ A + B + x, family = poisson(link=sqrt), data = worm.counts)
对于所有族,响应的方差将取决于均值,并将具有比例参数作为乘数。方差对均值的依赖形式是响应分布的特征;例如,对于泊松分布,Var(y) = mu。
对于拟似似然估计和推理,没有指定精确的响应分布,而只指定了链接函数和方差函数的形式,因为它取决于均值。由于拟似似然估计使用与高斯分布形式相同的技术,因此顺便说一句,此族提供了一种拟合具有非标准链接函数或方差函数的高斯模型的方法。
例如,考虑拟合非线性回归 y = theta_1 z_1 / (z_2 - theta_2) + e,也可以将其另写为 y = 1 / (beta_1 x_1 + beta_2 x_2) + e,其中 x_1 = z_2/z_1,x_2 = -1/z_1,beta_1 = 1/theta_1,beta_2 = theta_2/theta_1。假设设置了合适的 data 帧,我们可以拟合此非线性回归,如下所示
> nlfit <- glm(y ~ x1 + x2 - 1, family = quasi(link=inverse, variance=constant), data = biochem)
读者可参阅手册和帮助文档以获取更多信息(视需要而定)。
某些形式的非线性模型可以通过广义线性模型 (glm()
) 进行拟合。但在大多数情况下,我们必须将非线性曲线拟合问题当作非线性优化问题来处理。R 的非线性优化例程是 optim()
、nlm()
和 nlminb()
, 我们寻求最小化某些拟合度不足指标的参数值,它们通过迭代尝试各种参数值来实现这一点。例如,与线性回归不同,无法保证该过程会收敛于令人满意的估计值。所有方法都需要关于要尝试的参数值的初始猜测,并且收敛可能极大地取决于起始值的质量。
拟合非线性模型的一种方法是通过最小化平方误差和 (SSE) 或残差。如果观测误差可能合理地源自正态分布,则此方法有意义。
以下是 Bates & Watts (1988) 第 51 页中的一个示例。数据是
> x <- c(0.02, 0.02, 0.06, 0.06, 0.11, 0.11, 0.22, 0.22, 0.56, 0.56, 1.10, 1.10) > y <- c(76, 47, 97, 107, 123, 139, 159, 152, 191, 201, 207, 200)
要最小化的拟合准则是
> fn <- function(p) sum((y - (p[1] * x)/(p[2] + x))^2)
为了进行拟合,我们需要参数的初始估计值。找到合理起始值的一种方法是绘制数据,猜测一些参数值,并使用这些值叠加模型曲线。
> plot(x, y) > xfit <- seq(.02, 1.1, .05) > yfit <- 200 * xfit/(0.1 + xfit) > lines(spline(xfit, yfit))
我们可以做得更好,但 200 和 0.1 的起始值似乎足够了。现在进行拟合
> out <- nlm(fn, p = c(200, 0.1), hessian = TRUE)
拟合后,out$minimum
是 SSE,out$estimate
是参数的最小二乘估计值。要获得估计值的近似标准误差 (SE),我们执行
> sqrt(diag(2*out$minimum/(length(y) - 2) * solve(out$hessian)))
上面一行中减去的 2
表示参数的数量。95% 置信区间将是参数估计值 +/- 1.96 SE。我们可以将最小二乘拟合叠加到新绘图中
> plot(x, y) > xfit <- seq(.02, 1.1, .05) > yfit <- 212.68384222 * xfit/(0.06412146 + xfit) > lines(spline(xfit, yfit))
标准包 stats 为通过最小二乘法拟合非线性模型提供了更广泛的工具。我们刚刚拟合的模型是 Michaelis-Menten 模型,因此我们可以使用
> df <- data.frame(x=x, y=y) > fit <- nls(y ~ SSmicmen(x, Vm, K), df) > fit Nonlinear regression model model: y ~ SSmicmen(x, Vm, K) data: df Vm K 212.68370711 0.06412123 residual sum-of-squares: 1195.449 > summary(fit) Formula: y ~ SSmicmen(x, Vm, K) Parameters: Estimate Std. Error t value Pr(>|t|) Vm 2.127e+02 6.947e+00 30.615 3.24e-11 K 6.412e-02 8.281e-03 7.743 1.57e-05 Residual standard error: 10.93 on 10 degrees of freedom Correlation of Parameter Estimates: Vm K 0.7651
最大似然是一种非线性模型拟合方法,即使误差不呈正态分布也可以应用。该方法找到使对数似然函数最大化(或等效地使负对数似然函数最小化)的参数值。以下是 Dobson (1990) 第 108-111 页的一个示例。此示例将逻辑模型拟合到剂量反应数据,显然也可以通过 glm()
进行拟合。数据为
> x <- c(1.6907, 1.7242, 1.7552, 1.7842, 1.8113, 1.8369, 1.8610, 1.8839) > y <- c( 6, 13, 18, 28, 52, 53, 61, 60) > n <- c(59, 60, 62, 56, 63, 59, 62, 60)
要最小化的负对数似然函数为
> fn <- function(p) sum( - (y*(p[1]+p[2]*x) - n*log(1+exp(p[1]+p[2]*x)) + log(choose(n, y)) ))
我们选择合理的起始值并进行拟合
> out <- nlm(fn, p = c(-50,20), hessian = TRUE)
拟合后,out$minimum
是负对数似然函数,out$estimate
是参数的最大似然估计值。要获得估计值的近似 SE,我们执行
> sqrt(diag(solve(out$hessian)))
95% 置信区间为参数估计值 +/- 1.96 SE。
我们用简要介绍 R 中可用于特殊回归和数据分析问题的其他一些工具来结束本章。
lme()
和 nlme()
,用于线性混合效应模型和非线性混合效应模型,即某些系数对应于随机效应的线性和非线性回归。这些函数大量使用公式来指定模型。
loess()
函数通过使用局部加权回归来拟合非参数回归。此类回归对于突出杂乱数据中的趋势或对数据进行简化以深入了解大型数据集非常有用。
lqs
为高抗性拟合提供了最先进的算法。在包中提供了不太抗性但统计上更有效的方法,例如包 MASS 中的函数 rlm
。
avas
和 ace
以及包 mda 中的函数 bruto
和 mars
提供了 R 中用户贡献包中这些技术的示例。扩展是 广义加性模型,在用户贡献包 gam 和 mgcv 中实现。
模型再次以普通线性模型形式指定。模型拟合函数是 tree()
, 但许多其他通用函数(如 plot()
和 text()
)非常适合以图形方式显示基于树的模型拟合的结果。
图形工具是 R 环境中一个重要且极其通用的组件。可以使用该工具显示各种统计图形,还可以创建完全新类型的图形。
图形工具可在交互模式和批处理模式下使用,但在大多数情况下,交互使用更有效。交互使用也很容易,因为在启动时,R 会启动一个图形设备驱动程序,该驱动程序会打开一个特殊的图形窗口以显示交互式图形。虽然这是自动完成的,但了解所使用的命令在 UNIX 下是 X11()
、在 Windows 下是 windows()
、在 macOS 下是 quartz()
可能很有用。始终可以通过 dev.new()
打开新设备。
设备驱动程序运行后,可以使用 R 绘图命令生成各种图形显示并创建完全新类型的显示。
绘图命令分为三类基本组
此外,R 维护了一个图形参数列表,可以对其进行操作以自定义绘图。
本手册仅描述所谓的“基本”图形。程序包 grid 中的单独图形子系统与基本图形共存——它更强大,但更难使用。有一个推荐的程序包 lattice,它建立在 grid 的基础上,并提供生成类似于 S 中Trellis 系统中的多面板绘图的方法。
高级绘图函数旨在生成作为函数参数传递的数据的完整绘图。在适当的情况下,会自动生成坐标轴、标签和标题(除非您另有要求)。高级绘图命令始终会启动一个新绘图,必要时会擦除当前绘图。
plot()
函数 ¶R 中使用最频繁的绘图函数之一是 plot()
函数。这是一个泛型函数:所生成绘图的类型取决于第一个参数的类型或类。
plot(x, y)
plot(xy)
如果 x 和 y 是向量,plot(x, y)
会生成 y 针对 x 的散点图。通过将一个参数(第二种形式)作为包含两个元素 x 和 y 的列表或两列矩阵,也可以产生相同的效果。
plot(x)
如果 x 是时间序列,这会生成时间序列绘图。如果 x 是数值向量,它会生成向量中值针对其在向量中的索引的绘图。如果 x 是复数向量,它会生成向量元素的虚部针对实部的绘图。
plot(f)
plot(f, y)
f 是一个因子对象,y 是一个数字向量。第一种形式生成 f 的条形图;第二种形式生成 f 的每个级别的 y 的箱线图。
plot(df)
plot(~ expr)
plot(y ~ expr)
df 是一个数据框,y 是任何对象,expr 是一个由“+
”分隔的对象名称列表(例如 a + b + c
)。前两种形式生成数据框中的变量的分布图(第一种形式)或多个命名对象的分布图(第二种形式)。第三种形式将 y 与 expr 中命名的每个对象进行比较。
R 提供了两个非常有用的函数来表示多变量数据。如果 X
是一个数字矩阵或数据框,则命令
> pairs(X)
生成由 X
的列定义的变量的对成散点图矩阵,即 X
的每一列都与 X
的每一列绘制,生成的 n(n-1) 个图以矩阵的形式排列,矩阵的行和列上的图例保持不变。
当涉及三个或四个变量时,coplot 可能会更直观。如果 a
和 b
是数字向量,c
是数字向量或因子对象(所有长度相同),则命令
> coplot(a ~ b | c)
生成多个散点图,其中 a
相对于 b
,针对 c
的给定值。如果 c
是一个因子,这仅仅意味着 a
相对于 b
绘制 c
的每个级别。当 c
是数字时,它会被分成多个条件间隔,并且对于每个间隔,a
相对于 b
绘制间隔内 c
的值。间隔的数量和位置可以通过 given.values=
参数控制 coplot()
—函数 co.intervals()
对于选择间隔很有用。您还可以使用两个给定变量,使用类似这样的命令
> coplot(a ~ b | c + d)
生成 a
相对于 b
的散点图,针对 c
和 d
的每个联合条件间隔。
函数 coplot()
和 pairs()
都采用参数 panel=
,该参数可用于自定义每个面板中显示的绘图类型。默认值为 points()
,用于生成散点图,但是通过提供一些其他低级图形函数(两个向量 x
和 y
)作为 panel=
的值,您可以生成您希望的任何类型的绘图。一个对共绘图有用的示例面板函数是 panel.smooth()
。
其他高级图形函数生成不同类型的绘图。一些示例是
qqnorm(x)
¶qqline(x)
qqplot(x, y)
分布比较绘图。第一种形式将数字向量 x
相对于预期的正态顺序分数(正态分数绘图)进行绘图,第二种形式通过绘制一条穿过分布和数据四分位的直线,向这种绘图中添加一条直线。第三种形式将 x
的分位数相对于 y
的分位数进行绘图,以比较它们各自的分布。
hist(x)
¶hist(x, nclass=n)
hist(x, breaks=b, …)
生成数字向量 x
的直方图。通常会选择合理的类别数,但可以通过 nclass=
参数提供建议。或者,可以使用 breaks=
参数准确指定断点。如果给出了 probability=TRUE
参数,则条形图表示按箱宽除以的相对频率,而不是计数。
dotchart(x, …)
¶构建 x
中数据的点图。在点图中,y 轴给出了 x
中数据的标记,x 轴给出了其值。例如,它允许轻松直观地选择值位于指定范围内的所有数据条目。
image(x, y, z, …)
¶contour(x, y, z, …)
persp(x, y, z, …)
三个变量的绘图。image
绘图使用不同的颜色绘制矩形网格来表示 z
的值,contour
绘图绘制轮廓线来表示 z
的值,persp
绘图绘制 3D 曲面。
可以将许多参数传递给高级图形函数,如下所示
add=TRUE
强制函数充当低级图形函数,将绘图叠加在当前绘图上(仅限某些函数)。
axes=FALSE
禁止生成坐标轴,这对于使用 axis()
函数添加自己的自定义坐标轴很有用。默认值 axes=TRUE
表示包含坐标轴。
log="x"
log="y"
log="xy"
导致 x、y 或两个坐标轴变为对数。这适用于许多类型的绘图,但并非所有类型。
type=
type=
参数控制生成的绘图类型,如下所示
type="p"
绘制各个点(默认)
type="l"
绘制线
type="b"
绘制由线连接的点(两者)
type="o"
绘制被线覆盖的点
type="h"
从点到零轴绘制垂直线(高密度)
type="s"
type="S"
阶跃函数绘图。在第一种形式中,垂直线的顶部定义点;在第二种形式中,底部定义点。
type="n"
完全不绘图。但是,仍然绘制轴(默认),并且根据数据设置坐标系。非常适合使用后续低级图形函数创建绘图。
xlab=string
ylab=string
x 和 y 轴的轴标签。使用这些参数来更改默认标签,通常是高级绘图函数调用中使用的对象的名称。
main=string
图形标题,以大字体置于绘图顶部。
sub=string
副标题,以较小的字体置于 x 轴正下方。
有时,高级绘图函数无法生成您想要的绘图类型。在这种情况下,可以使用低级绘图命令向当前绘图添加额外信息(例如点、线或文本)。
一些更有用的低级绘图函数是
points(x, y)
¶lines(x, y)
向当前绘图添加点或连接线。plot()
的 type=
参数也可以传递给这些函数(并且对于 points()
默认为 "p"
,对于 lines()
默认为 "l"
)。
text(x, y, labels, …)
¶在由 x, y
给出的点处向绘图添加文本。通常,labels
是一个整数或字符向量,在这种情况下,labels[i]
绘制在点 (x[i], y[i])
处。默认值为 1:length(x)
。
注意:此函数通常在以下序列中使用
> plot(x, y, type="n"); text(x, y, names)
图形参数 type="n"
会禁止点,但会设置轴,而 text()
函数会提供特殊字符,如字符向量 names
为点指定的特殊字符。
abline(a, b)
¶abline(h=y)
abline(v=x)
abline(lm.obj)
向当前绘图添加一条斜率为 b
、截距为 a
的线。h=y
可用于指定水平线穿过绘图的 y 坐标,v=x
同理用于指定垂直线的 x 坐标。此外,lm.obj 可以是长度为 2 的 coefficients
组件的列表(例如模型拟合函数的结果),按顺序将其视为截距和斜率。
polygon(x, y, …)
¶绘制由 (x
, y
) 中的有序顶点定义的多边形,并(可选)用阴影线填充它,或者如果图形设备允许填充图形,则填充它。
legend(x, y, legend, …)
¶在指定位置向当前绘图添加图例。绘图字符、线型、颜色等通过字符向量 legend
中的标签进行识别。还必须给出至少一个其他参数 v(一个与 legend
长度相同的向量),其中包含绘图单元的相应值,如下所示
legend( , fill=v)
填充框的颜色
legend( , col=v)
绘制点或线的颜色
legend( , lty=v)
线条样式
legend( , lwd=v)
线条宽度
legend( , pch=v)
绘制字符(字符向量)
title(main, sub)
¶在当前绘图顶部添加大字体标题 main
,并在底部添加小字体副标题 sub
(可选)。
axis(side, …)
¶在当前绘图中添加一个轴,轴位于第一个参数指定的侧边(从底部顺时针计数,为 1 到 4)。其他参数控制轴在绘图中或旁边的位置,以及刻度位置和标签。在使用 axes=FALSE
参数调用 plot()
之后,此功能可用于添加自定义轴。
低级绘图函数通常需要一些定位信息(例如,x 和 y 坐标)来确定新绘图元素的位置。坐标以用户坐标给出,由先前的顶级图形命令定义,并根据提供的数据进行选择。
在需要 x
和 y
参数的地方,也可以只提供一个参数,该参数是一个列表,其中包含名为 x
和 y
的元素。类似地,具有两列的矩阵也是有效的输入。通过这种方式,可以使用诸如 locator()
(见下文)之类的函数来交互式地指定绘图中的位置。
在某些情况下,向绘图中添加数学符号和公式很有用。这可以通过在 text
、mtext
、axis
或 title
中指定表达式而不是字符串来实现。例如,以下代码绘制了二项概率函数的公式
> text(x, y, expression(paste(bgroup("(", atop(n, x), ")"), p^x, q^{n-x})))
更多信息,包括可用功能的完整列表,可以使用以下命令从 R 中获取
> help(plotmath) > example(plotmath) > demo(plotmath)
使用 text
和 contour
函数渲染文本时,可以指定 Hershey 矢量字体。使用 Hershey 字体有三个原因
更多信息,包括 Hershey 字符表,可以使用以下命令从 R 中获取
> help(Hershey) > demo(Hershey) > help(Japanese) > demo(Japanese)
R 还提供了一些函数,允许用户使用鼠标从绘图中提取或向绘图中添加信息。其中最简单的是 locator()
函数
locator(n, type)
¶等待用户使用鼠标左键选择当前绘图上的位置。这将持续到选择 n
(默认 512)个点,或按下另一个鼠标按钮。 type
参数允许在所选点处绘图,并且与高级图形命令的效果相同;默认是不绘图。 locator()
返回所选点的坐标,作为具有两个分量 x
和 y
的列表。
locator()
通常不带参数调用。当难以预先计算图形应该放置的位置时,它对于交互式选择诸如图例或标签等图形元素的位置特别有用。例如,要在远离点的附近放置一些信息性文本,可以使用以下命令
> text(locator(1), "Outlier", adj=0)
(如果当前设备(如 postscript
)不支持交互式指向,则将忽略 locator()
。)
identify(x, y, labels)
¶允许用户通过绘制 labels
的相应分量(或如果 labels
不存在,则绘制点的索引号)来突出显示 x
和 y
定义的任何点(使用鼠标左键)。在按下另一个按钮时返回所选点的索引。
有时我们希望识别绘图上的特定点,而不是它们的位置。例如,我们可能希望用户从图形显示中选择一些感兴趣的观察结果,然后以某种方式处理该观察结果。给定两个数字向量 x
和 y
中的若干(x, y) 坐标,我们可以按如下方式使用 identify()
函数
> plot(x, y) > identify(x, y)
identify()
函数本身不执行绘图,而只是允许用户移动鼠标指针并在某个点附近单击鼠标左键。如果鼠标指针附近有某个点,它将用其索引号(即它在 x
/y
向量中的位置)标记在附近。或者,你可以使用一些信息字符串(例如案例名称)作为高亮,方法是将 labels
参数用于 identify()
,或使用 plot = FALSE
参数完全禁用标记。当该进程终止(见上文)时,identify()
返回所选点的索引;你可以使用这些索引从原始向量 x
和 y
中提取所选点。
在创建图形时,特别是出于演示或发布目的,R 的默认设置并不总是能完全产生所需内容。但是,你可以使用图形参数来自定义显示的几乎每个方面。R 维护了一个包含大量图形参数的列表,这些参数控制着线条样式、颜色、图形排列和文本对齐等许多内容。每个图形参数都有一个名称(例如“col
”,它控制颜色)和一个值(例如颜色编号)。
为每个活动设备维护一个单独的图形参数列表,并且每个设备在初始化时都有一组默认参数。图形参数可以通过两种方式设置:永久设置,影响访问当前设备的所有图形函数;或临时设置,仅影响单个图形函数调用。
par()
函数 ¶par()
函数用于访问和修改当前图形设备的图形参数列表。
par()
如果没有参数,则返回当前设备的所有图形参数及其值的列表。
par(c("col", "lty"))
使用字符向量参数,仅返回命名的图形参数(同样,作为列表)。
par(col=4, lty=2)
使用命名参数(或单个列表参数),设置命名图形参数的值,并将参数的原始值作为列表返回。
使用 par()
函数设置图形参数会更改参数的值,从某种意义上说,永久地,因为对图形函数(在当前设备上)的所有未来调用都将受到新值的影响。您可以将以这种方式设置图形参数视为设置参数的“默认”值,除非给出了替代值,否则所有图形函数都将使用该值。
请注意,对 par()
的调用始终影响图形参数的全局值,即使从函数内调用 par()
也是如此。这通常是不希望的行为——通常我们希望设置一些图形参数,进行一些绘图,然后恢复原始值,以免影响用户的 R 会话。您可以通过在进行更改时保存 par()
的结果,并在绘图完成后恢复初始值来恢复初始值。
> oldpar <- par(col=4, lty=2)
... plotting commands ...
> par(oldpar)
要保存和恢复所有可设置24 图形参数,请使用
> oldpar <- par(no.readonly=TRUE)
... plotting commands ...
> par(oldpar)
图形参数也可以作为命名参数传递给(几乎)任何图形函数。这与将参数传递给 par()
函数的效果相同,除了更改仅持续函数调用的时间。例如
> plot(x, y, pch="+")
使用加号作为绘图字符生成散点图,而不会更改未来绘图的默认绘图字符。
遗憾的是,这并未完全一致地实现,有时有必要使用 par()
设置和重置图形参数。
以下部分详细介绍了许多常用的图形参数。par()
函数的 R 帮助文档提供了一个更简洁的摘要;这作为一种更详细的替代方案提供。
图形参数将以以下形式呈现
name=value
参数效果的描述。 name 是参数的名称,即在调用 par()
或图形函数时使用的参数名称。 value 是设置参数时可能使用的典型值。
请注意,axes
不是图形参数,而是几个 plot
方法的参数:请参阅 xaxt
和 yaxt
。
R 图形由点、线、文本和多边形(填充区域)组成。存在控制如何绘制这些图形元素的图形参数,如下所示
pch="+"
用于绘制点的字符。默认值因图形驱动程序而异,但通常为圆形。绘制的点往往会略高于或低于适当的位置,除非您使用 "."
作为绘制字符,它会产生居中的点。
pch=4
当 pch
被指定为 0 到 25(包括)之间的整数时,将生成一个专门的绘制符号。要查看符号是什么,请使用命令
> legend(locator(1), as.character(0:25), pch = 0:25)
21 到 25 的符号可能看起来与前面的符号重复,但可以用不同的方式着色:请参阅 points
及其示例的帮助。
此外,pch
可以是字符或介于 32:255
范围内的数字,代表当前字体中的一个字符。
lty=2
线条类型。并非所有图形设备都支持备用线条样式(并且在支持备用线条样式的设备上有所不同),但线条类型 1 始终为实线,线条类型 0 始终为不可见,线条类型 2 及更高为点线或虚线,或两者的某种组合。
lwd=2
线条宽度。以“标准”线条宽度的倍数表示的所需线条宽度。影响坐标轴线以及使用 lines()
等绘制的线条。并非所有设备都支持此功能,有些设备对可使用的宽度有限制。
col=2
用于点、线、文本、填充区域和图像的颜色。当前调色板中的一个数字(请参阅 ?palette
)或一个已命名的颜色。
col.axis
col.lab
col.main
col.sub
分别用于坐标轴注释、x 和 y 标签、主标题和副标题的颜色。
font=2
一个整数,用于指定用于文本的字体。如果可能,设备驱动程序会安排 1
对应于纯文本、2
对应于粗体、3
对应于斜体、4
对应于粗斜体和 5
对应于符号字体(包括希腊字母)。
font.axis
font.lab
font.main
font.sub
分别用于坐标轴注释、x 和 y 标签、主标题和副标题的字体。
adj=-0.1
文本相对于绘图位置的对齐方式。0
表示左对齐,1
表示右对齐,0.5
表示在绘图位置水平居中。实际值是文本中出现在绘图位置左侧的部分,因此值为 -0.1
会在文本和绘图位置之间留出 10% 的文本宽度间隙。
cex=1.5
字符扩展。该值是文本字符(包括绘图字符)相对于默认文本大小的所需大小。
cex.axis
cex.lab
cex.main
cex.sub
分别用于坐标轴注释、x 和 y 标签、主标题和副标题的字符扩展。
R 的许多高级绘图都有坐标轴,你也可以使用低级 axis()
图形函数自己构建坐标轴。坐标轴有三个主要组成部分:坐标轴线(线条样式由 lty
图形参数控制)、刻度标记(沿坐标轴线标记单位划分)和刻度标签(标记单位)。可以使用以下图形参数自定义这些组件。
lab=c(5, 7, 12)
前两个数字分别是 x 和 y 坐标轴上所需的刻度间隔数。第三个数字是坐标轴标签所需的长度,以字符为单位(包括小数点)。为此参数选择过小的值可能会导致所有刻度标签都舍入到相同的数字!
las=1
坐标轴标签的方向。 0
表示始终平行于坐标轴,1
表示始终水平,2
表示始终垂直于坐标轴。
mgp=c(3, 1, 0)
坐标轴组件的位置。第一个组件是从坐标轴标签到坐标轴位置的距离,以文本行表示。第二个组件是到刻度标签的距离,最后一个组件是从坐标轴位置到坐标轴线(通常为零)的距离。正数测量绘图区域外部,负数测量内部。
tck=0.01
刻度标记的长度,作为绘图区域大小的几分之一。当 tck
较小时(小于 0.5),x 和 y 坐标轴上的刻度标记被迫具有相同的大小。值为 1 会生成网格线。负值会在绘图区域外部生成刻度标记。对于内部刻度标记,请使用 tck=0.01
和 mgp=c(1,-1.5,0)
。
xaxs="r"
yaxs="i"
分别针对 x 和 y 轴的轴样式。对于样式 "i"
(内部)和 "r"
(默认),刻度标记始终落在数据范围内,但样式 "r"
在边缘处留出少量空间。
R 中的单个绘图称为 figure
,由一个 绘图区域 组成,该区域周围有边距(可能包含轴标签、标题等),并且(通常)由轴本身限定。
一个典型的图形是
控制图形布局的图形参数包括
mai=c(1, 0.5, 0.5, 0)
分别以英寸为单位测量的底部、左侧、顶部和右侧边距的宽度。
mar=c(4, 2, 2, 1)
类似于 mai
,但测量单位是文本行。
mar
和 mai
是等效的,因为设置其中一个会更改另一个的值。为此参数选择的默认值通常过大;很少需要右侧边距,如果未使用标题,则也不需要顶部边距。底部和左侧边距必须足够大,以容纳轴和刻度标签。此外,默认值的选择不考虑设备表面的大小:例如,将 postscript()
驱动程序与 height=4
参数一起使用,将导致一个绘图,除非明确设置 mar
或 mai
,否则该绘图大约有 50% 的边距。当使用多幅图形时(见下文),边距会减小,但当许多图形共享同一页面时,这可能不够。
R 允许您在单页上创建 n 乘 m 个图形的阵列。每个图形都有自己的边距,并且图形阵列可以选择被 外边距 包围,如下面的图形所示。
与多个图形相关的图形参数如下
mfcol=c(3, 2)
mfrow=c(2, 4)
设置多个图形阵列的大小。第一个值是行数;第二个值是列数。这两个参数之间的唯一区别在于设置 mfcol
会按列填充图形;mfrow
按行填充。
图中的布局可以通过设置 mfrow=c(3,2)
创建;该图形显示在绘制了四个图后的页面。
设置其中任何一个都可以减小符号和文本的基本大小(由 par("cex")
和设备的点大小控制)。在恰好有两行两列的布局中,基本大小减小了 0.83 倍:如果行或列有三个或更多,则减小因子为 0.66。
mfg=c(2, 2, 3, 2)
在多个图形环境中当前图形的位置。前两个数字是当前图形的行和列;后两个数字是多个图形阵列中的行数和列数。设置此参数可在阵列中的图形之间跳转。您甚至可以使用与同一页面上大小不等的图形的 真实 值不同的值作为后两个数字。
fig=c(4, 9, 1, 4)/10
当前图形在页面上的位置。值分别是页面左、右、下和上边缘的位置,以从左下角测量的页面百分比表示。示例值将用于页面右下角的图形。设置此参数可在页面内任意放置图形。如果您想将图形添加到当前页面,也请使用 new=TRUE
(与 S 不同)。
oma=c(2, 0, 3, 0)
omi=c(0, 0, 0.8, 0)
外边距的大小。与 mar
和 mai
类似,第一个测量文本行,第二个测量英寸,从下边距开始,顺时针进行。
外边距对于页面标题等特别有用。可以使用 mtext()
函数将文本添加到外边距,其参数 outer=TRUE
。但是,默认情况下没有外边距,因此必须使用 oma
或 omi
显式创建。
可以使用 split.screen()
和 layout()
函数以及 grid 和 lattice 包生成更复杂的多个图形排列。
R 可以在几乎任何类型的显示器或打印设备上生成图形(质量等级不同)。但在开始之前,R 需要知道它处理的是哪种类型的设备。这可以通过启动设备驱动程序来完成。设备驱动程序的目的是将 R 中的图形指令(例如“绘制一条线”)转换为特定设备可以理解的形式。
通过调用设备驱动程序函数来启动设备驱动程序。每个设备驱动程序都有一个这样的函数:键入 help(Devices)
以获取它们的完整列表。例如,发出命令
> postscript()
将导致所有未来的图形输出以 PostScript 格式发送到打印机。一些常用的设备驱动程序是
X11()
¶用于类 Unix 系统上的 X11 窗口系统
windows()
¶用于 Windows
quartz()
¶用于 macOS
postscript()
¶用于在 PostScript 打印机上打印或创建 PostScript 图形文件。
pdf()
¶生成 PDF 文件,也可以将其包含在 PDF 文件中。
png()
¶生成位图 PNG 文件。(并非始终可用:请参阅其帮助页面。)
jpeg()
¶生成位图 JPEG 文件,最适合用于 image
图表。(并非始终可用:请参阅其帮助页面。)
使用完设备后,务必通过发出以下命令终止设备驱动程序
> dev.off()
这可确保设备干净地完成;例如,在硬拷贝设备的情况下,这可确保完成每页并将其发送到打印机。(这将在会话正常结束时自动发生。)
通过将 file
参数传递给 postscript()
设备驱动程序函数,您可以在您选择的文件中以 PostScript 格式存储图形。除非给出了 horizontal=FALSE
参数,否则图表将采用横向,您可以使用 width
和 height
参数控制图形的大小(图表将按适当比例缩放以适应这些尺寸)。例如,命令
> postscript("file.ps", horizontal=FALSE, height=5, pointsize=10)
将生成包含用于图表的 PostScript 代码的文件,该文件可能用于包含在文档中。需要注意的是,如果命令中命名的文件已存在,则该文件将被覆盖。即使该文件只是在同一 R 会话中创建的,情况也是如此。
PostScript 输出的许多用法是将图形合并到另一个文档中。当生成封装的 PostScript 时,效果最佳:R 始终生成符合规范的输出,但仅在提供 onefile=FALSE
参数时将输出标记为符合规范。这种不寻常的表示法源自 S 兼容性:它实际上意味着输出将是单页(这是 EPSF 规范的一部分)。因此,要生成用于包含的绘图,请使用类似于
> postscript("plot1.eps", horizontal=FALSE, onefile=FALSE, height=8, width=6, pointsize=10)
在高级使用 R 时,同时使用多个图形设备通常很有用。当然,任何时候只有一个图形设备可以接受图形命令,这称为当前设备。当多个设备处于打开状态时,它们会形成一个编号序列,名称会给出任何位置的设备类型。
用于操作多个设备的主要命令及其含义如下
X11()
[UNIX]
windows()
win.printer()
win.metafile()
[Windows]
quartz()
[macOS]
postscript()
pdf()
png()
jpeg()
tiff()
bitmap()
…
每次对设备驱动程序函数的新调用都会打开一个新的图形设备,从而将设备列表扩展一个。此设备成为当前设备,图形输出将发送到该设备。
dev.list()
¶返回所有活动设备的数量和名称。列表中位置 1 上的设备始终是根本不接受图形命令的空设备。
dev.next()
¶dev.prev()
分别返回当前设备的下一个或上一个图形设备的数量和名称。
dev.set(which=k)
¶可用于将当前图形设备更改为设备列表中位置 k 上的设备。返回设备的数量和标签。
dev.off(k)
¶终止设备列表中点 k 处的图形设备。对于某些设备(例如 postscript
设备),这将立即打印文件或正确完成文件以供以后打印,具体取决于设备的启动方式。
dev.copy(设备, …, which=k)
dev.print(设备, …, which=k)
复制设备 k。此处 设备
是一个设备函数,如 postscript
,如有需要,可通过“…”指定额外参数。 dev.print
类似,但复制的设备会立即关闭,以便立即执行结束操作,如打印硬拷贝。
graphics.off()
终止列表中的所有图形设备,空设备除外。
R 没有动态或交互图形的内置功能,例如旋转点云或“刷选”(交互式突出显示)点。但是,Swayne、Cook 和 Buja 提供的系统 GGobi 中提供了广泛的动态图形功能,可从以下位置获取:
并且可以通过包 rggobi 从 R 中访问,该包在 http://ggobi.org/rggobi.html 中进行了描述。
此外,包 rgl 提供了与 3D 图形(例如曲面)交互的方法。
所有 R 函数和数据集都存储在包中。只有在加载包时,其内容才可用。这样做既是为了提高效率(完整列表会占用更多内存,并且搜索时间比子集更长),也是为了帮助包开发人员,使他们免受与其他代码的名称冲突。包的开发过程在 编写 R 扩展 的 创建 R 包 中进行了描述。在此,我们将从用户的角度对其进行描述。
要查看在您的网站上安装了哪些软件包,请发布命令
> library()
不带任何参数。要加载特定软件包(例如,boot软件包,其中包含 Davison & Hinkley (1997) 的函数),请使用类似于以下内容的命令
> library(boot)
连接到互联网的用户可以使用 install.packages()
和 update.packages()
函数(可通过 Windows 和 macOS GUI 中的 Packages
菜单获得,请参阅 R 安装和管理 中的 安装软件包)来安装和更新软件包。
要查看当前加载了哪些软件包,请使用
> search()
以显示搜索列表。某些软件包可能已加载但不在搜索列表中(请参阅 命名空间):这些软件包将包含在
> loadedNamespaces()
中给出的列表中。要查看已安装软件包中的所有可用帮助主题的列表,请使用
> help.start()
以启动 HTML 帮助系统,然后导航到 Reference
部分中的软件包列表。
标准(或 base)软件包被认为是 R 源代码的一部分。它们包含使 R 能够工作的基本函数,以及本手册中描述的数据集和标准统计和图形函数。它们应在任何 R 安装中自动可用。请参阅 R 常见问题解答 中的 R 软件包,以获取完整列表。
R 有成千上万个由不同作者编写的贡献包。其中一些包实现了专门的统计方法,另一些包提供了对数据或硬件的访问,还有一些包旨在补充教科书。一些(推荐包)随 R 的每个二进制发行版一起分发。大多数包可从 CRAN(https://CRAN.R-project.org/ 及其镜像)和其他存储库(如 Bioconductor (https://www.bioconductor.org/))下载。R 常见问题解答包含 CRAN 包在发布时的列表,但可用包的集合经常变化。
包有命名空间,它可以做三件事:允许包编写者隐藏仅供内部使用的函数和数据,防止当用户(或其他包编写者)选择与包中名称冲突的名称时函数中断,并提供一种在特定包中引用对象的方法。
例如,t()
是 R 中的转置函数,但用户可以定义自己的名为 t
的函数。命名空间可以防止用户的定义优先,并破坏尝试转置矩阵的每个函数。
有两个运算符可用于命名空间。双冒号运算符 ::
从特定命名空间中选择定义。在上面的示例中,转置函数始终可用作 base::t
,因为它是在 base
包中定义的。只有从包中导出的函数才能通过这种方式检索。
三冒号运算符 :::
可能出现在 R 代码中的几个地方:它就像双冒号运算符,但还可以访问隐藏的对象。用户更有可能使用 getAnywhere()
函数,该函数搜索多个包。
包通常是相互依赖的,加载一个包可能会导致自动加载其他包。上面描述的冒号运算符还将导致自动加载关联的包。当自动加载具有命名空间的包时,它们不会添加到搜索列表中。
R 拥有相当广泛的设施来访问其运行所在的操作系统:这允许将其用作脚本语言,并且 R 本身大量使用了这种能力,例如安装包。
由于 R 自身的脚本需要在所有平台上运行,因此已投入大量精力使脚本设施尽可能地与平台无关。
有许多函数可以操作文件和目录。以下是其中一些常用函数的指针。
要创建(空)文件或目录,请使用 file.create
或 dir.create
。(它们是 POSIX 实用程序 touch
和 mkdir
的类似物。)有关 R 会话目录中的临时文件和目录,请参见 tempfile
。
可以通过 file.remove
或 unlink
删除文件:后者可以删除目录树。
对于目录列表,请使用 list.files
(也可作为 dir
)或 list.dirs
。这些可以使用正则表达式选择文件:要通过通配符选择,请使用 Sys.glob
。
可以通过 file.info
查找有关文件路径的许多类型的信息(例如,它是否是文件或目录)。
有几种方法可以找出文件是否“存在”(文件可以存在于文件系统中,但当前用户不可见)。有函数 file.exists
、file.access
和 file_test
,其中包含此测试的各种版本:file_test
是 POSIX test
命令的版本,适用于熟悉 shell 脚本的人员。
函数 file.copy
是 POSIX 命令 cp
的 R 类似物。
可以通过 file.choose
交互式地选择文件:Windows 端口具有更通用的函数 choose.files
和 choose.dir
,并且 tcltk 包中也有类似的函数:tk_choose.files
和 tk_choose.dir
。
函数 file.show
和 file.edit
将以适合 R 端口的方式显示和编辑一个或多个文件,如果正在使用控制台(例如 Windows 上的 RGui 或 macOS 上的 R.app),则使用控制台的功能。
文件系统中对 链接 有一定的支持:请参阅函数 file.link
和 Sys.readlink
。
除了少数例外情况外,R 依赖于底层操作系统函数来处理文件路径。这方面的一些内容允许依赖于操作系统,甚至依赖于操作系统的版本。有关操作系统应如何解释文件路径的 POSIX 标准,许多 R 用户都假定符合 POSIX:但 Windows 并未声称符合该标准,而其他操作系统可能不太完全符合该标准。
以下是使用文件路径时遇到的一些问题。
函数 basename
和 dirname
选择文件路径的各个部分:从组件组装文件路径的推荐方法是 file.path
。函数 pathexpand
执行“波浪线扩展”,用主目录(当前用户的主目录,可能还有其他用户的主目录)的值进行替换。
在具有链接的文件系统上,单个文件可以通过许多文件路径进行引用。函数 normalizePath
将找到一个规范文件路径。
Windows 有短(“8.3”)和长文件名概念:normalizePath
将返回一个使用长文件名的绝对路径,shortPathName
将返回一个使用短文件名的版本。后者不包含空格,并使用反斜杠作为分隔符,因此有时可用于从 R 导出名称。
文件 权限 是一个相关主题。R 支持所有者/组/所有人的读/写/执行权限的 POSIX 概念,但这可能仅在文件系统上得到部分支持,例如在 Windows 上仅识别只读文件(对于运行 R 会话的帐户)。访问控制列表 (ACL) 用于多个文件系统,但没有商定的标准,R 也没有控制它们的工具。使用 Sys.chmod
更改权限。
函数 system
和 system2
用于调用系统命令并选择性地收集其输出。 system2
更通用一些,但其主要优势在于使用它可以更轻松地编写跨平台代码。
system
在 Windows 上的行为与其他操作系统不同(因为同名的 API C 调用也是如此)。在其他地方,它调用 shell 来运行命令:R 的 Windows 端口有一个函数 shell
来执行此操作。
要找出操作系统是否包含某个命令,请使用 Sys.which
,它尝试以跨平台的方式执行此操作(不幸的是,它不是标准操作系统服务)。
函数 shQuote
会根据当前操作系统对命令所需的文件路径进行引用。
最近版本的 R 具有广泛的工具来读取和写入压缩文件,通常是透明的。在 R 中读取文件在很大程度上是由连接完成的,而 file
函数用于打开与文件(或 URL)的连接,并且能够从文件的“魔术”头识别所使用的压缩。
支持时间最长的压缩类型是 gzip
压缩,它仍然是一个很好的通用折衷方案。也可以读取由早期 Unix compress
实用程序压缩的文件,但这些文件变得越来越少见。另外两种形式的压缩,即 bzip2
和 xz
实用程序的压缩,也可用。这些通常会以较慢的解压缩速度和更慢的压缩速度为代价实现更高的压缩率(取决于文件,高得多)。
xz
和 lzma
压缩之间存在一些混淆(请参阅 https://en.wikipedia.org/wiki/Xz 和 https://en.wikipedia.org/wiki/LZMA):R 可以读取大多数版本压缩的文件两者。
文件存档是包含文件集合的单个文件,最常见的是“tarball”和 zip 文件,用于分发 R 包。R 可以列出和解包两者(请参阅函数 untar
和 unzip
),并创建两者(对于 zip
,借助于外部程序)。
以下会话旨在通过使用 R 环境的某些功能向您介绍这些功能。系统中的许多功能最初会让人感到陌生和困惑,但这种困惑很快就会消失。
根据您的平台适当地启动 R(请参阅调用 R)。
R 程序以一个横幅开始。
(在 R 代码中,左侧的提示符不会显示,以避免混淆。)
help.start()
启动在线帮助的HTML界面(使用机器上可用的 Web 浏览器)。您应该使用鼠标简要浏览此功能的特性。
最小化帮助窗口并转到下一部分。
x <- rnorm(50)
y <- rnorm(x)
生成两个x和y坐标的伪随机正态向量。
plot(x, y)
在平面上绘制点。图形窗口将自动出现。
ls()
查看 R 工作空间中现在有哪些 R 对象。
rm(x, y)
删除不再需要的对象。(清理)。
x <- 1:20
使x = (1, 2, ..., 20)。
w <- 1 + sqrt(x)/2
标准差的“权重”向量。
dummy <- data.frame(x=x, y= x + rnorm(x)*w)
dummy
制作一个包含两列(x和y)的数据框,并查看它。
fm <- lm(y ~ x, data=dummy)
summary(fm)
拟合一个简单的线性回归并查看分析。使用波浪号左侧的y
,我们正在对x依赖的y进行建模。
fm1 <- lm(y ~ x, data=dummy, weight=1/w^2)
summary(fm1)
由于我们知道标准差,因此我们可以进行加权回归。
attach(dummy)
使数据框中的列显示为变量。
lrf <- lowess(x, y)
生成非参数局部回归函数。
plot(x, y)
标准点图。
lines(x, lrf$y)
添加局部回归。
abline(0, 1, lty=3)
真回归线:(截距 0,斜率 1)。
abline(coef(fm))
未加权回归线。
abline(coef(fm1), col = "red")
加权回归线。
detach()
从搜索路径中移除数据框。
plot(fitted(fm), resid(fm),
xlab="Fitted values",
ylab="Residuals",
main="Residuals vs Fitted")
标准回归诊断图,用于检查异方差性。你能看到吗?
qqnorm(resid(fm), main="Residuals Rankit Plot")
正态分数图,用于检查偏度、峰度和异常值。(此处不太有用。)
rm(fm, fm1, lrf, x, dummy)
再次清理。
下一部分将研究 Michelson 的经典实验数据,以测量光速。此数据集可在 morley
对象中获得,但我们将读取它以说明 read.table
函数。
filepath <- system.file("data", "morley.tab" , package="datasets")
filepath
获取数据文件的路径。
file.show(filepath)
可选。查看文件。
mm <- read.table(filepath)
mm
将 Michelson 数据读入数据框并查看。有五次实验(列 Expt
),每项实验有 20 次运行(列 Run
),sl
是记录的光速,经过适当编码。
mm$Expt <- factor(mm$Expt)
mm$Run <- factor(mm$Run)
将 Expt
和 Run
更改为因子。
attach(mm)
使数据框在位置 2(默认)处可见。
plot(Expt, Speed, main="Speed of Light Data", xlab="Experiment No.")
使用简单的箱线图比较五次实验。
fm <- aov(Speed ~ Run + Expt, data=mm)
summary(fm)
作为随机区组分析,其中“运行”和“实验”作为因子。
fm0 <- update(fm, . ~ . - Run)
anova(fm0, fm)
拟合省略“运行”的子模型,并使用正式方差分析进行比较。
detach()
rm(fm, fm0)
继续之前先清理干净。
现在我们来看看一些更图形化的特性:等高线图和图像图。
x <- seq(-pi, pi, len=50)
y <- x
x 是 [-pi\, pi] 区间中 50 个等间隔值的向量。y 相同。
f <- outer(x, y, function(x, y) cos(y)/(1 + x^2))
f 是一个方阵,行和列分别由 x 和 y 索引,值为函数 cos(y)/(1 + x^2)。
oldpar <- par(no.readonly = TRUE)
par(pty="s")
保存绘图参数并将绘图区域设置为“正方形”。
contour(x, y, f)
contour(x, y, f, nlevels=15, add=TRUE)
绘制 f 的等高线图;添加更多线条以获取更多详细信息。
fa <- (f-t(f))/2
fa
是 f 的“非对称部分”。(t()
是转置)。
contour(x, y, fa, nlevels=15)
绘制等高线图,…
par(oldpar)
… 并恢复旧的图形参数。
image(x, y, f)
image(x, y, fa)
绘制一些高密度图像图(如果你愿意,可以获得它们的硬拷贝),…
objects(); rm(x, y, f, fa)
… 并继续之前先清理干净。
R 还可以进行复数运算。
th <- seq(-pi, pi, len=100)
z <- exp(1i*th)
1i
用于复数 i。
par(pty="s")
plot(z, type="l")
绘制复数参数意味着绘制虚部与实部的关系。这应该是一个圆。
w <- rnorm(100) + rnorm(100)*1i
假设我们想要在单位圆内抽样点。一种方法是采用实部和虚部为标准正态分布的复数…
w <- ifelse(Mod(w) > 1, 1/w, w)
…并将圆外的任何点映射到它们的倒数。
plot(w, xlim=c(-1,1), ylim=c(-1,1), pch="+",xlab="x", ylab="y")
lines(z)
所有点都在单位圆内,但分布不均匀。
w <- sqrt(runif(100))*exp(2*pi*runif(100)*1i)
plot(w, xlim=c(-1,1), ylim=c(-1,1), pch="+", xlab="x", ylab="y")
lines(z)
第二种方法使用均匀分布。现在这些点在圆盘上看起来应该分布得更均匀。
rm(th, w, z)
再次清理。
q()
退出 R 程序。系统会询问你是否要保存 R 工作空间,对于这样的探索性会话,你可能不想保存。
Windows 或 macOS 上的 R 用户应首先阅读特定于操作系统的部分,但命令行使用也受支持。
在 UNIX 或 Windows 上使用命令行时,命令“R”既可用于以如下形式启动 R 主程序
R
[options] [<
infile] [>
outfile],
也可通过 R CMD
接口用作各种 R 工具(例如,用于处理 R 文档格式中的文件或操作加载项包)的包装器,这些工具不打算被“直接”调用。
在 Windows 命令行中,Rterm.exe
优于 R
。
你需要确保环境变量 TMPDIR
未设置,或者它指向一个可用于创建临时文件和目录的有效位置。
大多数选项控制 R 会话开始和结束时发生的情况。启动机制如下(有关更多信息,另请参阅主题“Startup”的在线帮助,以及以下部分中的一些特定于 Windows 的详细信息)。
R_ENVIRON
指向;如果未设置,则使用 R_HOME/etc/Renviron.site(如果存在)。用户文件由环境变量 R_ENVIRON_USER
指向(如果已设置);否则,按顺序搜索当前目录或用户主目录中的 .Renviron 文件。这些文件应包含“name=value”格式的行。(有关精确说明,请参见 help("Startup")
。)您可能想要设置的变量包括 R_PAPERSIZE
(默认纸张大小)、R_PRINTCMD
(默认打印命令)和 R_LIBS
(指定搜索附加包的 R 库树列表)。
R_PROFILE
环境变量的值。如果该变量未设置,则使用默认 R_HOME/etc/Rprofile.site(如果存在)。
R_PROFILE_USER
;如果未设置,则按顺序搜索当前目录或用户主目录中的名为 .Rprofile 的文件。
.First()
函数,则执行该函数。此函数(以及在 R 会话结束时执行的 .Last()
)可以在相应的启动配置文件中定义,或驻留在 .RData 中。
此外,还有用于控制 R 进程可用内存的选项(有关更多信息,请参见主题“Memory”的在线帮助)。除非用户尝试限制 R 使用的内存量,否则通常不需要使用这些选项。
R 接受以下命令行选项。
将简短的帮助消息打印到标准输出并成功退出。
将版本信息打印到标准输出并成功退出。
指定从控制台或 stdin
输入时要采用的编码。这需要是 iconv
已知的编码:请参见其帮助页面。(--encoding enc
也被接受。)输入将重新编码为 R 正在运行的区域设置,并且需要在后者的编码中表示(因此,例如,除非区域设置使用 UTF-8 编码,否则无法在法语区域设置中重新编码希腊文本)。
将 R“主目录”的路径打印到标准输出并成功退出。除了前端 shell 脚本和手册页,R 安装会将所有内容(可执行文件、包等)放入此目录。
控制在 R 会话结束时是否保存数据集。如果在交互会话中未给出任何选项,则在使用 q() 结束会话时会询问用户所需行为;在非交互使用中,必须指定其中一个选项或由其他选项暗示(见下文)。
不读取任何用户文件来设置环境变量。
在启动时不读取全站配置文件。
在启动时不读取用户配置文件。
控制在启动时是否恢复已保存的映像(R 启动所在的目录中的文件 .RData)。默认情况下为恢复。(--no-restore 暗含所有特定的 --no-restore-* 选项。)
控制在启动时是否恢复历史文件(通常为 R 启动所在的目录中的文件 .Rhistory,但可以通过环境变量 R_HISTFILE
设置)。默认情况下为恢复。
(仅限 Windows)防止在启动时加载 Rconsole 文件。
组合 --no-save、--no-environ、--no-site-file、--no-init-file 和 --no-restore。在 Windows 中,这也包括 --no-Rconsole。
(不是 Rgui.exe
)从 file 获取输入:‘-’表示 stdin
。暗示 --no-save,除非已设置 --save。在类似 Unix 的系统上,应在 file 中避免使用 shell 元字符(但允许使用空格)。
(不是 Rgui.exe
)将 expression 用作输入行。可以使用一个或多个 -e 选项,但不能与 -f 或 --file 一起使用。暗示 --no-save,除非已设置 --save。(以这种方式使用的表达式的总长度限制为 10,000 个字节。包含空格或 shell 元字符的表达式需要加引号。)
(仅限 UNIX)通过 readline 关闭命令行编辑。当使用 ESS(“Emacs Speaks Statistics”)包在 Emacs 中运行 R 时,这很有用。有关更多信息,请参见 命令行编辑器。命令行编辑已启用以供默认交互使用(参见 --interactive)。此选项还影响波浪号展开:请参见 path.expand
的帮助。
仅供专家使用:分别设置向量堆(以字节为单位)和cons 单元格(数字)的垃圾回收的初始触发器大小。后缀“M”分别指定兆字节或数百万个单元格。默认值分别为 6Mb 和 350k,也可以通过环境变量 R_NSIZE
和 R_VSIZE
设置。
将指针保护堆的最大大小指定为 N 个位置。默认值为 10000,但可以增加以允许进行大型和复杂的计算。目前接受的最大值为 100000。
不打印初始版权和欢迎消息。
让 R 尽可能安静地运行。此选项旨在支持使用 R 为其计算结果的程序。它暗示 --quiet 和 --no-save。
(仅限 UNIX)即使输入已重定向,也断言 R 确实正在交互式运行:如果输入来自 FIFO 或管道并由交互式程序提供,则使用。 (默认情况下,仅当 stdin 连接到终端或 pty
时,才推断出 R 正在交互式运行。)使用 -e、-f 或 --file 断言非交互式使用,即使给出了 --interactive。
请注意,这不会打开命令行编辑。
(仅限 Windows)设置 Rterm
以供 ESS 中的 R-inferior-mode
使用,包括断言交互式使用(没有命令行编辑器)和不缓冲 stdout。
打印更多有关进度的信息,特别是将 R 的选项 verbose
设置为 TRUE
。R 代码使用此选项来控制诊断消息的打印。
(仅限 UNIX)通过调试器 name 运行 R。对于大多数调试器(例外是 valgrind
和 gdb
的最新版本),将忽略进一步的命令行选项,而应在从调试器内部启动 R 可执行文件时提供这些选项。
(仅限 UNIX)使用 type 作为图形用户界面(请注意,这也包括交互式图形)。目前,type 的可能值为“X11”(默认值),并且只要有“Tcl/Tk”支持,则为“Tk”。(为了向后兼容,“x11”和“tk”是可以接受的。)
(仅限 UNIX)运行指定的子架构。
此标志除了导致跳过命令行的其余部分外,什么也不做:这可用于使用 commandArgs(TRUE)
从中检索值。
请注意,输入和输出可以用通常的方式重定向(使用“<”和“>”),但仍适用 4095 字节的行长限制。警告和错误消息将发送到错误通道(stderr
)。
命令 R CMD
允许调用各种工具,这些工具与 R 结合使用时很有用,但并不打算“直接”调用。一般形式为
R CMD command args
其中 command 是工具的名称,args 是传递给它的参数。
目前,可以使用以下工具。
BATCH
以批处理模式运行 R。使用可能的进一步选项(参见 ?BATCH
)运行 R --restore --save
。
COMPILE
(仅限 UNIX)编译 C、C++、Fortran … 文件以与 R 一起使用。
SHLIB
构建共享库以进行动态加载。
INSTALL
安装附加包。
REMOVE
移除附加包。
build
构建(即打包)附加包。
check
检查附加包。
LINK
(仅限 UNIX)创建可执行程序的前端。
Rprof
后处理 R 配置文件。
Rdconv
Rd2txt
将 Rd 格式转换为各种其他格式,包括 HTML、LaTeX、纯文本以及提取示例。 Rd2txt
可用作 Rd2conv -t txt
的速记。
Rd2pdf
将 Rd 格式转换为 PDF。
Stangle
从 Sweave 或其他小插图文档中提取 S/R 代码
Sweave
处理 Sweave 或其他小插图文档
Rdiff
忽略标题等内容的 Diff R 输出
config
获取配置信息
javareconf
(仅限 Unix)更新 Java 配置变量
rtags
(仅限 Unix)从 C、R 和 Rd 文件创建 Emacs 样式标记文件
open
(仅限 Windows)通过 Windows 的文件关联打开文件
texify
(仅限 Windows)使用 R 的样式文件处理 (La)TeX 文件
使用
R CMD command --help
要获取通过 R CMD
接口访问的每个工具的使用信息。
此外,您可以在 R
和 CMD
之间使用选项 --arch=、--no-environ、--no-init-file、--no-site-file 和 --vanilla:这些选项会影响工具运行的任何 R 进程。(此处 --vanilla 等效于 --no-environ --no-site-file --no-init-file。)但请注意,R CMD
本身不会使用任何 R 启动文件(特别是,不会使用用户或站点 Renviron 文件),并且这些工具运行的所有 R 进程(BATCH
除外)都会使用 --no-restore。大多数都会使用 --vanilla,因此不会调用任何 R 启动文件:当前的例外是 INSTALL
、REMOVE
、Sweave
和 SHLIB
(使用 --no-site-file --no-init-file)。
R CMD cmd args
对于路径中或通过绝对文件路径给出的任何其他可执行文件 cmd
:这对于拥有与 R 或在其下运行的特定命令相同的环境非常有用,例如运行 ldd
或 pdflatex
。在 Windows 下,cmd 可以是可执行文件或批处理文件,或者如果它具有扩展名 .sh
或 .pl
,则会调用相应的解释器(如果可用)来运行它。
在 Windows 下运行 R 有两种方法。在终端窗口(例如 cmd.exe
或功能更强大的 shell)中,可以使用上一部分中描述的方法,通过 R.exe
或更直接地通过 Rterm.exe
进行调用。对于交互式使用,有一个基于控制台的 GUI(Rgui.exe
)。
Windows 下的启动过程与 UNIX 下的非常相似,但需要澄清对“主目录”的引用,因为这在 Windows 上并不总是被定义。如果定义了环境变量 R_USER
,则它会给出主目录。接下来,如果定义了环境变量 HOME
,则它会给出主目录。在这些两个用户可控设置之后,R 会尝试查找系统定义的主目录。它首先尝试使用 Windows 的“个人”目录(在 Windows 的最新版本中通常是 My Documents
)。如果失败,并且定义了环境变量 HOMEDRIVE
和 HOMEPATH
(它们通常被定义),则它们会定义主目录。如果所有这些都失败,则主目录将被视为起始目录。
您需要确保环境变量 TMPDIR
、TMP
和 TEMP
未设置,或者其中一个指向创建临时文件和目录的有效位置。
环境变量可以在命令行上作为“name=value”对提供。
如果有以 .RData(不区分大小写)结尾的参数,则将其解释为要还原的工作空间的路径:它意味着 --restore,并将工作目录设置为命名文件父目录。(此机制用于 RGui.exe
的拖放和文件关联,但也可用于 Rterm.exe
。如果命名文件不存在,则在父目录存在时设置工作目录。)
调用 RGui.exe
时,可以使用以下其他命令行选项。
控制 Rgui
是以 MDI 程序(在一个主窗口内有多个子窗口)还是 SDI 应用程序(控制台、图形和寻呼机有多个顶级窗口)的形式运行。命令行设置会覆盖用户 Rconsole 文件中的设置。
启用 Rgui
中的“中断到调试器”菜单项,并在命令行处理期间触发中断到调试器。
在使用 R CMD
的 Windows 中,您还可以指定自己的 .bat、.exe、.sh 或 .pl 文件。它将在适当的解释器(.pl 的 Perl)下运行,并设置多个环境变量,包括 R_HOME
、R_OSTYPE
、PATH
、BSTINPUTS
和 TEXINPUTS
。例如,如果您已在路径中拥有 latex.exe,则
R CMD latex.exe mydoc
将在 mydoc.tex 上运行 LaTeX,并将 R 的 share/texmf 宏的路径附加到 TEXINPUTS
。(不幸的是,这对于 MiKTeX 构建的 LaTeX 没有帮助,但 R CMD texify mydoc
在这种情况下将起作用。)
在 macOS 中运行 R 有两种方法。在 Terminal.app
窗口中调用 R
,应用第一个小节中描述的方法。此外,还有一个基于控制台的 GUI (R.app
),默认安装在系统中的 Applications
文件夹中。它是一个标准的 macOS 双击应用程序。
macOS 中的启动过程与 UNIX 中的非常相似,但 R.app
不使用命令行参数。“主目录”是 R.framework 中的目录,但除非在 GUI 中可访问的“首选项”窗口中给出了不同的启动目录,否则启动和当前工作目录将设置为用户的“主目录”。
如果你只想运行一个 R 命令文件 foo.R,建议使用 R CMD BATCH foo.R
。如果你想在后台或作为批处理作业运行此文件,请使用特定于操作系统的工具来执行此操作:例如,在类似 Unix 的操作系统上的大多数 shell 中,R CMD BATCH foo.R &
会运行一个后台作业。
你可以通过命令行上的其他参数将参数传递给脚本:例如(所需的精确引号将取决于所使用的 shell)
R CMD BATCH "--args arg1 arg2" foo.R &
将参数传递给脚本,可以通过以下方式将其作为字符向量检索:
args <- commandArgs(TRUE)
替代前端 Rscript
简化了此操作,可以通过以下方式调用此前端:
Rscript foo.R arg1 arg2
还可以使用此前端编写可执行脚本文件,如下所示(至少在类 Unix 系统和某些 Windows shell 中):
#! /path/to/Rscript args <- commandArgs(TRUE) ... q(status=<exit status code>)
如果将此内容输入文本文件 runfoo 并使其可执行(通过 chmod 755 runfoo
),则可以通过以下方式针对不同的参数调用此文件:
runfoo arg1 arg2
有关更多选项,请参阅 help("Rscript")
。这会将 R 输出写入 stdout 和 stderr,并且可以通过运行该命令的 shell 以通常的方式进行重定向。
如果您不希望硬编码到 Rscript
的路径,但将其放在您的路径中(对于已安装的 R 来说通常如此,除了 Windows,但例如 macOS 用户可能需要将 /usr/local/bin 添加到其路径中),请使用
#! /usr/bin/env Rscript ...
至少在 Bourne 和 bash shell 中,#!
机制 不允许 额外的参数,例如 #! /usr/bin/env Rscript --vanilla
。
需要考虑的一件事是 stdin()
指的是什么。用类似以下片段编写 R 脚本很常见
chem <- scan(n=24) 2.90 3.10 3.40 3.40 3.70 3.70 2.80 2.50 2.40 2.40 2.70 2.20 5.28 3.37 3.03 3.03 28.95 3.77 3.40 2.20 3.50 3.60 3.70 3.70
并且 stdin()
指的是脚本文件,以允许此类传统用法。如果您想引用进程的 stdin,请使用 "stdin"
作为 file
连接,例如 scan("stdin", ...)
。
编写可执行脚本文件(由 François Pinard 建议)的另一种方法是使用类似以下内容的 here 文档
#!/bin/sh [environment variables can be set here] R --no-echo [other options] <<EOF R program goes here... EOF
但此处 stdin()
指的是程序源,并且 "stdin"
将不可用。
可以通过 -e 标志在命令行上将简短脚本传递给 Rscript
via。(不接受空脚本。)
请注意,在类似 Unix 的系统上,输入文件名(例如 foo.R)不应包含空格或 shell 元字符。
当在 UNIX 下为编译配置 R 时,如果 GNU readline 库可用,将使用一个内置命令行编辑器,允许召回、编辑和重新提交之前的命令。请注意,readline 的其他版本存在,并且可能被内置命令行编辑器使用:这在 macOS 上最常见。您可以在 R 会话中运行 extSoftVersion()
来找出哪个版本(如果有)可用。
可以使用启动选项 --no-readline 禁用它(对于与 ESS 一起使用很有用 25)。
R 的 Windows 版本具有更简单的命令行编辑:请参阅 GUI 的“帮助”菜单下的“控制台”,以及 README.Rterm 文件,了解 Rterm.exe
下的命令行编辑。
在将 R 与 GNU26 readline 功能一起使用时,可以使用下面描述的函数,以及系统上的 man readline
或 info readline
中(可能)记录的其他函数。
其中许多函数使用 Control 或 Meta 字符。Control 字符(如 Control-m)是通过在按 m 键的同时按住 CTRL 获得的,在下面写为 C-m。Meta 字符(如 Meta-b)是通过按住 META27 并按 b 获得的,在下面写为 M-b。如果您的终端未启用 META 键,您仍可以使用以 ESC 开头的两个字符序列来输入 Meta 字符。因此,要输入 M-b,您可以键入 ESCb。ESC 字符序列在具有真实 Meta 键的终端上也是允许的。请注意,Meta 字符区分大小写。
某些但并非所有版本28 的 readline 将识别终端窗口的大小调整,因此最好避免这种情况。
R 程序会保留您键入的命令行的历史记录,包括错误行,并且历史记录中的命令可以被重新调用、必要时更改,并作为新命令重新提交。在 Emacs 样式的命令行编辑中,在该编辑阶段中进行的任何直接键入操作都会导致字符插入到您正在编辑的命令中,从而取代光标右侧的任何字符。在 vi 模式中,字符插入模式由 M-i 或 M-a 启动,键入字符后,通过键入另一个 ESC 来结束插入模式。(默认是 Emacs 样式,这里仅对此进行描述:有关 vi 模式,请参阅 readline 文档。)
随时按下 RET 命令都会导致重新提交该命令。
其他编辑操作总结在以下表格中。
转到上一个命令(在历史记录中向后)。
转到下一个命令(在历史记录中向前)。
查找包含 text 字符串的最后一个命令。这可以通过 C-g
(在某些 R 版本中通过 C-c
)取消。
在大多数终端上,您还可以使用向上和向下箭头键分别代替 C-p 和 C-n。
转到命令的开头。
转到行的末尾。
后退一个单词。
前进一个单词。
后退一个字符。
前进一个字符。
在大多数终端上,您还可以使用向左和向右箭头键分别代替 C-b 和 C-f。
在光标处插入 文本。
在光标后追加 文本。
删除前一个字符(光标左侧)。
删除光标下的字符。
删除光标下单词的其余部分,并“保存”它。
从光标删除到命令末尾,并“保存”它。
在此处插入(yank)最后“保存”的文本。
将光标下的字符与下一个字符互换。
将单词的其余部分更改为小写。
将单词的其余部分更改为大写。
重新向 R 提交命令。
最后的 RET 终止命令行编辑序列。
readline 键绑定可以通过通常的方式 via ~/.inputrc 文件进行自定义。这些自定义可以有条件地应用于应用程序 R
,即通过包含类似于以下内容的部分
$if R "\C-xd": "q('no')\n" $endif
跳转到: | -
:
!
?
.
*
/
&
%
^
+
<
=
>
|
~
A B C D E F G H I J K L M N O P Q R S T U V W X |
---|
跳转到: | -
:
!
?
.
*
/
&
%
^
+
<
=
>
|
~
A B C D E F G H I J K L M N O P Q R S T U V W X |
---|
跳转到: | A B C D E F G I K L M N O P Q R S T U V W |
---|
跳转到: | A B C D E F G I K L M N O P Q R S T U V W |
---|
D. M. Bates 和 D. G. Watts (1988),非线性回归分析及其应用。 John Wiley & Sons,纽约。
Richard A. Becker、John M. Chambers 和 Allan R. Wilks (1988),新 S 语言。 Chapman & Hall,纽约。这本书通常被称为“蓝皮书”。
John M. Chambers 和 Trevor J. Hastie 编辑。(1992),S 中的统计模型。 Chapman & Hall,纽约。这也称为“白皮书”。
John M. Chambers (1998) 用数据编程。施普林格,纽约。这也称为“绿皮书”。
A. C. Davison 和 D. V. Hinkley (1997),自举法及其应用,剑桥大学出版社。
Annette J. Dobson (1990),广义线性模型简介,Chapman and Hall,伦敦。
Peter McCullagh 和 John A. Nelder (1989),广义线性模型。第二版,Chapman and Hall,伦敦。
John A. Rice (1995),数理统计和数据分析。第二版。Duxbury Press,贝尔蒙特,加利福尼亚州。
S. D. Silvey (1970),统计推断。企鹅,伦敦。
ACM 软件系统奖,1998 年:https://awards.acm.org/award_winners/chambers_6640862.cfm。
对于可移植的 R 代码(包括在 R 包中使用的代码),只应使用 A–Za–z0–9。
不在字符串中,也不在函数定义的参数列表中
有些控制台不允许您输入更多内容,而允许输入的控制台中,有些会静默地丢弃多余内容,有些会将其用作下一行的开头。
长度不受限制。
此文件名中的前导“点”使其在 UNIX 中的普通文件列表中和 macOS 和 Windows 上的默认 GUI 文件列表中不可见。
对于非向量类型的参数,例如 list
模式参数,c()
的操作相当不同。请参阅 连接列表。
实际上,在执行任何其他语句之前,它仍然可用作 .Last.value
。
paste(..., collapse=ss)
将参数连接成一个单一的字符字符串,在它们之间放置 ss,例如,ss <- "|"
。还有更多用于字符操作的工具,请参阅 sub
和 substring
的帮助。
numeric 模式实际上是两种不同模式的混合,即 integer 和 double 精度,如手册中所述。
但请注意,length(object)
并不总是包含有用的内在信息,例如,当 object
是一个函数时。
通常,从数字到字符再返回的转换不会完全可逆,因为字符表示中存在舍入误差。
包 methods
中提供了使用“形式”或“S4”类的不同样式。
读者应注意,澳大利亚有八个州和领地,即澳大利亚首都领地、新南威尔士州、北领地、昆士兰州、南澳大利亚州、塔斯马尼亚州、维多利亚州和西澳大利亚州。
请注意,当 tapply()
的第二个参数不是因子时,它也能工作,例如,“tapply(incomes, state)
”,对于很多其他函数来说也是如此,因为必要时参数会强制转换为因子(使用 as.factor()
)。
请注意,x %*% x
是模棱两可的,因为它可能表示 x’x 或 x x’,其中 x 是列形式。在这种情况下,较小的矩阵似乎是隐式采用的解释,因此标量 x’x 在这种情况下是结果。矩阵 x x’ 可以通过 cbind(x) %*% x
或 x %*% rbind(x)
计算,因为 rbind()
或 cbind()
的结果始终是矩阵。但是,计算 x’x 或 x x’ 的最佳方法分别是 crossprod(x)
或 x %o% x
。
更好的方法是形成一个矩阵平方根 B,其中 A = BB’,并找出 By = x 的解的平方长度,也许可以使用 A 的 Cholesky 或特征值分解。
有关第二个术语的含义,请参阅 autoload
的在线帮助。
在 UNIX 下,可以使用实用程序 sed
或 awk
。
稍后讨论,或从包 lattice 中使用 xyplot
。
另请参阅 R 中的统计模型 中描述的方法
从某种意义上来说,这模仿了 S-PLUS 中的行为,因为在 S-PLUS 中,此运算符始终创建或赋值给全局变量。
因此它在 UNIX 下是隐藏的。
某些图形参数(例如当前设备的大小)仅供参考。
“Emacs Speaks Statistics” 包;请参阅 URL https://ESS.R-project.org/
可以使用 GNU readline 的仿真来构建 R,例如基于 NetBSD 的 editline(也称为 libedit),在这种情况下,可能只提供部分功能。
在 PC 键盘上,这通常是 Alt 键,有时是“Windows”键。在 Mac 键盘上,通常没有元键可用。
特别是,不是 6.3 或更高版本:这是从 R 3.4.0 开始解决的。