搜档网
当前位置:搜档网 › R语言的数据的导入和导出

R语言的数据的导入和导出

R语言的数据的导入和导出
R语言的数据的导入和导出

R R 数据导入和导出数据导入和导出数据导入和导出

版本版本::2.2.12.2.1((2005年12月20日)

R 开发核心小组

目录 致谢

1 概述

1.1 导入

1.2 导出到文本文件 1.3 XML

2 类电子表格格式的数据

2.1 read.table 函数的各种形式 2.2 固定长度格式文件 2.3 直接使用scan 函数 2.4 整理数据 2.5 平面列联表

3 导入其他统计软件数据

3.1 EpiInfo, Minitab, S-PLUS, SAS, SPSS, Stata, Systat 3.2 Octave

4 关系数据库

4.1 为何使用数据库

4.2 关系数据库管理系统概要 4.2.1 SQL 查询 4.2.2 数据类型 4.3 R 的接口包 4.3.1 DBI 和RMySQL 包 4.3.2 RODBC 包

5 二进制文件

5.1 二进制数据格式

5.2 dBase文件(DBF)

6 连接

6.1 连接的类型

6.2 连接的输出

6.3 从连接中输入

6.3.1 Pushback

6.4 列出和操作连接

6.5 二进制连接

6.5.1 特殊值

7 网络接口

7.1 从sockets中读取数据

7.2 使用download.file函数

7.3 DCOM接口

7.4 CORBA接口

8 读取Excel表格

附录A 参考文献

(缺少索引)

致谢

手册中关系数据库内容部分基于Douglas Bates和Saikat DebRoy的早期手册。本手册的主要作者是Brian Ripley。

许多志愿者为手册中使用的软件包作出了贡献。这些涉及的软件包的主要作者是:CORBA Duncan Temple Lang

foreign Thomas Lumley, Saikat DebRoy, Douglas Bates, Duncan,Murdoch and Roger Bivand

hdf5 Marcus Daniels

ncdf David Pierce

ncvar Juerg Schmidli

RMySQL David James and Saikat DebRoy

RNetCDF Pavel Michna

RODBC Michael Lapsley and Brian Ripley

RSPerl Duncan Temple Lang

RSPython Duncan Temple Lang

SJava John Chambers and Duncan Temple Lang

XML Duncan Temple Lang

Brian Ripley 是支持连接(connection )的作者。

第一章第一章::概述 统计分析系统读入数据和输入结果报告到其他系统是让人沮丧的任务,会花费比统计分析本身更多的时间,虽然读者会发现统计分析要更加吸引人。 本手册描述了通过R 本身或者通过可来自CRAN 的软件包读写数据的机制。虽然涉及到的软件包有的还在开发中,但是他们提供了有用的功能。 除非特别说明,手册中描述的内容适用于任何平台中的R 。 一般来说,类似R 这类统计分析系统对大批量的数据不是特别合适。这个方面其他系统比R 更加合适,手册一些地方提到说与其增加R 的功能,不如让其他系统进行这项工作。(比如,Therneau 和Grambsch (2000)说他们习惯在SAS 中操作数据,然后使用S 的survival 分析。)最近一个软件包允许以Java, perl 和python 等语言直接整合R 代码来开发,利用这些语言提供的功能也许适合些。(从Omegahat 工程https://www.sodocs.net/doc/7117240413.html, 上可以得到See the SJava, RSPerl and RSPython 软件包) R 和S 类似有Unix 可重用的小工具的传统,在导入数据前和输出结果后可以使用awk 和perl 来处理。在Becker, Chambers 和Wilks (1988, Chapter 9)的书中有一个例子就是通过Unix 的工具来检验和操作输入到S 的的数据。R 自身使用perl 来操作起帮助文件,可以使用read.fwf 函数来调用perl 脚本,知道停止perl 为止。Unix 传统的工具目前有很多,包括适用于Windows 平台的。

1.1 导入 早期导入到R 的数据是简单的文本格式的文件,中小规模的数据通常是可以接受的。导入文本文件的基本函数是scan ,随后会有很多更加好用的函数将在第二章中讨论([Spreadsheet-like data], page 5)。 然而所有统计顾问都会遇到客户提交的包含权限设置的二进制数据的软盘或者CD ,比如说Excel 电子表格或者SPSS 数据文件。通常,可以导出为文本格式的文件(这样统计顾问就获得了他们电脑上最普通应用数据格式文件的备份。)但是,有时候这是不可能的,第三章([Importing from other statistical systems], page 11)讨论了通过R 直接读取这些文件的机制。读取Excel 电子表格的方法在第八章([Reading Excel spreadsheets], page 25)中做了总结。 有时候,数据压缩以后成为加速读取的二进制文件。我们有时候把图像数据通过这种方式来处理,在内存中以比特流的形式存在。这种形式的文件读取在第五章和第六章第五节([Binary files], page 18 and Section 6.5 [Binary connections], page 21)中讨论。

1.2 导出到文本文件 从R 中导出结果一般来说没什么争议,但是还是有些缺陷。通常,文本格式的文件是最方便的交换媒介。(如果需要二进制文件,参照第五章[Binary files], page 18.)

函数cat成为结果导出函数的基础。cat函数通过一个函数作为参数,附带一些其他参数使得通过正确调用cat函数得到一个文本文件。更好的是,可以多次建立连接,打开一个文件用来写入或添加,然后关闭文件。

常见的工作是以矩阵的形式把一个矩阵或者数据框写入到文件中,有时候还带上行和列的名称。这可以通过write.table和write函数来完成。函数write仅写出一个制定列数的矩阵或者向量。write.table函数更加方面,可以写出一个数据框(或者可以转化为数据库形式的对象),并带有行列标记。写出数据框到文本文件还有一些问题需要考虑。

1.精度问题

通过这些函数,大多数实数或者复数转换为完全的精度,write函数得到的精度依赖于option(digits)的当前设置。为了进一步细致的控制,可以使用format函数来一列一列的操作数据框。

2.首行问题

R默认首行为变量名称行,于是文件内容常有如下格式:

dist climb time

Greenmantle 2.5 650 16.083

…………

如果write.table函数的https://www.sodocs.net/doc/7117240413.html,s参数为NA的话,其他一些系统需要输入变量名称行。Excel中就是这样的情况。

3.分隔符

在英语国家中当逗号不出现在任何字段中的时候,文件中常见分隔符是逗号。这些文件被称为CSV(comma separated values)文件,封装好的函数write.csv提供了一些合适的默认选项来读取数据。一些情况中,逗号被用作进制符号(在write.table函数中设置参数dec = ","),这时候使用write.csv2默认参数来读取数据,使用分号作为分隔符。使用分号或者tab (sep="\t")设置是最安全的选择。

4.缺失值

默认情况下,缺失值的输出为NA,但是可以通过参数na的设置来改变。请注意,wrtie.table函数中把NaNs当作NA处理,但是cat和write函数中不是如此。

5.引号

默认情况下,字符串都有引号(包括行和列的名称)。参数quote决定了字符和因子变量的引号形式。字符串中含有引号的时候需要注意,三种有用的形式如下:

> 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

escape的第二种形式在电子表格较常用。

MASS包中的write.matrix函数提供了写出矩阵格式数据的特别接口,选择块的形式从而节省了内存消耗。

可以使用sink函数把标准的R输出写到一个文件,从而获得打印的说明。这不是通常最有效的方式,options(width)设置也许需要增加。

foreign包中的write.foreign函数通过使用write.table函数产生一个文本文件,同时也可以给出读取这些文本文件到其他统计软件包需要的代码。现在可以支持数据输出到SPSS和Stata的情况。

1.3 XML

从文本文件中读取数据的时候,用户需要知道如何定制产生文件的一些转换设置,比如说评注字符,是否需要首行(名称),值的分隔符,缺失值的表示等等,这些内容在1.2节([Export to text files], page 3)中做了说明。一种可以不仅用来保存内容,而且可以提供内容结构的标记性语言可以让文件自我说明,一次不需要提供细节就可以被软件读取数据了。

XML(可扩展性标记语言)可以提供这种结构,不仅可以提供技术的数据内容,而且可以提供负责的数据结构。XML极其流行并且成为通行标记和交换语言的标准。可以在不同场合下描述地理学的数据,比如地图,图表展示和数学内容等等。

XML包提供了读写XML文件通用的工具,在R和S-PLUS中都可以方便的使用这项技术。一些人展现了如何使用XML技术,同时也包括其他内容,去展示不同应用软件之间可以共同使用的数据集,存储R和S-PLUS的对象,使得在两个系统中都可用;通过SVG (Scalable Vector Graphics, XML的同义词)展示作图,表达函数文件;生成包括文本、数据和代码的动态分析报告。

XML包的功能超出了本手册的范围,可以在https://www.sodocs.net/doc/7117240413.html,/RSXML这个网页得到XML包的详细资料和例子。CRAN中的StatDataML包就是基于XML的一个例子。

第二章类电子表格数据

在1.2章节中([Export to text files], page 3),我们看到电子表格形式的文本文件的几种情况,其中的数据是矩阵形式的,有的还有行和列的名称。本章节将要讨论读取这种格式的数据到R中。

2.1 read.table函数的几种形式

read.table函数是读取矩阵形式数据的最好方法。其他一些函数是调用了read.table函数加上了一些默认参数。需要注意的是,read.table函数读取大数值矩阵是缺乏效率的,参见下面提到的scan函数。

下面是一些需要注意的方面:

1、编码:如果文件中含有非ASCII编码的字段,必须保证以正确的编码形式读入。这主要出现在UTF-8的情况下读取Latin-1文件格式,可以通过如下方式实现read.table(file("file.dat", encoding="latin1"))。这种方法可以在Latin-1名字的任何情况下成功。

2、首行:我们推荐显式的指定首行参数,依照惯例,首行表示列名称而非行名称,于是出现了比其他行少一个字段的情况。(在R中,设置参数header = TRUE)。如果文件中有

首个字段作为行名称,可以通过如下方式实现read.table("file.dat", header = TRUE, https://www.sodocs.net/doc/7117240413.html,s = 1)。列名称可以显式的通过https://www.sodocs.net/doc/7117240413.html,s参数实现,显式的名称将不考虑首行。

3、分隔符:一般来说,可以看到文件内容就知道字段之间的分隔符,但是字段间有空格的时候,可能是缺失的参数sep = "",可以代表任意间隔(空格、制表符或者回车)作为分隔符。请注意,选择的分隔符会影响到带有引号的字符串。如果在制表符分隔符的文件中包含空字段,请使用sep = "\t"作为参数。

4、引号:默认情况下,字符串使用单引号或者双引号,这时候所有字符中的引号都作为一部分来匹配。引号的有效设置通过quote参数来控制。sep ="\n"默认的改变quote = ""。如果没有指定分隔符,没有被引字符串前面使用c语言形式的‘\’。如果指定了分隔符,被引用字符串中的引号在电子表格文件中连续两次出现当作通常的一个字符。比如,read.table("testfile", sep = ",")方式可以读取’One string isn’’t two’,"one more" ,而不会对缺省的分隔符产生作用。

5、缺失值:默认情况下,包含NA的字符代表缺失值,不过可以通过na.strings参数来改变设置,na.strings是包含一个和几个表示缺失值的字符。数值列中空值也被视作缺失值。在数值列中,NaN、Inf和-Inf是合法的。

6、尾行:通常从电子文档格式文件中导入的数据的时候,用参数fill=TRUE省略尾部空字段。

7、字符型字段中的空格:如果指定了分隔符,字符型字段中前后空格作为字段的部分存在,若想去掉这些空格,使用参数strip.white=TRUE.

8、空白行:缺失情况下,read.table函数略过空白行。可以通过参数blank.lines.skip=FALSE 来改变设置,这是需要配套使用参数fill=TRUE。

9、变量的类:除非你有特别的指定,read.table函数为数据框中的每一个变量自动选择一个合适的类。遵照如下的顺序:logical, integer, numeric and complex,略过无法转化的部分。如果以上所有都失败了,变量转化为因子(factor)。参数colClasses和as.is提供了更强的控制,as.is禁止字符型向量转化为因子。使用colClasses参数可以在输入数据的时候为各列指定类。需要注意的是,colClasses和as.is参数用来指定各列,不是针对每个变量,于是包含了行名的那一列(如果这列存在的话)。

10、注解:缺省情况下,read.table函数使用‘#’作为注释字符,如果被读入了,该行剩下的部分将被省略掉(除了使用引号的以保外)。空白行和注释行被视为空行。如果已知数据文件中没有注视,那么可以设置comment.char="",也许速度会更快。

11、Escapes:很多操作系统中,在文本文件中使用反斜杠作为escape字符,但是Windows 操作系统中不是如此(而是使用反斜杠作为文件路径名的一部分)。在R中是否使用这样的惯例风格是可选的。在read.table和scan两个函数中,有一个allowEscapes的参数。从R2.2.0开始,缺省设置为false,反斜杠被解释为excape符号(在上述情况下)。如果设置为true,就解释为C语言风格的escape字符,称为控制字符,可以表示类似\a, \b, \f, \n, \r, \t, \v以及八进制、十六进制\040 和\0x2A的情况。

通用函数read.csv和read.delim给read.table函数提供了恰当的参数,用来读取英语情况下的CSV和制表符分割文件。而read.csv2和read.delim2函数提供了使用逗号作为小数点分割情况下读取类似文件的功能。

如果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为一个原子型向量(logical, integer, numeric, complex, character 或者raw),设置nrows——读取的行数——做一个恰当的估计要比不做任何设置好,这些都有利于提高数据读取效率。可以看下面的例子。

2.2 固定宽度格式的文件

有时候数据文件中的字段没有分隔符,但是字段实现制定了列的情况。这在打卡的时代是常见的事情,现在有时候也用来节省文件的空间。

通过指定一个包含字符宽度的向量,read.fwf函数提供读取这种文件的简单途径。这个函数把整个文件作为整行读入内存,拆分字符,写出到一个临时的制表符分割的文件,然后调用read.table函数。对小文件而言这是尚可的办法,但是对任何复杂的情况,我们推荐使用perl等语言预处理一下文件转化格式。

read.fortran函数是另外一个读取固定格式文件的函数,使用了Fortran风格的列确定方法。

2.3 直接使用scan函数

read.table和read.fwf两个函数都通过scan函数来读取文件,然后处理scan函数得到的结果。这非常方便,不过有时候直接使用scan函数要好些。

函数scan有太多的参数,很多参数已经通过read.table函数介绍过了。最主要的参数是what,它用来制定读取文件中变量的类型的列表。如果这个列表命名了,这些命名就会作用到返回列表的组成部分。类型可以是数值(numeric),字符(character)或者复数(complex)等,通常可以通过例子来指定,比如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函数可能更方便。

scan函数一个通常的用法是读取大的矩阵。假如文件matrix.dat恰好包含200×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函数使用有效设置后(特别的,指定colClasses)需要18秒钟,原始不设置情况下需要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下的两倍),以及和垃圾回收的情况有关。

2.4 改变数据形状

有时候,电子表格数据是紧凑型的。每个对象跟着全部的观测值。在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

有两个covariate,四次测量。数据从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

X1P2364645190V1

X2CC2617435535V1

X3CC2772325691V1

X4CC2719330949V1

X5CC2437050542V1

X6CC2835958591V1

X7CC2513645801V1

X11P2364650333V2

……

而函数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函数可以完成相反任务。

2.5 平列联表

以数组的形式展示高维的列联表是相当的有难度。在定类数据分析中,这种信息通常通过包含有边的带有行列组合的因子水平对应的格子计数的二维数组来实现。这些行列典型的是“粗糙”的,只有当它们改变的时候,标签才显示出来,以明显通用的行从顶端到底端列从左端到右端的方式。在R中,这种平列联表可以通过ftable函数来实现,该函数生成一个ftable类,带有相应的打印方法。

以R标准数据的UCBAdmissions作为一个简单的例子,其包含一个三维的列联表,是

通过1973年研究生申请UC Berkeley6个最大的院系的人员依照录入和性别分类的情况: data(UCBAdmissions) ftable(UCBAdmissions)

Dept

A

B

C

D

E

F

Admit Gender

Male 512 353 120 138 53 22 Admitted Female 89 17 202 131 94 24 Male 313 207 205 279 138 351 Rejected

Female

19

8

391

244

299

317

这种打印形式明显比三维数组形式的要有用。 有一个read.ftable 函数用来读取这种平列联表形式的文件。额外的参数是用来精确处理行列变量名称和测量水平的。在read.ftable 函数的帮助中有一些有用的例子。平列联表可以从数组形式通过as.table 函数转化维标准列联表。 请注意平列联表通过其“粗糙”的行列标签来定制。如果行的所有测量水平均被给定,可以使用read.table 函数来读取数据,通过xtabs 函数来生成一个列联表。

第三章第三章:: 从其他统计软件中导入 本章中,我们将讨论从其他统计软件系统中读取二进制数据文件。通常最好可以避免这种情况,然而如果原有的系统不存在,这种情况就无法避免了。

3.1 EpiInfo 、Minitab 、S-PLUS 、SAS 、SPSS 、Stata 、Systat 自带的foreign 包(术语推荐包系列)提供了其他统计软件系统数据导入的工具,以及导出数据到Stata 等。有时候,这些函数需要的内存比read.table 函数少一些。write.foreign 函数(参见1.2节【导出到文本文件】,第三页)目前提供了支持导出到SPSS 和Stata 的机制。 EpiInfo 第五和第六版存储数据到一个自描述的固定宽度文本文件中。read.epiinof 函数可以读取'REC'格式的函数到R 的data.frame 类型的对象中。EpiData 也生成这样的数据文件。 函数read.mtp 导入“Minitab Portable Worksheet ”文件,返回一个工作表组成的R 列表。 函数read.xport 导入SAS 的可交换格式文件,返回一个包含数据框的列表。如果SAS 安装在电脑中,read.ssd 函数可以生成和读取SAS 脚本,该脚本中包含了以可交换格式存储的SAS 永久数据集。它通过read.xport 来读取文件。包HMisc 有一个类似的函数sas.get 。 函数read.S 可以读取S-PLUS3.x 、

4.x 和2000版本在UNIX 和Windows 系统中的二进制对象(可以在不同的操作系统中读取他们)。可以读取大部分但不是所有的S 对象:可以读取向量、矩阵、数据框和包含这些内容的列表。 函数data.restore 读取S-PLUS 的转移数据(由函数data.dump 生成),并且保存了相同

的限制(除了从Aplpha平台)。其还可以读取S-PLUS5.x和6.x版本的转移数据,这些数据通过data.dump(oldStyle=T)写出。

如果以及连接到S-PLUS,转移S-PLUS中的对象和在R中提供转移文件是可靠的。S-PLUS5.x和6.x版本中需要使用dump(……,oldStyle=T),读取非常大的对象时,最好使用批处理脚本的转移文件,而不要使用source函数。

函数read.spss读取SPSS中保存和导出的文件,返回由保存数据集中每个变量组成的一个列表。SPSS变量带有值标签的可以选择转化维R中的因子。

SPSS Data Entry时生成数据输入格式的工具。缺省情况下,生成的有额外格式信息的数据文件无法被read.spss函数来操作,但是其可以输出数据成为普通的SPSS格式。

Stata中“.dta”格式文件时二进制格式的文件。从5,6,7/SE和8版本的Stata的得到的文件可以通过函数read.dta和write.dta函数来读写。Stata中的有值标签的变量可以转化维R中的因子。

函数read.systat读取在lSystat中SA VE格式的长方形数据文件(mtype=1)。这些文件以.sys或者.syd(最近的用法)作为扩展名。

3.2 Octave

Octave是线性代数数值运算系统,foreign包中的read.octave函数可以读取Octave中ASCII数据文件的第一个向量或者矩阵,这些数据文件是Octave的save -ascii命令生成的。

第四章:关系型数据库

4.1 为什么使用数据库

R操作的数据类别是有限制的,因为R中所有数据都是存留在内存中的,在执行一个函数的过程中数据可能被生成好几份,R不适应操作大数据集。超过百兆的数据对象会导致R耗尽内存资源。1

R自身目前不容易支持数据获取。因为如果多个用户获取数据的时候,存在更新同一个数据,这样一个用户的操作对另外的用户就是不可见的了。

R支持永久性数据,这样你可以把一个数据对象和一个任务的整个工作表保存,并用于随后的任务中,然而存储的数据是针对R的,不太容易被其他系统操作。

数据库管理系统(DBMSs),尤其是关系型数据库管理系统2(RDBMSs)用来完成一下这些工作,其功能有如下方面:

1、提供读取大数据集中快速选取部分数据的功能

2、数据库中强大功能的汇总和交叉列表的功能

3、以比长方形格子模型的电子表格3和R数据库更加严格的方式保存数据

4、多用户并发存取数据,同时确保存取数据的安全约束

5、作为一个服务器维大范围的用户提供服务

这样,DBMS可能使用统计工具提取10%的样本数据,生成交叉列表4从而得到一个多维

的列联表,从一个数据库中可以依照分组提取数据组进行独立的分析等等。

4.2 关系型数据库管理系统简介

传统上,有大型(并且昂贵)的商业化的关系型数据库管理系统(Informix; Oracle; Sybase; IBM's DB/2; Microsoft SQL Server on Windows)和学术的、小型系统的数据库系统(比如MySQL, PostgreSQL, Microsoft Access等),前一类型极其强调数据的安全性。现在随着开源的PostgreSQL有了越来越高端的特点,以及“自由”版本的Informix,Oracle和Sybase 在Linux上使用,这种界线正在变得模糊。

同时还有其他常用的数据源类型,包括电子表格,非关系型数据库,乃至文本格式文件(可能是压缩的)。开放数据库接口(ODBC)是使用这些数据源的标准。其源于Windows (参考https://www.sodocs.net/doc/7117240413.html,/data/odbc/),也可以在Linux/Unix上实现。

本章随后提及的包都提供了客户服务器数据库形式的服务。数据库可以驻留在本机也可以是远程(通常如此)设备上。有一个称为SQL(结构化查询语言,读为“sequel”参见Bowman等,1996和Kline and Kline,2001)接口语言的ISO标准(事实上有几个:SQL92是ISO/IEC 9075, 也称为ANSI X3.135-1992, 同时SQL99即将出台),数据库管理系统均不同程度的支持这个标准5。

4.2.1 SQL查询

R中诸多接口为通常的操作生成SQL,然而直接使用SQL需要复杂的操作。同城SQL 使用大写字母拼写,但是很多用户发现在R接口函数中使用小写是方便的。

关系型数据库管理系统以数据库中的数据表(或者关系)作为存储数据的方式,其非常类R中的数据框,它们都是由相同类型的列或者叫字段的组成(数值、字符、日期、货币等等),行或者叫记录的包含整条的观测值。

SQL查询在关系型数据库中是相当普遍的操作。下面是一些典型的SELECT6查询语句:

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对结果进行排序。和数据框不同,关系型数据库中的各行

最好认为是没有顺序的,没有ORDER BY子句的时候,顺序是不确定的。可以对用逗号分割的多行进行排序(以字典顺序)。通过设置DESC在ORDER BY字段的后面可以反向排序。

SELECT DISTINCT查询仅返相应数据表中回各各不同的行。

GROUP BY子句通过准则来选择各组的行。如果指定了多列,则多维交叉分类被5个汇总函数进行汇总计算。HA VING子句允许通过汇总计算得到的值来选择包含或者不好某些行。

如果SELECT中包含了ORDER BY子句会产生唯一的顺序,增加一个LIMIT子句可以选取(通过数值)连续一块数据的列。这对一次取回一个数据行块是有用的(当LIMIT子句用来优化查询的时候,除非顺序是唯一的,否则是不可靠的)。

Kline和Kline (2001)讨论了SQL在SQL Server 2000 、Oracle、MySQL和PostgreSQL 中实现的具体细节。

数据库中的数据可以保存为多种数据类型。数据类型是数据库管理系统指定的,不过SQL标准定义了许多类型,下列是广泛地被实现了的(通常不是通过SQL名称):

float(p) 实数,可选精度,通常称为实数或者双精度数

integer 32位整数,通常称为整数

smallint 16位整数

character(n) 定长字符串,通常称为字符

character varying(n) 变长字符串,通常称为变长字符,有255字符的限制

Boolean true或false,通常称为bool或者bit

date 日历时间

time 当日时间

timestamp 日期时间

和时区有关,有多种时间,以及多种日期时间。文本和bolb(表示大块文本和二进制数据)也被广泛的实现了。R接口包广泛地的为用户实现隐藏了数据类型转换的情况。

4.3 R接口包

在CRAN上有几个包可以让R和DBMSs进行通信。它们提供了不同层次的抽象。有一些提供了将整个数据框读入写出到数据库中。所有这些包中都有通过SQL查询语言的函数选取数据,读取结果分片(通常是不同组的行)或者整体作为数据框7。

除了RODBC以外,其他所有的包都和一种DBMS相关,然而所有的操作都使用DBI 包(https://www.sodocs.net/doc/7117240413.html,/db)作为统一的前端工具和各种作为终端工具的结合起来,其中开发最好的是RMySQL包。在CRAN中终端的包还有ROracle和RSQLite(和内置的数据库管理系统SQLite结合工作, https://www.sodocs.net/doc/7117240413.html,/sw/sqlite)

较早的RmSQL和RPgSQL两个包当前在CRAN的开发领域已经终止了支持:BioConductor项目有一个RdbiPgSQL.PL.R (https://www.sodocs.net/doc/7117240413.html,/plr/),是一个把R嵌入到PostgreSQL的项目。

CRAN上的RMySQL包提供了和MySQL数据库系统的接口(参见https://www.sodocs.net/doc/7117240413.html, and Dubois, 2000.)。这里的表示适合0.5-0版:早期的版本会有本质上的差异。当前版本需要DBI包,这里的描述只需要做很小的改变就可以适用于其他包使用DBI的终端。

从3.23.x版本以来,在GPL下,MySQL存在于Unix/Linux和Windows。MySQL是一个轻量级的数据库系统(其默认操作系统的系统文件是大小写敏感的,不同于Windows的情况)。RMySQL包在Linux和Windows下均可使用。

dbDriver("MySQL")调用返回一个数据库连接管理对象,接着调用dbConnect函数打开数据库连接,随后可以使用泛型函数dbDisconnect来关闭数据库连接。相应的可以在ROracle 或RSQLite中使用dbDriver("Oracle")或dbDriver("SQLite")

SQL查询的发送可以通过dbSendQuery或dbGetQuery函数来实现。dbGetQuery函数发送查询并取回结果保存为一个数据框。dbSendQuery函数则发送查询避过那发挥一个从DBIResult 类继承而来的对象中,这个对象可以取回结果,随后可以使用dbClearResult函数删除结果。函数fetch用来取回查询中部分或者全部的行,生成一个列表。函数dbHasCompleted标识是否所有的行都被取回了,dbGetRowCount函数返回结果中的行数。

在读出、写入和删除数据库中的表方面,都有方便的接口。dbReadTable和dbWriteTable函数从一个R的数据框中读写数据表,并把数据框的行名变为MySQL数据表中的row_names 字段。

> library(RMySQL) # 加载DBI包

## 打开一个和MySQL的连接

> con <-dbConnect(dbDriver("MySQL"), dbname = "test")

## 列出数据库中的数据表

> dbListTables(con)

## 载入一个数据框到数据库中,删除已有同名的数据表

> data(USArrests)

> dbWriteTable(con, "arrests", USArrests, overwrite = TRUE)

TRUE

> dbListTables(con)

[1] "arrests"

## 读取整个数据表

> 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

...

## 选择加载过的数据表

> 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包给支持ODBC8的数据库管理系统提供了接口。它可以广泛存在,并允许相同的R代码和不同的数据库管理系统连通。RODBC在Unix/Linux和Windows均可运行,并且几乎所有的数据库管理系统都支持ODBC。我们已经测试了Windows上的Microsoft SQL Server, Access, MySQL 和PostgreSQL,以及Linux上的MySQL, Oracle, PostgreSQL and SQLite等。

ODBC是一个客户服务器系统,可以顺利的在Windows客户机上连接运行在Unix上的数据库管理系统,反之同样可以。

在Windows上,通常都有对ODBC的支持,当前的版本可以从https://www.sodocs.net/doc/7117240413.html,/data/odbc/上获取,作为MDAC的组成部分。在Unix/Linux上,你也许需要一个ODBC驱动管理器,比如unixODBC (https://www.sodocs.net/doc/7117240413.html,)或者iOBDC (https://www.sodocs.net/doc/7117240413.html,) 以及一个数据库管理系统的驱动程序。

在Windows下不仅提供了对数据库管理系统的支持,而且提供了对Excel(‘.xls’)数据表、Dbase('.dbf')文件,甚至文本文件的支持(这些应用都不再用安装了)。

并发的连接是可能的。通过odbcConnect或者odbcDriverConnect函数调用(Windows界面下,允许通过对话框操作)打开一个数据库连接,返回一个随后对数据库进行操作的句柄。打印一个数据库连接可以提供ODBC连接的一些细节,odbcGetInfo函数可以提供客户机和服务器的细节。

通过调用close或者odbcClose函数可以关闭一个数据库连接,也可以在一个R流程结束时又没有R的对象引用其时自动的关闭(会给出一个警告)。

一个数据库连接中各个表格的细节可以通过sqlTables函数得到。

函数sqlSave把一个R的数据框写入到数据库的一个表中,sqlFetch函数把数据库中的一个表写到R中的一个数据框。

一个SQL查询可以通过sqlQuery函数发送到数据库中。这样返回结果到一个R的数据框中。(sqlCopy发送一个查询到数据库中,并且将结果保存为数据库中的一个数据表。)

下面时一个使用PostgreSQL的例子,ODBC把列和数据框名字转化为小写。我们将使用预先建好的数据框testdb,在unixODBC环境下把DSN(数据源名称)保留在'~/.odbc.ini'文件中。相同的代码可以使用MyODBC在Linux或者Windows(这时候MySQL也把名字转化为小写)下针对MySQL使用。在Windows操作环境下,DSN在“控制面板”中操作(2000/xp 版本中,“ODBC数据源”在管理工具选项中)。

> library(RODBC)

## 把命名改为小写

> channel <-odbcConnect("testdb", uid="ripley", case="tolower")

## 把一个数据框写入到数据库中

> data(USArrests)

> sqlSave(channel, USArrests, rownames = "state", addPK = TRUE)

> rm(USArrests)

## 给出数据库中的数据表

> sqlTables(channel)

TABLE_QUALIFIER TABLE_OWNER TABLE_NAME TABLE_TYPE REMARKS

1 usarrests TABLE

## 展示数据库中数据表的内容

> sqlFetch(channel, "USArrests", rownames = "state")

murder assault urbanpop rape

Alabama 13.2 236 58 21.2

Alaska 10.0 263 48 44.5

...

## 一个SQL查询

> 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

## 移除数据库中的数据表

> sqlDrop(channel, "USArrests")

## 关闭连接

> odbcClose(channel)

下面是一个Windows下通过ODBC使用Excel电子表格的例子,我们可以通过如下方式读取电子表格:

> library(RODBC)

> channel <-odbcConnectExcel("bdr.xls")

## 给出电子表格

> 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

## 读取sheet1的内容

> sh1 <-sqlFetch(channel, "Sheet1")

> sh1 <-sqlQuery(channel, "select * from [Sheet1$]")

请注意sqlTables 和sqlFetch 函数数据表的不同之处,sqlFetch 可以给出差异。 ODBC 和Excel 的接口是只读的,你不能改变电子表格中的数据。

第五章第五章:: 二进制文件 二进制连接(第六章,连接,19页)是较好的二进制文件处理方式。

5.1 二进制数据格式 CRAN 上的hdf5、RNetCDF 和ncdf 包提供了和NASA 的HDF5格式文件(Hierarchical Data Format, 参见https://www.sodocs.net/doc/7117240413.html,/HDF5/)的接口,以及和UCAR 的netCDF 数据文件(network Common Data Form, 参见 https://www.sodocs.net/doc/7117240413.html,/packages/netcdf/)的接口。 上述两种文件格式都是用来存储数组方式组织的科学技术数据的文件系统,其中包括描述、标签、格式、单位等。HDF5还提供了各组数组,R 接口使得列表和HDF5的分组数据对应起来,可以读写数值和字符型的向量和矩阵。 CRAN 上的ncvar 包通过使用RNetCDF 的功能提供了高层次的和netCDF 的接口。 还有来自于https://www.sodocs.net/doc/7117240413.html, 上的rhdf5包。

5.2 dBase files (DBF) Ashton-Tate 发明的dBase 是DOS 下的程序,后来为Borland 公司拥有,它带有".dbf"扩展名,作为一种二进制“平”文件格式变得相当流行。它已经被'Xbase'系列的数据库系统使用了,包括dBase 、Clipper 、FoxPro 和他们相应的Windows 版本Visual dBase 、Visual Objects 和Visual FoxPro (参见 http://www.e-bachmann.dk/docs/xbase.htm)。一个dBase 文件中包含一个头,随后是一系列的字段,非常类似于R 的数据框。数据本身以文本格式存储,可以包含字符、逻辑和数值型字段,后续的版本中还有其他类型(参见 http://clicketyclick.dk/docs/data_types.html)。 在所有的平台中,R 都提供了read.dbf 和write.dbf 函数读写基础DBF 文件。在Windows 环境下,可以使用RODBC 包中的odbcConnectDbase 函数,它提供了通过Microsoft's dBase ODBC 驱动程序读取DBF 文件的全面功能(Visual FoxPro 驱动也可以通过odbcDriverConnect 函数实现)。

第六章第六章:: 连接 R 中提供的连接依照了Chambers 在1998年提出的意见,这个系列的函数通过使用灵活的接口连接到类似文件的对象而不是使用文件名。

6.1 连接类型

最常见的连接类型是一个文件连接,R中文件连接使用file函数生成。文件连接(如果操作系统允许的话)可以打开一个文件以便于以文本或二进制的格式读、写或者增加文件。事实上,打开的文件既可以读也可以写,R为读写保存一个独立的文件位置。

请注意,在缺省情况下当一个连接生成时它还没有被打开。规则就是说如果连接没有打开,一个函数使用它之前必须要打开它(必须的),如果打开连接后,使用以后关闭连接。简而言之,保持你发现的连接的状态。通用函数open和close将显式的打开和关闭连接。通过函数gzip提供的算法压缩后的文件可以作为由函数gzfile产生的连接来使用,同时通过函数bizp2压缩的文件可以通过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是一种连接到其他过程的特殊文件形式,pipe连接使用函数pipe来生成。打开一个供写入的pipe连接(或者是追加内容到pipe)运行操作系统命令,连接其标准输入到R,随后将内容写入到连接。逆过程是打开一个输入的pipe连接,运行操作系统命令,从连接中获得R中已有的标准输出。

“http://”、”ftp://”、”file://”等URL类型可以使用函数url读取。为了方便起见,在调用url函数时,可以将文件作为file参数来指定。

在大多数支持socket的Unix、Linux和Windows操作系统中,Socket可以通过函数socketConnection来作为连接使用。Socket可以读写,客户端和服务端socket都可以使用。

6.2 输出到连接

我们已经说明了cat、write、write.table和sink作为文件写入的函数,可以通过设置参数append=TRUE在文件后追加内容,而且这是1.2.0版本以前的优先做法。现在的情形类似,当file参数是字符串,文件连接是打开的(供写入或者追加内容),在调用函数后再关闭。如果我们想反复的写出内容到同一个文件,显式的声明并打开一个连接,把连接对象作为输出函数的参数调用会更加有效率。这些也可以用来写入到pipe中,早期通过file="|cmd”来实现这些功能(现在也在使用)。

函数writeLines把完整的文本行写出到一个连接中。下面是一些简单的例子:

zz <-file("ex.data", "w") # 打开一个输出文件连接

cat("TITLE extra line", "2 3 5 7", "", "11 13 17",

file = zz, sep = "\n")

cat("One more line\n", file = zz)

close(zz)

## Unix环境下,使用pipe在输出中把数字间隔符号转化为逗号

## R字符串和shell中需要双反斜杠

zz <-pipe(paste("sed s/\\\\./,/ >", "outfile"), "w")

cat(format(round(rnorm(100), 4)), sep = "\n", file = zz)

close(zz)

## 现在看输出文件:

file.show("outfile", delete.file = TRUE)

## 使用lm函数帮助中的例子,获取R输出

zz <-textConnection("ex.lm.out", "w")

sink(zz)

example(lm, prompt.echo = "> ")

sink()

close(zz)

## 现在'ex.lm.out' 中包含了供进一步处理的输出内容

## 如下方式,查看其中内容

cat(ex.lm.out, sep = "\n")

6.3 从连接中输入

从连接中读取内容的基本函数是scan和readLines。将一个字符串作为参数,打开一个文件连接作为函数的持久调用,显式的打开一个文件连接可以以不同的格式连续的读取内容。

调用了scan函数的其他函数也可以使用连接,特别的是read.table函数,下面的一些简单的例子:

## 读取上个例子中生成的文件

readLines("ex.data")

unlink("ex.data")

## 读取当前目录下的文件列表(Unix环境下)

readLines(pipe("ls -1"))

# 假设一个“data”文件中包含如下内容

450, 390, 467, 654, 30, 542, 334, 432, 421,

357, 497, 493, 550, 549, 467, 575, 578, 342,

446, 547, 534, 495, 979, 479

# 读取如上内容

scan(pipe("sed -e s/,$// data"), sep=",")

为了方便性,如果file参数指定了一个FTP或者HTTP URL,URL通过url函数来读取。通过file://foo.bar指定文件也是可以的。

6.3.1 Pushback

C程序员可能比较熟悉ungetc函数,用来在文本输入中对一个字符进行压栈。R连接已一种更强大的方法实现相同的想法,函数pushBack可以把任意数量的文本行压栈到一个连接上。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)

压栈仅供文本模式输入下的连接使用。

6.4 列出和操作连接

用户当前打开的所有连接可以通过showConnections函数列出,使用参数all=TRUE可以把已经关闭或者中止的连接展示出来。

泛型函数seek可以用来读取数据,以及在一些连接中重置读写的当前点。不幸的是,该函数依赖于操作系统的功能,这些可能是不可信的(比如Windows下的文本文件)。函数isSeekabel函数通过输入参数连接对象可以报告连接的位置能否改变。

函数truncate可以在当前位置截断一个已打开的供写入的文件。

6.5 二进制连接

函数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是一个连接,在调用过程中需要的时候打开,如果是使用一个字符串,那么就默认为是指定一个文件名。

写入的情况是类似的。对象可以是原子型的向量对象,是没有定义属性的数值型、整数型、逻辑型、字符型、复数型或者raw型向量。默认情况下,像在内存中那样,作为一个精确的比特流写出到文件,

函数readBin从文件中读取比特流,通过what设置其模式,作为一个向量读取。设置

相关主题