本指南介绍了如何将数据导入和导出到 R 中。
本手册适用于 R 版本 4.3.3 (2024-02-29)。
版权所有 © 2000–2023 R 核心团队
允许制作和分发本手册的逐字副本,前提是在所有副本上保留版权声明和本许可声明。
允许在逐字复制的条件下复制和分发本手册的修改版本,前提是整个派生作品在与本许可声明相同的许可声明条款下分发。
允许在上述修改版本的条件下复制和分发本手册的翻译版本,但本许可声明可以使用 R 核心团队批准的翻译版本。
本手册中关于关系数据库的部分部分基于 Douglas Bates 和 Saikat DebRoy 早期的手册。本手册的主要作者是 Brian Ripley。
许多志愿者为这里使用的包做出了贡献。下面列出了所提及包的主要作者:
- DBI:
David A. James
- dataframes2xls:
Guido van Steen
- foreign:
Thomas Lumley, Saikat DebRoy, Douglas Bates, Duncan Murdoch 和 Roger Bivand
- gdata:
Gregory R. Warnes
- ncdf4:
David Pierce
- rJava:
Simon Urbanek
- RJDBC:
Simon Urbanek
- RMySQL:
David James 和 Saikat DebRoy
- RNetCDF:
Pavel Michna
- RODBC:
Michael Lapsley 和 Brian Ripley
- ROracle:
David A. James
- RPostgreSQL:
Sameer Kumar Prayaga 和 Tomoaki Nishiyama
- RSPerl:
Duncan Temple Lang
- RSPython:
Duncan Temple Lang
- RSQLite:
David A. James
- SJava:
John Chambers 和 Duncan Temple Lang
- WriteXLS:
Marc Schwartz
- XLConnect:
Mirai Solutions GmbH
- XML:
Duncan Temple Lang
Brian Ripley 是连接支持的作者。
将数据读入统计系统进行分析,并将结果导出到其他系统以进行报告编写,可能是一项令人沮丧的任务,它可能比统计分析本身花费更多时间,即使大多数读者会发现后者更具吸引力。
本手册介绍了 R 本身或通过从 CRAN 或其他地方获得的包提供的导入和导出功能。
除非另有说明,否则本手册中描述的所有内容(至少在原则上)都可以在运行 R 的所有平台上使用。
一般而言,像 R 这样的统计系统并不特别适合处理大规模数据。其他一些系统在这方面比 R 更出色,本手册的一部分内容就是建议,与其在 R 中重复功能,不如让其他系统来完成这项工作!(例如,Therneau & Grambsch (2000) 评论说,他们更喜欢在 SAS 中进行数据操作,然后在 S 中使用 survival 包进行分析。)数据库操作系统通常非常适合操作和提取数据:这里讨论了几个与 DBMS 交互的包。
有一些包允许将 Java
、perl
和 python
等语言中开发的功能直接集成到 R 代码中,这使得使用这些语言中的功能更加合适。(参见 CRAN 上的 rJava 包。)
同样值得记住的是,R 就像 S 一样,源于 Unix 的小型可重用工具的传统,使用 awk
和 perl
等工具在导入之前或导出之后操作数据可能会很有益。Becker、Chambers & Wilks (1988,第 9 章) 中的案例研究就是一个例子,其中使用 Unix 工具在输入 S 之前检查和操作数据。传统的 Unix 工具现在已经广泛可用,包括 Windows 版本。
本手册最初编写于 2000 年,此后 R 包的数量和范围增加了百倍。对于专业数据格式,值得搜索一下是否已经存在合适的包。
导入 R 的最简单的数据形式是简单的文本文件,对于小型或中型问题,这通常是可以接受的。从文本文件导入的主要函数是 scan
,它也是 类似电子表格的数据 中讨论的大多数更方便函数的基础。
然而,所有统计顾问都熟悉客户提供一个包含数据的存储器(以前是软盘或 CD-R),数据以某种专有二进制格式存储,例如“Excel 电子表格”或“SPSS 文件”。通常最简单的方法是使用源应用程序将数据导出为文本文件(统计顾问会在他们的计算机上保存最常用的应用程序副本以备不时之需)。但是,这并不总是可行,从其他统计系统导入讨论了从 R 直接访问此类文件有哪些可用工具。对于 Excel 电子表格,可用的方法总结在读取 Excel 电子表格中。
在少数情况下,数据以二进制形式存储以实现紧凑性和快速访问。我们多次看到的一个应用是图像数据,它通常以内存中表示的字节流的形式存储,可能前面有一个标题。此类数据格式在二进制文件和二进制连接中讨论。
对于更大的数据库,通常使用数据库管理系统 (DBMS) 来处理数据。同样可以选择使用 DBMS 提取一个普通文件,但对于许多此类 DBMS,提取操作可以直接从 R 包中完成:参见关系数据库。通过网络连接导入数据在网络接口中讨论。
除非要导入的文件完全是 ASCII,否则通常需要知道它是如何编码的。对于文本文件,了解其结构的一个好方法是 file
命令行工具(对于 Windows,包含在 Rtools
中)。它会报告类似以下内容:
text.Rd: UTF-8 Unicode English text text2.dat: ISO-8859 English text text3.dat: Little-endian UTF-16 Unicode English character data, with CRLF line terminators intro.dat: UTF-8 Unicode text intro.dat: UTF-8 Unicode (with BOM) text
现代类 Unix 系统,包括 macOS,可能会生成 UTF-8 文件。Windows 可能会生成它称为“Unicode”的文件(UCS-2LE
或可能只是 UTF-16LE
1)。否则,大多数文件将使用 8 位编码,除非来自中文/日文/韩文区域设置(这些区域设置在通用使用中具有广泛的编码)。无法自动确定地检测哪种 8 位编码(尽管可能可以猜测,并且 file
可能会像上面的示例中那样猜测),因此您可能只需要向创建者询问一些线索(例如“Windows 上的俄语”)。
“BOM”(字节顺序标记,https://en.wikipedia.org/wiki/Byte_order_mark)会导致 Unicode 文件出现问题。在 Unix 世界中,BOM 很少使用,而在 Windows 世界中,它们几乎总是用于 UCS-2/UTF-16 文件,并且经常用于 UTF-8 文件。file
实用程序甚至无法识别没有 BOM 的 UCS-2 文件,但许多其他实用程序会拒绝读取带有 BOM 的文件,并且 IANA 针对 UTF-16LE
和 UTF-16BE
的标准禁止使用 BOM。我们经常不得不使用命令行实用程序 od
或十六进制编辑器来查看文件以确定其编码。
请注意,utf8
不是有效的编码名称(UTF-8
是),而 macintosh
是对有时称为“Mac Roman”编码的最便携的名称。
从 R 导出结果通常是一项不太有争议的任务,但仍然存在一些陷阱。会有一个目标应用程序,并且文本文件通常是最方便的交换媒介。(如果需要二进制文件,请参阅 二进制文件。)
函数 cat
是导出数据的函数的基础。它接受一个 file
参数,而 append
参数允许通过对 cat
的连续调用来写入文本文件。更好的是,特别是如果要多次执行此操作,可以打开一个用于写入或追加的 file
连接,并将 cat
写入该连接,然后 close
它。
最常见的任务是将矩阵或数据框写入文件,作为数字的矩形网格,可能带有行和列标签。这可以通过 write.table
和 write
函数来完成。函数 write
只会以指定的列数写入矩阵或向量(并转置矩阵)。函数 write.table
更方便,它会写入数据框(或可以强制转换为数据框的对象),并带有行和列标签。
将数据框写入文本文件时,需要考虑一些问题。
这些函数对实数/复数的大多数转换都是以全精度进行的,但由 write
进行的转换受 options(digits)
的当前设置控制。为了获得更多控制,请对数据框使用 format
,可能需要逐列进行。
R 倾向于让标题行没有行名的条目,因此文件看起来像
dist climb time Greenmantle 2.5 650 16.083 ...
其他一些系统需要一个(可能是空的)行名条目,这是 write.table
在指定参数 col.names = NA
时将提供的。Excel 就是这样的系统之一。
在文件中使用的常见字段分隔符是逗号,因为在英语国家,逗号不太可能出现在任何字段中。此类文件被称为 CSV(逗号分隔值)文件,包装函数 write.csv
提供了适当的默认值。在某些地区,逗号用作小数点(在 write.table
中通过 dec = ","
设置),而 CSV 文件使用分号作为字段分隔符:使用 write.csv2
获取适当的默认值。有一个用于 CSV 文件的 IETF 标准(它规定使用逗号和 CRLF 行结尾,为此使用 eol = "\r\n"
),RFC4180(参见 https://www.rfc-editor.org/rfc/rfc4180),但在实践中更重要的是文件是否可以被其目标应用程序读取。
使用分号或制表符 (sep = "\t"
) 可能是最安全的选项。
默认情况下,缺失值输出为 NA
,但这可以通过参数 na
更改。请注意,NaN
被 write.table
视为 NA
,但 cat
或 write
不会。
默认情况下,字符串会被引用(包括行名和列名)。参数 quote
控制是否引用字符和因子变量:某些程序(例如 Mondrian (https://en.wikipedia.org/wiki/Mondrian_(software)))不接受带引号的字符串。
如果字符串包含嵌入的引号,则需要小心。三种有用的形式是
> df <- data.frame(a = I("a \" quote")) > write.table(df) "a" "1" "a \" quote" > write.table(df, qmethod = "double") "a" "1" "a "" quote" > write.table(df, quote = FALSE, sep = ",") a 1,a " quote
第二种形式是电子表格常用的转义形式。
文本文件不包含关于其编码的元数据,因此对于非-ASCII 数据,文件需要针对要读取它的应用程序进行定位。所有这些函数都可以写入连接,这允许为文件指定编码,并且write.table
有一个fileEncoding
参数来简化此操作。
困难的部分是知道要使用什么文件编码。对于在 Windows 上使用,最好使用 Windows 所谓的“Unicode”2,即"UTF-16LE"
。使用 UTF-8 是制作可移植文件的良好方法,这些文件不会轻易与任何其他编码混淆,但即使 macOS 应用程序(其中 UTF-8 是系统编码)也可能无法识别它们,而 Windows 应用程序最不可能识别它们。显然,Excel:mac 2004/8 预计.csv
文件使用"macroman"
编码(早期版本的 Mac OS 中使用的编码)。
包 MASS 中的函数 write.matrix
提供了一个专门的接口用于写入矩阵,可以选择以块的形式写入它们,从而减少内存使用量。
可以使用 sink
将标准 R 输出重定向到文件,从而捕获(可能隐式)print
语句的输出。这通常不是最有效的方法,并且可能需要增加 options(width)
设置。
包 foreign 中的函数 write.foreign
使用 write.table
生成文本文件,并写入一个代码文件,该文件将读取此文本文件到另一个统计软件包中。目前支持导出到 SAS
、SPSS
和 Stata
。
从文本文件读取数据时,用户有责任了解并指定用于创建该文件的约定,例如注释字符、是否存在标题行、值分隔符、缺失值的表示(等等),如导出到文本文件中所述。一种可以用来描述内容和内容结构的标记语言可以使文件自描述,这样就不需要向读取数据的软件提供这些详细信息。
可扩展标记语言(更常见的是简称为XML)可用于提供这种结构,不仅适用于标准数据集,还适用于更复杂的数据结构。 XML 正在变得非常流行,并正在成为通用数据标记和交换的标准。 它正在被不同的社区用来描述地理数据,例如地图、图形显示、数学等等。
XML 提供了一种指定文件编码的方式,例如
<?xml version="1.0" encoding="UTF-8"?>
虽然它并不强制要求。
XML 包提供了在 R 中读取和写入 XML 文档的一般功能。 CRAN 上的 StatDataML 包是建立在 XML 之上的一个示例。 libxml2 C 库的另一个接口由 xml2 包提供。
yaml 是另一种用于结构化文本数据的系统,重点是人类可读性:它由 yaml 包支持。
在 导出到文本文件 中,我们看到了类电子表格文本文件格式的多种变体,其中数据以矩形网格形式呈现,可能带有行和列标签。 在本节中,我们将考虑将这些文件导入 R。
read.table
的变体 ¶函数 read.table
是读取矩形数据网格最方便的方法。由于可能性很多,还有其他几个函数调用 read.table
但更改了一组默认参数。
注意,read.table
是读取非常大的数值矩阵的低效方法:请参见下面的 scan
。
需要考虑的一些问题是
如果文件包含非 ASCII 字符字段,请确保它以正确的编码读取。这主要是针对在 UTF-8 环境中读取 Latin-1 文件的问题,可以通过以下方式解决:
read.table("file.dat", fileEncoding="latin1")
请注意,这将在任何可以表示 Latin-1 字符串的环境中工作,但并非所有希腊语/俄语/中文/日语……环境。
我们建议您明确指定 header
参数,按照惯例,标题行只包含列的条目,而不包含行标签,因此比其余行少一个字段。(如果 R 看到这一点,它会设置 header = TRUE
。)如果遇到一个文件,该文件包含一个(可能为空)用于行标签的标题字段,可以通过以下方式读取它:
read.table("file.dat", header = TRUE, row.names = 1)
列名可以通过 col.names
明确给出;明确的名称会覆盖标题行(如果有)。
通常,查看文件将确定要使用的字段分隔符,但在使用空格分隔的文件中,可能需要在默认的 sep = ""
(使用任何空格(空格、制表符或换行符)作为分隔符)之间进行选择,sep = " "
和 sep = "\t"
。请注意,分隔符的选择会影响引号字符串的输入。
如果您有一个包含空字段的制表符分隔文件,请务必使用 sep = "\t"
。
默认情况下,字符字符串可以用 ‘"’ 或 ‘'’ 引号括起来,在每种情况下,直到匹配的引号为止的所有字符都将被视为字符字符串的一部分。有效的引号字符集(可能为空)由 quote
参数控制。对于 sep = "\n"
,默认值将更改为 quote = ""
。
如果没有指定分隔符字符,则可以在引号字符串中通过在引号之前立即加上 ‘\’ 来转义引号,C 语言风格。
如果指定了分隔符字符,则可以在引号字符串中通过将引号加倍来转义引号,这在电子表格中很常见。例如
'One string isn''t two',"one more"
可以被
read.table("testfile", sep = ",")
读取。这在默认分隔符下不起作用。
默认情况下,假设文件包含字符字符串 NA
来表示缺失值,但这可以通过 na.strings
参数更改,该参数是一个包含一个或多个缺失值字符表示的向量。
数值列中的空字段也被视为缺失值。
在数值列中,接受 NaN
、Inf
和 -Inf
值。
从电子表格导出的文件通常会省略所有尾随的空字段(及其分隔符)。要读取此类文件,请设置 fill = TRUE
。
如果指定了分隔符,则字符字段中的前导和尾随空格将被视为字段的一部分。要删除空格,请使用参数 strip.white = TRUE
。
默认情况下,read.table
会忽略空行。这可以通过设置 blank.lines.skip = FALSE
来更改,这只有在与 fill = TRUE
结合使用时才有用,也许是为了使用空行来指示常规布局中的缺失情况。
除非采取任何特殊措施,否则 read.table
会将所有列读取为字符向量,然后尝试为数据框中的每个变量选择合适的类。它依次尝试 logical
、integer
、numeric
和 complex
,如果任何条目不缺失且无法转换,则继续进行。3 如果所有这些都失败,则该变量将转换为因子。
参数 colClasses
和 as.is
提供了更大的控制。指定 as.is = TRUE
将抑制将字符向量转换为因子(仅此而已)。使用 colClasses
允许为输入中的每一列设置所需的类:它将更快且使用更少的内存。
请注意,colClasses
和 as.is
是针对 每列指定的,而不是针对 每变量指定的,因此包括行名列(如果有)。
默认情况下,read.table
使用 ‘#’ 作为注释字符,如果遇到此字符(除了在引号字符串中),则忽略该行的其余部分。仅包含空格和注释的行将被视为空行。
如果已知数据文件中没有注释,则使用 comment.char = ""
更安全(并且可能更快)。
许多操作系统都有在文本文件中使用反斜杠作为转义字符的约定,但 Windows 没有(并在路径名中使用反斜杠)。在 R 中,是否将此类约定应用于数据文件是可选的。
read.table
和 scan
都有一个逻辑参数 allowEscapes
。默认情况下,此参数为 false,并且反斜杠仅在(如上所述的情况下)转义引号时被解释为转义字符。如果将其设置为 true,则会解释 C 样式转义,即控制字符 \a, \b, \f, \n, \r, \t, \v
以及八进制和十六进制表示形式,例如 \040
和 \0x2A
。任何其他转义字符都将被视为自身,包括反斜杠。请注意,Unicode 转义(例如 \uxxxx
)永远不会被解释。
这可以通过 fileEncoding
参数指定,例如
fileEncoding = "UCS-2LE" # Windows ‘Unicode’ files fileEncoding = "UTF-8"
如果您(正确地)知道文件的编码,这几乎总是有效的。但是,我们知道一个例外,即带有 BOM 的 UTF-8 文件。有些人声称 UTF-8 文件永远不应该有 BOM,但一些软件(显然包括 Excel:mac)使用它们,并且许多类 Unix 操作系统不接受它们。因此,面对一个 file
报告为
intro.dat: UTF-8 Unicode (with BOM) text
的文件,它可以在 Windows 上通过
read.table("intro.dat", fileEncoding = "UTF-8")
读取,但在类 Unix 系统上可能需要
read.table("intro.dat", fileEncoding = "UTF-8-BOM")
(在 UTF-8 本地环境中,即使不指定编码,这也很可能有效。)
便捷函数 read.csv
和 read.delim
为 read.table
提供了适用于从英语地区电子表格中导出的 CSV 和制表符分隔文件参数。变体 read.csv2
和 read.delim2
适用于那些使用逗号作为小数点,并且(对于 read.csv2
)使用分号分隔字段的地区。
如果 read.table
的选项指定不正确,错误消息通常会以以下形式出现:
Error in scan(file = file, what = what, sep = sep, : line 1 did not have 5 elements
或
Error in read.table("files.dat", header = TRUE) : more columns than column names
这可能提供足够的信息来找到问题,但辅助函数 count.fields
可以用来进一步调查。
读取大型数据网格时,效率可能很重要。指定 comment.char = ""
、colClasses
作为每列的原子向量类型之一(逻辑、整数、数值、复数、字符或可能是原始类型),以及给出 nrows
(要读取的行数,稍微高估比完全不指定要好)。请参阅后面部分的示例。
有时数据文件没有字段分隔符,但字段位于预先指定的列中。这在打孔卡时代非常普遍,现在有时仍然用于节省文件空间。
函数 read.fwf
提供了一种简单的方法来读取此类文件,指定一个字段宽度向量。该函数将文件作为整行读入内存,拆分结果字符字符串,写入一个临时制表符分隔文件,然后调用 read.table
。这对于小文件来说已经足够了,但对于更复杂的文件,我们建议使用 perl
等语言的工具来预处理文件。
函数 read.fortran
是一个类似的函数,用于固定格式文件,使用 Fortran 风格的列规范。
有时用于类似电子表格数据的旧格式是 DIF,即数据交换格式。
函数 read.DIF
提供了一种简单的方法来读取此类文件。它接受类似于 read.table
的参数,用于为每列分配类型。
在 Windows 上,电子表格程序通常将复制到剪贴板的电子表格数据存储为此格式;read.DIF("clipboard")
可以直接从那里读取它。它在处理包含空单元格的电子表格方面比 read.table("clipboard")
更健壮。
scan
¶read.table
和 read.fwf
都使用 scan
读取文件,然后处理 scan
的结果。它们非常方便,但有时直接使用 scan
更好。
函数 scan
有很多参数,我们已经在 read.table
下介绍了大多数参数。最关键的参数是 what
,它指定从文件中读取的变量模式列表。如果列表已命名,则名称将用于返回列表的组件。模式可以是数字、字符或复数,通常由示例指定,例如 0
、""
或 0i
。例如
cat("2 3 5 7", "11 13 17 19", file="ex.dat", sep="\n") scan(file="ex.dat", what=list(x=0, y="", z=0), flush=TRUE)
返回一个包含三个组件的列表,并丢弃文件中的第四列。
有一个函数 readLines
,如果只想将整行读入 R 以供进一步处理,它会更方便。
scan
的一个常见用途是读取大型矩阵。假设文件 matrix.dat 只包含 200 x 2000 矩阵的数字。然后我们可以使用
A <- matrix(scan("matrix.dat", n = 200*2000), 200, 2000, byrow = TRUE)
在一个测试中,这花费了 1 秒(在 Linux 下,在同一台机器上的 Windows 下花费了 3 秒),而
A <- as.matrix(read.table("matrix.dat"))
花费了 10 秒(以及更多内存),并且
A <- as.matrix(read.table("matrix.dat", header = FALSE, nrows = 200, comment.char = "", colClasses = "numeric"))
花费了 7 秒。差异几乎完全归因于读取 2000 个单独的短列的开销:如果它们的长度为 2000,scan
花费了 9 秒,而 read.table
花费了 18 秒(如果使用有效的方式,特别是指定 colClasses
)和 125 秒(如果使用天真方式)。
请注意,计时可能取决于读取的类型和数据。考虑读取一百万个不同的整数
writeLines(as.character((1+1e6):2e6), "ints.dat") xi <- scan("ints.dat", what=integer(0), n=1e6) # 0.77s xn <- scan("ints.dat", what=numeric(0), n=1e6) # 0.93s xc <- scan("ints.dat", what=character(0), n=1e6) # 0.85s xf <- as.factor(xc) # 2.2s DF <- read.table("ints.dat") # 4.5s
以及一小部分代码的百万个示例
code <- c("LMH", "SJC", "CHCH", "SPC", "SOM") writeLines(sample(code, 1e6, replace=TRUE), "code.dat") y <- scan("code.dat", what=character(0), n=1e6) # 0.44s yf <- as.factor(y) # 0.21s DF <- read.table("code.dat") # 4.9s DF <- read.table("code.dat", nrows=1e6) # 3.6s
请注意,这些计时高度依赖于操作系统(Windows 中的基本读取速度至少是 Linux 速度的两倍)以及垃圾回收器的精确状态。
有时电子表格数据采用紧凑格式,其中包含每个受试者的协变量,然后是该受试者的所有观察结果。R 的建模函数需要将观察结果放在单个列中。考虑以下来自重复 MRI 脑部测量样本的数据
Status Age V1 V2 V3 V4 P 23646 45190 50333 55166 56271 CC 26174 35535 38227 37911 41184 CC 27723 25691 25712 26144 26398 CC 27193 30949 29693 29754 30772 CC 24370 50542 51966 54341 54273 CC 28359 58591 58803 59435 61292 CC 25136 45801 45389 47197 47126
有两个协变量,每个受试者最多有四个测量值。数据从 Excel 导出为文件 mr.csv。
我们可以使用 stack
来帮助操作这些数据以获得单个响应。
zz <- read.csv("mr.csv", strip.white = TRUE) zzz <- cbind(zz[gl(nrow(zz), 1, 4*nrow(zz)), 1:2], stack(zz[, 3:6]))
结果为
Status Age values ind X1 P 23646 45190 V1 X2 CC 26174 35535 V1 X3 CC 27723 25691 V1 X4 CC 27193 30949 V1 X5 CC 24370 50542 V1 X6 CC 28359 58591 V1 X7 CC 25136 45801 V1 X11 P 23646 50333 V2 ...
函数 unstack
则执行相反的操作,可能对导出数据很有用。
另一种方法是使用函数 reshape
,方法如下:
> reshape(zz, idvar="id",timevar="var", varying=list(c("V1","V2","V3","V4")),direction="long") Status Age var V1 id 1.1 P 23646 1 45190 1 2.1 CC 26174 1 35535 2 3.1 CC 27723 1 25691 3 4.1 CC 27193 1 30949 4 5.1 CC 24370 1 50542 5 6.1 CC 28359 1 58591 6 7.1 CC 25136 1 45801 7 1.2 P 23646 2 50333 1 2.2 CC 26174 2 38227 2 ...
函数 reshape
的语法比 stack
更复杂,但可用于“长”形式数据,其中包含多个列(本例中只有一列)。使用 direction="wide"
,reshape
还可以执行相反的转换。
有些人更喜欢包 reshape、reshape2 和 plyr 中的工具。
以数组形式显示高维列联表通常很不方便。在分类数据分析中,此类信息通常以带边框的二维数组形式表示,其中前导行和列指定与单元格计数相对应的因子水平组合。这些行和列通常是“参差不齐”的,因为标签仅在更改时显示,并遵循明显的约定,即从上到下读取行,从左到右读取列。在 R 中,可以使用 ftable
创建此类“扁平”列联表, 该函数创建 "ftable"
类的对象,并具有相应的打印方法。
举个简单的例子,考虑 R 标准数据集 UCBAdmissions
,它是一个三维列联表,结果是将 1973 年加州大学伯克利分校六个最大系的研究生申请者分类,按录取情况和性别分类。
> data(UCBAdmissions) > ftable(UCBAdmissions) Dept A B C D E F Admit Gender Admitted Male 512 353 120 138 53 22 Female 89 17 202 131 94 24 Rejected Male 313 207 205 279 138 351 Female 19 8 391 244 299 317
打印的表示形式显然比将数据显示为三维数组更有用。
还有一个函数 read.ftable
用于从文件中读取扁平化的列联表。 它有额外的参数来处理关于行和列变量名称和级别如何表示的变体。 read.ftable
的帮助页面有一些有用的示例。可以使用 as.table
将扁平化的表格转换为标准的数组形式的列联表。
请注意,扁平化的表格的特点是它们的行(以及可能还有列)标签的“参差不齐”显示。如果给出了行变量级别的完整网格,则应该使用 read.table
读取数据,并使用 xtabs
从中创建列联表。
在本章中,我们考虑读取另一个统计系统写入的二进制数据文件的问题。这通常最好避免,但如果原始系统不可用,则可能无法避免。
在所有情况下,所描述的功能都是为来自其他系统特定版本的(通常是在 2000 年代初)数据文件编写的,并且不一定已针对其他系统的最新版本更新。
推荐的包 foreign 提供了从这些统计系统生成的 文件导入功能,以及导出到 Stata 的功能。在某些情况下,这些函数可能比 read.table
需要更少的内存。 write.foreign
(参见 导出到文本文件)提供了一个导出机制,目前支持 SAS
、SPSS
和 Stata
。
EpiInfo 5 和 6 版本将数据存储在自描述的固定宽度文本格式中。 read.epiinfo
将从这些 .REC 文件中读取数据到 R 数据框中。EpiData 也以这种格式生成数据。
函数 read.mtp
导入 “Minitab 可移植工作表”。这将工作表的组件作为 R 列表返回。
函数 read.xport
读取 SAS 传输 (XPORT) 格式的文件,并返回一个数据框列表。如果您的系统上安装了 SAS,则可以使用函数 read.ssd
创建并运行一个 SAS 脚本,该脚本将 SAS 永久数据集 (.ssd 或 .sas7bdat) 保存为传输格式。然后它调用 read.xport
来读取结果文件。(包 Hmisc 有一个类似的函数 sas.get
,也运行 SAS。)对于那些没有访问 SAS 但在 Windows 上运行的用户,可以使用 SAS 系统查看器(免费下载)打开 SAS 数据集并将其导出为例如 .csv 格式。
函数 read.S
可以读取由 S-PLUS 3.x、4.x 或 2000 在 (32 位) Unix 或 Windows 上生成的二进制对象(并且可以在不同的操作系统上读取它们)。它能够读取许多但不是所有 S 对象:特别是它可以读取向量、矩阵和数据框以及包含这些对象的列表。
函数 data.restore
读取 S-PLUS 数据转储(由 data.dump
创建),具有相同的限制(除了可以读取来自 Alpha 平台的转储)。应该可以读取由 S-PLUS 5.x 及更高版本使用 data.dump(oldStyle=T)
写入的数据转储。
如果您有权访问 S-PLUS,通常更可靠的是在 S-PLUS 中 dump
对象,并在 R 中 source
转储文件。对于 S-PLUS 5.x 及更高版本,您可能需要使用 dump(..., oldStyle=T)
,并且为了读取非常大的对象,最好将转储文件用作批处理脚本,而不是使用 source
函数。
函数 read.spss
可以读取由 SPSS 中的 “save” 和 “export” 命令创建的文件。它返回一个列表,其中包含保存的数据集中每个变量的一个组件。 SPSS 变量的值标签可以选择性地转换为 R 因子。
SPSS 数据录入是一个用于创建数据录入表单的应用程序。默认情况下,它创建的数据文件包含 read.spss
无法处理的额外格式信息,但可以将数据导出为普通 SPSS 格式。
一些第三方应用程序声称以 “SPSS 格式” 生成数据,但格式有所不同:read.spss
可能能够或可能无法处理这些数据。
Stata .dta 文件是一种二进制文件格式。函数 read.dta
和 write.dta
可以读取和写入 Stata 5 到 12 版本的文件。Stata 变量的值标签可以选择性地转换为(和从)R 因子。对于 Stata 13 及更高版本,请参见 CRAN 包 readstata13 和 haven。
read.systat
读取那些 Systat SAVE
文件,这些文件是矩形数据文件 (mtype = 1
),在小端机器(例如来自 Windows)上写入。这些文件扩展名为 .sys 或(最近).syd。
Octave 是一个数值线性代数系统 (https://octave.org/),包 foreign 中的函数 read.octave
可以读取使用 Octave 命令 save -ascii
创建的 Octave 文本数据格式文件,支持大多数常见的变量类型,包括标准原子类型(实数和复数标量、矩阵和 N 维数组、字符串、范围和布尔标量和矩阵)和递归类型(结构体、单元格和列表)。
R 处理的数据类型存在限制。由于 R 操作的所有数据都驻留在内存中,并且在执行函数期间可以创建数据的多个副本,因此 R 不适合处理极其庞大的数据集。大小超过(几百)兆字节的数据对象会导致 R 耗尽内存,尤其是在 32 位操作系统上。
R 不容易支持对数据的并发访问。也就是说,如果多个用户访问(可能更新)相同的数据,则一个用户所做的更改将不会对其他用户可见。
R 支持数据的持久性,您可以从一个会话中保存数据对象或整个工作表并在后续会话中恢复它,但存储数据的格式是特定于 R 的,并且不容易被其他系统操作。
数据库管理系统 (DBMS),特别是关系型数据库管理系统 (RDBMS),旨在出色地完成所有这些任务。 它们的优势在于
DBMS 可能用于的统计应用程序类型包括提取 10% 的数据样本,交叉制表数据以生成多维列联表,以及从数据库中逐组提取数据以进行单独分析。
越来越多的操作系统本身出于这些原因使用 DBMS,因此现在很可能您的(非 Windows)操作系统上已经安装了 DBMS。 Akonadi 用于 KDE4 存储个人信息。 包括 Mail 和 Address Book 在内的多个 macOS 应用程序使用 SQLite。
传统上,存在大型(且昂贵)的商业 RDBMS(Informix;Oracle;Sybase;IBM 的 DB2;Microsoft SQL Server 在 Windows 上)以及学术和小型系统数据库(如 MySQL4、PostgreSQL、Microsoft Access 等),前者以对数据安全功能的更大重视为标志。 这条界线正在变得模糊,MySQL 和 PostgreSQL 拥有越来越多的高端功能,并且商业 DBMS 提供了免费的“express”版本。
还有其他常用的数据源,包括电子表格、非关系型数据库甚至文本文件(可能已压缩)。 开放数据库连接 (ODBC) 是使用所有这些数据源的标准。 它起源于 Windows(参见 https://docs.microsoft.com/en-us/sql/odbc/microsoft-open-database-connectivity-odbc),但也已在 Linux/Unix/macOS 上实现。
本章后面介绍的所有软件包都为客户端/服务器数据库提供客户端。数据库可以驻留在同一台机器上,也可以(更常见的是)远程驻留。有一个ISO标准(实际上有几个:SQL92 是 ISO/IEC 9075,也称为 ANSI X3.135-1992,以及正在使用的 SQL99)用于称为 SQL(结构化查询语言,有时发音为“sequel”:参见 Bowman et al. 1996 和 Kline 和 Kline 2001)的接口语言,这些 DBMS 在不同程度上支持该语言。
更全面的 R 接口在幕后为常见操作生成 SQL,但在所有情况下,都需要直接使用 SQL 来执行复杂操作。按照惯例,SQL 以大写形式编写,但许多用户会发现使用 R 接口函数中的小写形式更方便。
关系型 DBMS 将数据存储为一个 表(或 关系)数据库,它与 R 数据框非常相似,因为它们由一个类型(数字、字符、日期、货币等)的 列或 字段和包含一个实体的观察结果的 行或 记录组成。
SQL “查询”是对关系数据库的非常通用的操作。经典查询是 SELECT 语句,其类型为
SELECT State, Murder FROM USArrests WHERE Rape > 30 ORDER BY Murder SELECT t.sch, c.meanses, t.sex, t.achieve FROM student as t, school as c WHERE t.sch = c.id SELECT sex, COUNT(*) FROM student GROUP BY sex SELECT sch, AVG(sestat) FROM student GROUP BY sch LIMIT 10
第一个选择从 R 数据框 USArrests
中选择的两个列,该数据框已复制到数据库表中,对第三列进行子集,并要求对结果进行排序。第二个对两个表 student
和 school
执行数据库 联接,并返回四列。第三和第四个查询进行一些交叉制表,并返回计数或平均值。(五个聚合函数是 COUNT(*) 和 SUM、MAX、MIN 和 AVG,每个函数都应用于单个列。)
SELECT 查询使用 FROM 来选择表,使用 WHERE 来指定包含条件(或由 AND 或 OR 分隔的多个条件),并使用 ORDER BY 来对结果进行排序。与数据框不同,RDBMS 表中的行最好被认为是无序的,如果没有 ORDER BY 语句,则排序是不确定的。您可以通过逗号分隔多个列来对多个列(按字典顺序)进行排序。在 ORDER BY 后面放置 DESC 将使排序按降序排列。
SELECT DISTINCT 查询将只返回所选表中每个不同行的单个副本。
GROUP BY 子句根据标准选择行的子组。如果指定了多个列(用逗号分隔),则可以通过五个聚合函数之一对多路交叉分类进行汇总。HAVING 子句允许选择根据聚合值包含或排除组。
如果 SELECT 语句包含一个产生唯一排序的 ORDER BY 语句,则可以添加一个 LIMIT 子句来按数量选择一个连续的输出行块。这对于一次检索一行块很有用。(除非排序是唯一的,否则可能不可靠,因为 LIMIT 子句可用于优化查询。)
有查询用于创建表(CREATE TABLE,但通常在这些接口中将数据帧复制到数据库中),插入、删除或更新数据。表通过 DROP TABLE '查询' 销毁。
Kline 和 Kline(2001)讨论了 SQL 在 Microsoft SQL Server 2000、Oracle、MySQL 和 PostgreSQL 中实现的细节。
数据可以以各种数据类型存储在数据库中。数据类型的范围是特定于 DBMS 的,但 SQL 标准定义了许多类型,包括以下广泛实现的类型(通常不是通过 SQL 名称)。
float(p)
实数,具有可选精度。通常称为 real
或 double
或 double precision
。
integer
32 位整数。通常称为 int
。
smallint
16 位整数
character(n)
固定长度字符字符串。通常称为 char
。
character varying(n)
可变长度字符字符串。通常称为 varchar
。几乎总是限制为 255 个字符。
boolean
真或假。有时称为 bool
或 bit
。
date
日历日期
time
一天中的时间
timestamp
日期和时间
有 time
和 timestamp
的变体,with timezone
。其他广泛实现的类型是 text
和 blob
,分别用于大型文本块和二进制数据。
更全面的 R 接口包会隐藏类型转换问题,对用户来说是透明的。
在 CRAN 上有几个包可以帮助 R 与数据库管理系统进行通信。它们提供了不同级别的抽象。一些包提供了将整个数据框复制到数据库和从数据库复制出来的方式。所有包都具有通过 SQL 查询在数据库中选择数据并以数据框的形式或分段(通常是按行分组)检索结果的功能。
除了 RODBC 之外,所有包都与一个数据库管理系统绑定,但有一个关于统一的“前端”包 DBI (https://developer.r-project.org/db/) 的提议,它与一个“后端”结合使用,其中最成熟的是 RMySQL。同样在 CRAN 上还有后端 ROracle、RPostgreSQL 和 RSQLite(它与捆绑的数据库管理系统 SQLite
协同工作,https://www.sqlite.org/index.html) 以及 RJDBC(它使用 Java,可以连接到任何具有 JDBC 驱动程序的数据库管理系统)。
PL/R (https://github.com/postgres-plr/plr) 是一个将 R 嵌入 PostgreSQL 的项目。
包 RMongo 为 ‘MongoDB’ (https://en.wikipedia.org/wiki/MongoDB) 数据库提供了一个 R 接口,该接口使用 JavaScript 而不是 SQL 进行查询。包 mongolite 是另一个使用 mongodb 的 C 驱动程序的客户端。
包 RMySQL 在 CRAN 上提供了与 MySQL 数据库系统(参见 https://www.mysqlserver.cn 和 Dubois,2000)或其分支 MariaDB(参见 https://mariadb.org/)的接口。此处的描述适用于版本 0.5-0
及更高版本:早期版本具有完全不同的接口。当前版本需要 DBI 包,此描述将适用于对 DBI 的所有其他后端进行的微小更改。
MySQL 存在于 Unix/Linux/macOS 和 Windows 上:有一个在 GPL 下发布的 “社区版”,但也有商业许可证可用。MySQL 最初是一个 “轻量级” 数据库。(它保留了操作系统文件系统区分大小写时的名称的大小写,因此不在 Windows 上。)
调用 dbDriver("MySQL")
返回一个数据库连接管理器对象,然后调用 dbConnect
打开一个数据库连接,该连接随后可以通过调用通用函数 dbDisconnect
关闭。使用 dbDriver("Oracle")
、dbDriver("PostgreSQL")
或 dbDriver("SQLite")
与这些 DBMS 和包 ROracle、RPostgreSQL 或 RSQLite 分别使用。
SQL 查询可以通过 dbSendQuery
或 dbGetQuery
发送。 dbGetquery
发送查询并检索结果作为数据框。 dbSendQuery
发送查询并返回一个继承自 "DBIResult"
类的对象,该对象可用于检索结果,随后可用于调用 dbClearResult
来删除结果。
函数 fetch
用于检索查询结果中的一些或所有行,作为列表。 函数 dbHasCompleted
指示是否已获取所有行,而 dbGetRowCount
返回结果中的行数。
这些是用于读写/测试/删除数据库中表的便捷接口。 dbReadTable
和 dbWriteTable
在 R 数据框之间复制,将数据框的行名映射到 MySQL
表中的 row_names
字段。
> library(RMySQL) # will load DBI as well ## open a connection to a MySQL database > con <- dbConnect(dbDriver("MySQL"), dbname = "test") ## list the tables in the database > dbListTables(con) ## load a data frame into the database, deleting any existing copy > data(USArrests) > dbWriteTable(con, "arrests", USArrests, overwrite = TRUE) TRUE > dbListTables(con) [1] "arrests" ## get the whole table > dbReadTable(con, "arrests") Murder Assault UrbanPop Rape Alabama 13.2 236 58 21.2 Alaska 10.0 263 48 44.5 Arizona 8.1 294 80 31.0 Arkansas 8.8 190 50 19.5 ... ## Select from the loaded table > dbGetQuery(con, paste("select row_names, Murder from arrests", "where Rape > 30 order by Murder")) row_names Murder 1 Colorado 7.9 2 Arizona 8.1 3 California 9.0 4 Alaska 10.0 5 New Mexico 11.4 6 Michigan 12.1 7 Nevada 12.2 8 Florida 15.4 > dbRemoveTable(con, "arrests") > dbDisconnect(con)
CRAN 上的 RODBC 包提供了对支持 ODBC 接口的数据库源的接口。 这是非常广泛可用的,并且允许相同的 R 代码访问不同的数据库系统。 RODBC 在 Unix/Linux、Windows 和 macOS 上运行,几乎所有数据库系统都提供对 ODBC 的支持。 我们已经在 Windows 上测试了 Microsoft SQL Server、Access、MySQL、PostgreSQL、Oracle 和 IBM DB2,以及 Linux 上的 MySQL、MariaDB、Oracle、PostgreSQL 和 SQLite。
ODBC 是一个客户端-服务器系统,我们已经成功地从 Windows 客户端连接到运行在 Unix 服务器上的 DBMS,反之亦然。
在 Windows 上,ODBC 支持是操作系统的一部分。 在 Unix/Linux 上,您将需要一个 ODBC 驱动程序管理器,例如 unixODBC (https://www.unixodbc.org/) 或 iOBDC (https://www.iodbc.org/:这在 macOS 中预先安装) 以及您数据库系统的已安装驱动程序。
Windows 不仅为 DBMS 提供驱动程序,还为 Excel (.xls) 电子表格、DBase (.dbf) 文件甚至文本文件提供驱动程序。(不需要安装上面提到的应用程序。支持的文件格式取决于驱动程序的版本。)有适用于 Excel 和 Access 2007/2010 的版本(访问 https://www.microsoft.com/en-us/download/default.aspx,搜索“Office ODBC”,这将引导您找到 AccessDatabaseEngine.exe),以及“2007 Office System Driver”(后者有适用于 64 位 Windows 的版本,并且也可以读取早期版本)。
在 macOS 上,Actual Technologies (https://www.actualtech.com/product_access.php) 驱动程序为 Access 数据库和 Excel 电子表格(不包括 Excel 2007/2010)提供 ODBC 接口。
可以建立多个并发连接。通过调用 odbcConnect
或 odbcDriverConnect
(在 Windows GUI 上,这允许通过对话框选择数据库)打开连接,该调用返回一个句柄,用于后续访问数据库。打印连接将提供有关 ODBC 连接的一些详细信息,调用 odbcGetInfo
将提供有关客户端和服务器的详细信息。
通过调用 close
或 odbcClose
关闭连接,并且当没有 R 对象引用它时以及在 R 会话结束时也会关闭连接(并发出警告)。
可以使用 sqlTables
查找连接上的表的详细信息。
函数 sqlSave
将 R 数据框复制到数据库中的表,而 sqlFetch
将数据库中的表复制到 R 数据框。
一个 SQL 查询可以通过调用 sqlQuery
发送到数据库。这将返回一个 R 数据框中的结果。(sqlCopy
将查询发送到数据库并将结果保存为数据库中的表。) 通过首先调用 odbcQuery
然后调用 sqlGetResults
来获取结果,可以获得更精细的控制。后者可以在循环中使用,以一次检索有限数量的行,就像函数 sqlFetchMore
一样。
以下是一个使用 PostgreSQL 的示例,其中 ODBC 驱动程序将列名和数据框名称映射为小写。我们使用之前创建的数据库 testdb
,并在 ~/.odbc.ini 中的 unixODBC
下设置了 DSN(数据源名称)。完全相同的代码在使用 MyODBC 访问 Linux 或 Windows 下的 MySQL 数据库时也能正常工作(其中 MySQL 也将名称映射为小写)。在 Windows 下,DSN 在控制面板中的 ODBC 小程序中设置(在“管理工具”部分中的“数据源 (ODBC)”)。
> library(RODBC) ## tell it to map names to l/case > channel <- odbcConnect("testdb", uid="ripley", case="tolower") ## load a data frame into the database > data(USArrests) > sqlSave(channel, USArrests, rownames = "state", addPK = TRUE) > rm(USArrests) ## list the tables in the database > sqlTables(channel) TABLE_QUALIFIER TABLE_OWNER TABLE_NAME TABLE_TYPE REMARKS 1 usarrests TABLE ## list it > sqlFetch(channel, "USArrests", rownames = "state") murder assault urbanpop rape Alabama 13.2 236 58 21.2 Alaska 10.0 263 48 44.5 ... ## an SQL query, originally on one line > sqlQuery(channel, "select state, murder from USArrests where rape > 30 order by murder") state murder 1 Colorado 7.9 2 Arizona 8.1 3 California 9.0 4 Alaska 10.0 5 New Mexico 11.4 6 Michigan 12.1 7 Nevada 12.2 8 Florida 15.4 ## remove the table > sqlDrop(channel, "USArrests") ## close the connection > odbcClose(channel)
作为在 Windows 下使用 ODBC 和 Excel 电子表格的简单示例,我们可以通过以下方式从电子表格中读取数据:
> library(RODBC) > channel <- odbcConnectExcel("bdr.xls") ## list the spreadsheets > sqlTables(channel) TABLE_CAT TABLE_SCHEM TABLE_NAME TABLE_TYPE REMARKS 1 C:\\bdr NA Sheet1$ SYSTEM TABLE NA 2 C:\\bdr NA Sheet2$ SYSTEM TABLE NA 3 C:\\bdr NA Sheet3$ SYSTEM TABLE NA 4 C:\\bdr NA Sheet1$Print_Area TABLE NA ## retrieve the contents of sheet 1, by either of > sh1 <- sqlFetch(channel, "Sheet1") > sh1 <- sqlQuery(channel, "select * from [Sheet1$]")
请注意,表的规范与 sqlTables
返回的名称不同:sqlFetch
能够映射这些差异。
二进制连接 (连接) 现在是处理二进制文件的首选方式。
包 h5,Bioconductor 的 rhdf5,RNetCDF 和 ncdf4 在 CRAN 上提供了对 NASA 的 HDF5(分层数据格式,参见 https://www.hdfgroup.org/HDF5/)和 UCAR 的 netCDF 数据文件(网络通用数据格式,参见 https://www.unidata.ucar.edu/software/netcdf/)的接口。
这两个都是以数组为导向的方式存储科学数据的系统,包括描述、标签、格式、单位等。HDF5 还允许 组数组,R 接口将列表映射到 HDF5 组,并可以写入数字和字符向量以及矩阵。
NetCDF 的版本 4 格式(令人困惑的是,在 netCDF 4.1.1 及更高版本中实现,但在 4.0.1 中没有实现)包括使用各种 HDF5 格式。这由包 ncdf4 处理,而 RNetCDF 处理版本 3 文件。
支持这些格式的软件的可用性在一定程度上受平台限制,尤其是在 Windows 上。
dBase
是 Ashton-Tate 编写的 DOS 程序,后来被 Borland 收购,它具有一个流行的二进制平面文件格式,文件扩展名为 .dbf。它已被“Xbase”系列数据库采用,涵盖 dBase、Clipper、FoxPro 及其 Windows 等效项 Visual dBase、Visual Objects 和 Visual FoxPro(参见 https://www.clicketyclick.dk/databases/xbase/format/)。dBase 文件包含一个标题,然后是一系列字段,因此最类似于 R 数据框。数据本身以文本格式存储,可以包含字符、逻辑和数字字段,以及更高版本中的其他类型(例如,参见 https://www.loc.gov/preservation/digital/formats/fdd/fdd000325.shtml 和 https://www.clicketyclick.dk/databases/xbase/format/index.html)。
函数 read.dbf
和 write.dbf
提供了在所有 R 平台上读取和写入基本 DBF 文件的方法。对于 Windows 用户,包 RODBC 中的 odbcConnectDbase
提供了更全面的功能来读取 DBF 文件 通过 Microsoft 的 dBase ODBC 驱动程序(Visual FoxPro 驱动程序也可以通过 odbcDriverConnect
使用)。
一类特殊的二进制文件是表示图像的,一个常见的请求是将这样的文件读入 R 作为矩阵。
图像文件有很多格式(大多数都有很多变体),可能需要使用外部转换软件将图像先转换为当前某个包提供的 R 读取器支持的格式之一。一个通用的例子是 ImageMagick 及其分支 GraphicsMagick。它们提供命令行程序 convert
和 gm convert
来将图像从一种格式转换为另一种格式:它们可以输入什么格式是在编译时确定的,支持的格式可以通过例如 convert -list format
列出。
包 pixmap 有一个函数 read.pnm
用于读取 PBM(黑白)、PGM(灰度)和 PPM(RGB 彩色)格式的“便携式任意图”。这些也称为“netpbm”格式。
包 bmp、jpeg 和 png 读取以它们命名的格式。另请参见包 biOps 和 Momocs,以及 Bioconductor 包 EBImage。
TIFF 更像是一种元格式,一个包装器,可以在其中嵌入各种各样的图像格式。包 rtiff 和 tiff 可以读取一些子格式(取决于它们编译时使用的外部 libtiff
软件)。有一些针对特定子格式的功能,例如在 Bioconductor 包 beadarray 中。
栅格文件在地理科学中很常见,rgdal 包提供了 GDAL 的接口,GDAL 自身提供了一些读取栅格文件的功能,并链接到许多其他功能。它支持的格式在编译 GDAL 时确定:使用 gdalDrivers()
查看您正在使用的版本支持哪些格式。这对于不常见的格式(如 JPEG 2000)很有用(JPEG 2000 与 JPEG 是不同的格式,目前在 macOS 或 Windows 的 rgdal 二进制版本中不支持)。
连接 在 R 中的意义与 Chambers (1998) 和 Ripley (2001) 中的意义相同,是一组函数,用于用灵活的接口替换对类似文件的对象的用法。
最熟悉的连接类型将是文件,文件连接由函数 file
创建。文件连接可以(如果操作系统允许特定文件)以文本或二进制模式打开以进行读取、写入或追加。实际上,文件可以同时打开以进行读取和写入,R 为读取和写入保留单独的文件位置。
请注意,默认情况下,连接在创建时不会打开。规则是,使用连接的函数应该在连接未打开的情况下打开连接(需要),并在使用后关闭连接(如果打开了连接)。简而言之,将连接保留在您找到它的状态。存在通用的函数 open
和 close
,它们具有显式打开和关闭连接的方法。
使用 gzip
算法压缩的文件可以通过 gzfile
函数创建的连接使用,而使用 bzip2
压缩的文件可以通过 bzfile
函数使用。
Unix 程序员习惯于处理特殊文件 stdin
、stdout
和 stderr
。这些在 R 中以 终端连接 的形式存在。它们可以是普通文件,但也可以指代来自 GUI 控制台的输入和输出。(即使使用标准 Unix R 接口,stdin
也指代来自 readline
的提交行,而不是文件。)
三个终端连接始终处于打开状态,无法打开或关闭。 stdout
和 stderr
通常分别用于正常输出和错误消息。它们通常会发送到同一个地方,但正常输出可以通过调用 sink
重定向,而错误输出则发送到 stderr
,除非通过 sink, type="message")
重定向。请仔细注意这里使用的语言:连接无法重定向,但输出可以发送到其他连接。
文本连接 是另一种输入来源。它们允许将 R 字符向量读取为从文本文件读取行。文本连接通过调用 textConnection
创建并打开,该函数在创建时将字符向量的当前内容复制到内部缓冲区。
文本连接还可以用于将 R 输出捕获到字符向量中。 textConnection
可以被要求创建一个新的字符对象或追加到现有的字符对象,这两种情况都在用户的工作空间中。连接通过调用 textConnection
打开,并且始终可以在 R 对象中获得输出到连接的完整行。关闭连接会将任何剩余的输出写入字符向量的最后一个元素。
管道 是一种特殊类型的文件,它连接到另一个进程,管道连接由 pipe
函数创建。打开一个用于写入的管道连接(追加到管道没有意义)会运行一个操作系统命令,并将它的标准输入连接到 R 随后写入该连接的内容。相反,打开一个用于输入的管道连接会运行一个操作系统命令,并使其标准输出可供 R 从该连接输入。
可以使用 url
函数读取类型为 ‘http://’、‘https://’、‘ftp://’ 和 ‘file://’ 的 URL。为了方便起见,file
也会接受这些作为文件规范并调用 url
。
套接字也可以通过 socketConnection
函数用作连接,该函数在支持 Berkeley 风格套接字的平台(大多数 Unix 系统、Linux 和 Windows)上可用。套接字可以写入或读取,并且可以使用客户端和服务器套接字。
我们已经描述了函数 cat
、write
、write.table
和 sink
作为写入文件,如果参数 append = TRUE
,则可能追加到文件,这正是它们在 R 版本 1.2.0 之前所做的。
当前的行为是等效的,但实际上发生的是,当 file
参数是字符字符串时,会打开一个文件连接(用于写入或追加),并在函数调用结束时关闭。如果我们想要重复写入同一个文件,更有效的方法是显式声明和打开连接,并将连接对象传递给对输出函数的每次调用。这也使得写入管道成为可能,这在早期通过语法 file = "|cmd"
(仍然可以使用)以有限的方式实现。
有一个函数 writeLines
用于将完整的文本行写入连接。
一些简单的例子是
zz <- file("ex.data", "w") # open an output file connection cat("TITLE extra line", "2 3 5 7", "", "11 13 17", file = zz, sep = "\n") cat("One more line\n", file = zz) close(zz) ## convert decimal point to comma in output, using a pipe (Unix) ## both R strings and (probably) the shell need \ doubled zz <- pipe(paste("sed s/\\\\./,/ >", "outfile"), "w") cat(format(round(rnorm(100), 4)), sep = "\n", file = zz) close(zz) ## now look at the output file: file.show("outfile", delete.file = TRUE) ## capture R output: use examples from help(lm) zz <- textConnection("ex.lm.out", "w") sink(zz) example(lm, prompt.echo = "> ") sink() close(zz) ## now ‘ex.lm.out’ contains the output for futher processing. ## Look at it by, e.g., cat(ex.lm.out, sep = "\n")
从连接中读取的基本函数是 scan
和 readLines
。这些函数接受一个字符字符串参数,并在函数调用期间打开一个文件连接,但显式打开文件连接允许以不同的格式顺序读取文件。
其他调用 scan
的函数也可以使用连接,特别是 read.table
。
一些简单的例子是
## read in file created in last examples readLines("ex.data") unlink("ex.data") ## read listing of current directory (Unix) readLines(pipe("ls -1")) # remove trailing commas from an input file. # Suppose we are given a file ‘data’ containing 450, 390, 467, 654, 30, 542, 334, 432, 421, 357, 497, 493, 550, 549, 467, 575, 578, 342, 446, 547, 534, 495, 979, 479 # Then read this by scan(pipe("sed -e s/,$// data"), sep=",")
为了方便起见,如果 file
参数指定了 FTP、HTTP 或 HTTPS URL,则通过 url
打开 URL 以供读取。还可以通过 ‘file://foo.bar’ 指定文件。
C 语言程序员可能熟悉 ungetc
函数,它可以将一个字符回退到文本输入流中。R 连接以更强大的方式实现了相同的想法,即可以通过调用 pushBack
将(本质上)任意数量的文本行回退到连接中。
回退操作作为堆栈工作,因此读取请求首先使用最近回退的文本中的每一行,然后使用之前回退的文本,最后从连接本身读取。一旦完全读取了回退的行,它就会被清除。可以通过调用 pushBackLength
来查找待处理的回退行数。
一个简单的例子将展示这个想法。
> zz <- textConnection(LETTERS) > readLines(zz, 2) [1] "A" "B" > scan(zz, "", 4) Read 4 items [1] "C" "D" "E" "F" > pushBack(c("aa", "bb"), zz) > scan(zz, "", 4) Read 4 items [1] "aa" "bb" "G" "H" > close(zz)
回退仅适用于以文本模式打开的输入连接。
可以通过 showConnections()
找到用户当前打开的所有连接的摘要,可以通过 showConnections(all = TRUE)
找到所有连接的摘要,包括已关闭的连接和终端连接。
通用函数 seek
可用于读取和(在某些连接上)重置当前的读写位置。不幸的是,它依赖于操作系统设施,这些设施可能不可靠(例如,在 Windows 下使用文本文件)。函数 isSeekable
报告 seek
是否可以更改其参数给出的连接上的位置。
函数 truncate
可用于在当前位置截断以写入方式打开的文件。它仅适用于 file
连接,并且并非在所有平台上都实现。
函数 readBin
和 writeBin
用于读取和写入二进制连接。通过在模式规范中附加 "b"
来以二进制模式打开连接,即使用模式 "rb"
进行读取,使用模式 "wb"
或 "ab"
(在适当的情况下)进行写入。这些函数具有以下参数
readBin(con, what, n = 1, size = NA, endian = .Platform$endian) writeBin(object, con, size = NA, endian = .Platform$endian)
在每种情况下,con
都是一个连接,如果需要,它将在调用期间打开,如果给出了一个字符字符串,则假定它指定一个文件名。
描述写入操作相对简单,因此我们先从这里开始。 object
应该是一个原子向量对象,即一个模式为 numeric
、integer
、logical
、character
、complex
或 raw
的向量,且不包含属性。默认情况下,它将以字节流的形式写入文件,与内存中的表示方式完全一致。
readBin
从文件中读取字节流,并根据 what
指定的模式将其解释为向量。这可以是适当模式的对象(例如 what=integer()
),也可以是描述模式的字符字符串(前一段中给出的五个模式之一,或 "double"
或 "int"
)。参数 n
指定从连接中读取的向量元素的最大数量:如果可用元素较少,则将返回更短的向量。参数 signed
允许将 1 字节和 2 字节整数读取为有符号整数(默认值)或无符号整数。
其余两个参数用于写入或读取数据以与另一个程序或另一个平台进行交换。默认情况下,二进制数据将直接从内存传输到连接或 反之。如果数据要传输到架构不同的机器,则此方法将无法满足要求,但在几乎所有 R 平台之间,唯一需要的更改是字节顺序。常见的 PC(基于 ‘ix86’ 和 ‘x86_64’ 的机器)、Compaq Alpha 和 Vaxen 是 小端,而 Sun Sparc、mc680x0 系列、IBM R6000、SGI 和大多数其他机器是 大端。(网络字节顺序(如 XDR(eXternal Data Representation)中使用的)是大端。)要传输到或从其他程序传输,我们可能需要做更多操作,例如读取 16 位整数或写入单精度实数。这可以通过使用 size
参数来完成,该参数(通常)允许整数和逻辑值的大小为 1、2、4、8,以及实数的大小为 4、8,以及可能为 12 或 16。以不同大小进行传输可能会导致精度损失,并且不应尝试对包含 NA
的向量进行此操作。
字符字符串以 C 格式读取和写入,即作为以零字节结尾的字节串。函数 readChar
和 writeChar
提供了更大的灵活性。
函数 readBin
和 writeBin
会传递缺失值和特殊值,尽管如果涉及大小更改,则不应尝试这样做。
R 逻辑和整数类型的缺失值为 INT_MIN
,这是 C 头文件 limits.h 中定义的最小可表示 int
,通常对应于位模式 0x80000000
。
R 数值和复数类型特殊值的表示方式取决于机器,也可能取决于编译器。使用它们的最佳方法是将外部应用程序链接到独立的 Rmath
库,该库导出双精度常量 NA_REAL
、R_PosInf
和 R_NegInf
,并包含定义宏 ISNAN
和 R_FINITE
的头文件 Rmath.h。
如果无法做到这一点,在所有当前平台上都使用 IEC 60559(又名 IEEE 754)算术,因此可以使用标准 C 设施来测试或设置 Inf
、-Inf
和 NaN
值。在这些平台上,NA
由低字为 0x7a2
(十进制为 1954)的 NaN
值表示。
字符缺失值写为 NA
,并且没有规定将字符值识别为缺失值(因为这可以通过在读取后重新分配它们来完成)。
一些有限的功能可用于在网络连接上更低级别地交换数据。
基础 R 包含一些用于通过 BSD 套接字进行通信的工具,这些工具在支持套接字的系统上可用(包括常见的 Linux、Unix 和 Windows 上的 R 端口)。使用套接字的一个潜在问题是,这些工具通常出于安全原因或为了强制使用 Web 缓存而被阻止,因此这些函数在内联网上可能比在外部更有用。对于新项目,建议使用套接字连接。
早期的低级接口由函数 make.socket
、read.socket
、write.socket
和 close.socket
提供。
download.file
¶函数 download.file
用于通过 FTP 或 HTTP(包括 HTTPS)从 Web 资源读取文件并将其写入文件。通常可以避免这种情况,因为诸如 read.table
和 scan
之类的函数可以直接从 URL 读取,方法是显式使用 url
打开连接,或者隐式使用它,方法是将 URL 作为 file
参数提供。
R 数据导入/导出中最常见的问题似乎是“如何读取 Excel 电子表格”。本章收集了之前给出的建议和选项。请注意,大多数建议适用于 Excel 2007 之前的电子表格,而不是后来的 .xlsx 格式。
第一个建议是,如果可能,尽量避免这样做!如果您有权访问 Excel,请以制表符分隔或逗号分隔的形式从 Excel 导出您想要的数据,并使用 read.delim
或 read.csv
将其导入 R。(您可能需要在使用逗号作为小数点的区域设置中使用 read.delim2
或 read.csv2
。)导出 DIF 文件并使用 read.DIF
读取它也是另一种可能性。
如果您没有 Excel,许多其他程序能够读取此类电子表格并在 Windows 和 Unix 上以文本格式导出,例如 Gnumeric (http://www.gnumeric.org) 和 OpenOffice (https://www.openoffice.org)。您也可以在这些程序中电子表格的显示和 R 之间进行剪切和粘贴:read.table
将从 R 控制台读取,或者在 Windows 下从剪贴板读取(通过 file = "clipboard"
或 readClipboard
)。read.DIF
函数也可以从剪贴板读取。
请注意,Excel .xls 文件不仅仅是一个电子表格:此类文件可以包含多个工作表,并且工作表可以包含公式、宏等等。并非所有读取器都能读取除第一个工作表以外的其他内容,并且可能会被文件中的其他内容所混淆。
Windows 用户(使用 32 位 R)可以使用 odbcConnectExcel
包 RODBC。这可以从 Excel 电子表格文件中的任何工作表中选择行和列(至少从 Excel 97-2003 开始,具体取决于您的 ODBC 驱动程序:通过直接调用 odbcConnect
,可以读取回 Excel 3.0 的版本)。版本 odbcConnectExcel2007
将读取 Excel 2007 格式以及更早的格式(前提是安装了驱动程序,包括 64 位 Windows R:请参阅 包 RODBC)。macOS 用户也可以使用 RODBC,前提是他们有合适的驱动程序(例如,来自 Actual Technologies 的驱动程序)。
Perl
用户贡献了一个模块 OLE::SpreadSheet::ParseExcel
和一个程序 xls2csv.pl
来将 Excel 95-2003 电子表格转换为 CSV 文件。包 gdata 在其 read.xls
函数中提供了一个基本包装器。如果安装了合适的 Perl
模块,此函数也可以读取 Excel 2007 电子表格。
包 dataframes2xls 和 WriteXLS 都包含一个函数,分别使用 Python 和 Perl 将一个或多个数据框 写入 .xls 文件。
包 xlsx 可以读取和操作 Excel 2007 及更高版本的电子表格:它需要 Java。
包 XLConnect 可以使用 Java 读取、写入和操作 Excel 97-2003 和 Excel 2007/10 电子表格。
包 readxl 可以使用包含的 C 库读取 Excel 97-2003 和 Excel 2007/10 电子表格。
R. A. Becker, J. M. Chambers 和 A. R. Wilks (1988) The New S Language. A Programming Environment for Data Analysis and Graphics. Wadsworth & Brooks/Cole.
J. Bowman, S. Emberson 和 M. Darnovsky (1996) The Practical SQL Handbook. Using Structured Query Language. Addison-Wesley.
J. M. Chambers (1998) Programming with Data. A Guide to the S Language. Springer-Verlag.
P. Dubois (2000) MySQL. New Riders.
M. Henning 和 S. Vinoski (1999) Advanced CORBA Programming with C++. Addison-Wesley.
K. Kline 和 D. Kline (2001) SQL in a Nutshell. O’Reilly.
B. Momjian (2000) PostgreSQL: Introduction and Concepts. Addison-Wesley. 也可以在 https://momjian.us/main/writings/pgsql/aw_pgsql_book/ 获取。
B. D. Ripley (2001) Connections. R News, 1/1, 16–7. https://www.r-project.org.cn/doc/Rnews/Rnews_2001-1.pdf
T. M. Therneau 和 P. M. Grambsch (2000) Modeling Survival Data. Extending the Cox Model. Springer-Verlag.
E. J. Yarger, G. Reese 和 T. King (1999) MySQL & mSQL. O’Reilly.
跳转到: | .
B C D F G H I M N O P R S T U W X |
---|
跳转到: | .
B C D F G H I M N O P R S T U W X |
---|
跳转到: | A B C D E F H I L M N O P Q R S T U X Y |
---|
跳转到: | A B C D E F H I L M N O P Q R S T U X Y |
---|
区别很细微,https://en.wikipedia.org/wiki/UTF-16/UCS-2,使用代理对的情况非常少见。
即使这样,Windows 应用程序也可能需要字节顺序标记,而 R 使用的 iconv
实现可能会根据平台添加或不添加字节顺序标记。
这通常很快,因为查看第一个条目会排除大多数可能性。
以及分支,特别是 MariaDB。