R语言是面向对象的。面向对象的理论一两句话说不清楚(我不清楚),但对于数据至少应该了解三个:
1、R能处理的东西(包括数据)都称为object。这个英文单词的意思原本很清楚,就是物体、物件的意思,但被计算机专家们翻译成“对象”以后就很玄乎了。
2、
物(object)以类聚。一个object都应该能找到它所归属的某个类(class)。“类”是抽象的概念,一个类至少有一个特征是这类数据所共有
的。根据应用需求、目的等不同可以定义不同的类。比如做生物信息的可以定义出DNA类、RNA类,为了高效处理这类数据,定义这些类是非常必要的。所以R
里面有很多的“类”。
3、类可以继承产生儿孙类。
我们不可能也没必要去了解所有的“类”,但R语言定义的一些基本数据类得了解,而且得较详细地了解。这包括向量、因子、矩阵、列表、数据框和一些特殊值数据。
一、向量(vector)
我们通常接触的数据主要是数字、字符和逻辑(真和假,是或不是)类型的。数据有一个个的,也有一串串一批批的。在R里面,最基本的数据类是向量,即一串有序数据;但vector是虚拟类,没有父类型,它包含了在其他语言里面常说的基本数据类型如整型、字符型和逻辑型等:
>getClass("vector")
VirtualClass"vector"[package"methods"]
NoSlots,prototype ofclass"logical"
KnownSubclasses:#已知子类
Class"logical",directly
Class"numeric",directly
Class"character",directly
Class"complex",directly
Class"integer",directly
Class"raw",directly
Class"expression",directly
Class"list",directly
Class"structure",directly,withexplicitcoerce
Class"array",byclass"structure",distance2,withexplicitcoerce
Class"matrix",byclass"array",distance3,withexplicitcoerce
Class"signature",byclass"character",distance2
Class"className",byclass"character",distance2
Class"ObjectsWithPackage",byclass"character",distance2
Class"mts",byclass"matrix",distance4,withexplicitcoerce
Class"ordered",byclass"factor",distance3
Class"namedList",byclass"list",distance2
Class"listOfMethods",byclass"namedList",distance3
R语言处理数据的最基本单位是向量,而不是原子数据。所以向量又称为原子向量(atomic
vector),R语言的数据单位里面它最小(也最大,没有谁是它的父母)。但由于vector是虚拟类,不管用什么方式你都不可能获得类型名称叫“vector”的对象,只能获得它的直接子类的对象。下面的x是一个矩阵,虽然我们用as.vector函数进行转换,但获得对象的类名称是integer而不是vector:
>x
>class(x)
[1]"matrix"
>class(as.vector(x))
[1]"integer"
一个向量可以是一串数字(n个数字,向量长度为n),也可以是1个数字(向量长度为1):
>x=1:40
>x
[1]123456789101112131415161718192021222324
[25]25262728293031323334353637383940
>x=1
>x
[1]1
等于号可以用于向量赋值,但符号“
>x
>x
[1]123
>y
>y
[1]"赵匡胤""钱学森""孙思邈"
c( )
是R的一个函数,表示将括号里面的内容连接起来成为一个向量。R提供了一些产生特殊向量的函数,如seq( )和rep( ),具体用法直接在R里面先输
入问号(?)和函数名去查询。vector是虚拟类,本身不指定数据的存储类型,但赋值以后就马上会有数字型(numeric)、字符型
(character)、逻辑型(logical)等实际类别,比如上面的变量x和y,用class( )函数获得的类型分别是数值型和字符型:
>class(x)
[1]"numeric"
>class(y)
[1]"character"
一个向量只属于一种类型,如果改变了一个元素的值可能会改变该向量的类型:
>x
>x
[1]12345678910
>class(x)
[1]"integer"
>x[2]
>x
[1]"1""Adam""3""4""5""6""7""8""9""10"
>class(x)
[1]"character"
向量元素的引用/提取用下标法如 x[2],R语言的下标从1开始编号(而不是0)。
二、因子(factor)
R定义了一类非常特殊的数据类型:因子。比如我们的实验获得了10个数据,前5个数据来自对照样品CK,其余属于处理样品TR,R语言中可以用下面方法标识这10个数据的样品属性:
>sample
>sample
>sample
[1]CK CK CK CK CK TR TR TR TR TR
Levels:CK TR
因子的种类称为水平(level)。上面的样品sample因子有两个水平:CK和TR。因子类数据很特殊:
>getClass("factor")
Class"factor"[package"methods"]
Slots:
Name:.Datalevels.S3Class
Class:integer character character
Extends:
Class"integer",fromdata part
Class"oldClass",directly
Class"numeric",byclass"integer",distance2
Class"vector",byclass"integer",distance2
KnownSubclasses:"ordered"
使用因子类数据是因为R是针对统计应用的语言。使用因子以后,数据的统计会完全不同。比如上面的两个样品10个测定数值如果是:
>value
>value
[1]1.44368380-1.994178980.602790370.751866101.08372729-0.16189030
[7]-0.056178011.03601538-0.87932814-0.32429184
求样品的平均值就可以这么做:
>tapply(value,sample,mean)
CK TR
0.37757771-0.07713458
gl( )函数也可以方便地产生因子:
>sample
>sample
[1]CK CK CK CK CK TR TR TR TR TR
Levels:CK TR
三、矩阵(matrix)
矩阵的继承关系比较复杂,它和数组(array)的关系既是父亲又是儿子,还是孙子:
>getClass("matrix")
Class"matrix"[package"methods"]
NoSlots,prototype ofclass"matrix"
Extends:
Class"array",directly
Class"structure",byclass"array",distance2
Class"vector",byclass"array",distance3,withexplicitcoerce
KnownSubclasses:
Class"array",directly,withexplicittestandcoerce
Class"mts",directly
如果你愿意,也可以把矩阵称为数组,但事实上它们是不同的类。生物类数据以二维数组/矩阵居多。
向量数据可以转成矩阵,下面代码将10个元素的x转成2行5列的矩阵:
>x
>dim(x)
>x
[,1][,2][,3][,4][,5]
[1,]13579
[2,]246810
>dim(x)
[1]25
dim( )是一个函数,它获取或设置数据的维度。注意x数据的行列排列顺序:先列后行。但是矩阵内数据的下标读取方式是先行后列。x[2, 1]是第2行第1列的值,x[2, ]表示第2行的所有数据,x[ ,2]表示第2列的所有数据。
>x[2,1]
[1]2
>x[2,]
[1]246810
>x[,2]
[1]34
把1个向量转成矩阵还可以使用matrix( )函数,参数nrow设置行数,ncol设置列数:
>matrix(1:10,nrow=2)
[,1][,2][,3][,4][,5]
[1,]13579
[2,]246810
几个长度相同的向量也可以合并到一个矩阵,cbind( )函数将每个向量当成一列(按列)合并,rbind( )按行合并:
>x
>y
>z
>cbind(x,y,z)
x y z
[1,]341
[2,]452
[3,]563
[4,]674
>rbind(x,y,z)
[,1][,2][,3][,4]
x3456
y4567
z1234
不同向量的数据类型要相同,否则转换成矩阵后数据类型会变样。下面代码将height内的数字全都转成了字符类型,这可能不是你想要的结果:
>name
>height
>info
>info
[,1][,2][,3]
name"赵匡胤""钱学森""孙思邈"
height"172""175""168"
>class(info)
[1]"matrix"
身高是数值,但跟姓名混合组成矩阵后就变成字符型了(输出结果中用双引号引起来)。
矩阵元素可通过下标引用,多维矩阵可以只用一个下标,请注意info[3]获得的数据:
>info[1,]
[1]"赵匡胤""钱学森""孙思邈"
>info[,1]
name height
"赵匡胤""172"
>info[3]
[1]"钱学森"
四、列表(list)
列表由向量直接派生而来,nameList是它的子类,listOfMethods是它家孙子:
>getClass("list")
Class"list"[package"methods"]
NoSlots,prototype ofclass"list"
Extends:"vector"
KnownSubclasses:
Class"namedList",fromdata part
Class"listOfMethods",byclass"namedList",distance2
那么列表是什么样子的呢?看这:
>gene
>gene
$agi
[1]"AT1G00010"
$gene.mode
[1]"AT1G00010.1""AT1G00010.2""AT1G00010.3"
$expression
[,1][,2]
[1,]16
[2,]27
[3,]38
[4,]49
[5,]510
列表可以组合不同的数据类型,甚至可以是其他列表,各组成数据的类、长度、维数都可以不一样。
五、数据框(data frame)
R
语言中,一个矩阵内的数据类型要求都要相同,这对生物类数据不大适用,因为我们的数据经常是既有数字又有字符类标记。R语言提供了另外一种更灵活的数据类
型:数据框。可以将几个不同类型但长度相同的向量用data.frame( )函数合并到一个数据框,它的模样就像二维数组。但要注意:合并的几个向量长
度必需一致。
>name
>height
>info
>info
name height
1赵匡胤172
2钱学森175
3孙思邈168
用as.data.frame( )函数可以将二维矩阵转成数据框,但鉴于矩阵的数据类型限制,在生物类数据中用得少一些。
虽然数据框的外观和二维矩阵差不多,但它却不是从矩阵而是从列表派生来的,它是数据(.data)是列表数据,列名称(names)就是列表中各项的名称,另外还有行名称(row.names):
>getClass("data.frame")
Class"data.frame"[package"methods"]
Slots:
Name:.Datanames row.names
Class:list character data.frameRowLabels
Name:.S3Class
Class:character
Extends:
Class"list",fromdata part
Class"oldClass",directly
Class"data.frameOrNULL",directly
Class"vector",byclass"list",distance2
数据框的每列是一个向量,称为列向量。列向量只有两种类型,要么是数字型,要么是因子型。从文件读取或其他类型数据转换成数据框的数据,如果不是数值型,会被强制转换成因子型。有时候数值型(尤其是整型)向量也会被转成因子,这点应该注意。
数据框可以用数字下标取数据,也可以用列名称下标取数据,但是两种方式所获数据的类型是不一样的,按列名称下标方式取得的数据仍然是数据框:
>info[,1]
[1]赵匡胤钱学森孙思邈
Levels:钱学森孙思邈赵匡胤
>class(info[,1])
[1]"factor"
>info["name"]
name
1赵匡胤
2钱学森
3孙思邈
>class(info["name"])
[1]"data.frame"
为什么要注意这个区别?因为看起来像是同样的数据,在一些对类型要求很严格的操作(比如作图)中得到完全不一样的结果。数据框还有一种数据提取方式,得到因子或向量:
>class(info$name)
[1]"factor"
>class(info$height)
[1]"numeric"
六、特殊值数据
为确保所有数据都能被正确识别、计算或统计等,R定义了一些特殊值数据:
NULL:空数据
NA:表示无数据
NaN:表示非数字
inf:数字除以0得到的值
判断一个object (x)是不是属于这些类型有相应的函数:
is.null(x)
is.na(x)
is.nan(x)
is.infinite(x)
七、获取数据类型信息的一些有用函数
R语言的对象“类”很多,虽然我们不可能一一去详细学习,但接触到一类新数据时我们需要了解一些基本信息才能进行进一步的操作。R提供了一些非常有用的方法(函数)。
getClass( )函数我们前面已经见过了,它的参数是表示类的字符串。
class( )可获取一个数据对象所属的类,它的参数是对象名称。
str( )可获取数据对象的结构组成,这很有用。
mode( )和storage.mode( )可获取对象的存储模式。
typeof( )获取数据的类型或存储模式。
要了解这些函数能干什么可以在R里面查询,方法是用问号加上面的函数名就可以,如:?str