3.5 向量子集
向量子集是R的主要优点之一。它非常灵活且功能强大。子集有三种类型:1. 按索引(数字)2. 按名称(字符)3. 按条件(逻辑)。要进行取子集操作,需要输入变量名称并在方括号中指定所需元素。数值子集与许多其他语言相反,R中的向量索引是基于1的,也就是说,第一个元素的索引为1。
> x = c(1,4,7,9,10,24,100)
> x[4]
[1] 9
> x[c(1,4,5)]
[1] 1 9 10
> x[c(6,1,5,1,2,6,6)]
[1] 24 1 10 1 4 24 24
> x[2:5]
[1] 4 7 9 10
> x[length(x):1]
[1] 100 24 10 9 7 4 1
> y = x[c(5,5,1:3)]
> y
[1] 10 10 1 4 7
负索引可用于排除特定元素:
> x[-1:-3]
[1] 9 10 24 100
> x[-length(x)]
[1] 1 4 7 9 10 24
3.5.1 按名称取子集
命名向量可以通过名称进行索引:
> names(x) = letters[1:length(x)]
> x
a b c d e f g
1 4 7 9 10 24 100
> x['a']
a
1
> x[c('b','a','c')]
b a c
4 1 7
注意!R允许名称重复。在这种情况下,将返回第一个匹配项:
> names(x)[3] = 'a'
> x
a b a d e f g
1 4 7 9 10 24 100
> x['a']
a
1
3.5.2 按逻辑值取子集
按逻辑值取子集用于有条件地选择某些元素。例如,可以获取所有奇数值:
> x[x %% 2 == 1]
a a d
1 7 9
> x[x>9]
e f g
10 24 100
括号内的逻辑值不一定基于向量计算:
> x[c(T,F,F,T,F,T,T)]
a d f g
1 9 24 100
> x[c(T,F)]
a a e g
1 7 10 100
3.6 列表(Lists)
向量可用于存储相同类型的值。如果需要存储不同类型的信息(例如一个人的姓名和年龄),它们就不起作用。R列表允许存储任何类型的变量,包括其他列表。列表非常灵活,可以满足您的所有需求。列表可以通过类似于c
函数的list
函数创建。
> l = list(1,'a',2:4,c('b','c'))
> l
[[1]]
[1] 1
[[2]]
[1] "a"
[[3]]
[1] 2 3 4
[[4]]
[1] "b" "c"
> typeof(l)
[1] "list"
> str(l)
List of 4
$ : num 1
$ : chr "a"
$ : int [1:3] 2 3 4
$ : chr [1:2] "b" "c"
> l = list(name='Sam',yob=2001L,weight=70.5)
> str(l)
List of 3
$ name : chr "Sam"
$ yob : int 2001
$ weight: num 70.5
> l[3:2]
$weight
[1] 70.5
$yob
[1] 2001
> l[c('weight','name')]
$weight
[1] 70.5
$name
[1] "Sam"
> l[c(F,T,F)]
$yob
[1] 2001
通过[
运算符进行列表索引将返回原始列表的子列表。要获取列表的特定元素,应使用[[
运算符:
> l2 = l[3]
> typeof(l2)
[1] "list"
> l2
$weight
[1] 70.5
> l3 = l[[3]]
> typeof(l3)
[1] "double"
> l3
[1] 70.5
运算符[[
看起来很不优雅,因此对于命名向量,可以使用与[[
完全相同的运算符$
:
> l$name
[1] "Sam"
> typeof(l$name)
[1] "character"
任何类型的数据都可以存储在列表中:
> l = list(abc=letters[1:4],innerlist=list(a='a',b=1:10),sumfun = sum)
> str(l)
List of 3
$ abc : chr [1:4] "a" "b" "c" "d"
$ innerlist:List of 2
..$ a: chr "a"
..$ b: int [1:10] 1 2 3 4 5 6 7 8 9 10
$ sumfun :function (..., na.rm = FALSE)
> l$innerlist$b
[1] 1 2 3 4 5 6 7 8 9 10
> l$innerlist$b[5:1]
[1] 5 4 3 2 1
> l$sumfun(1:10)
[1] 55
3.7 字典(Dictionaries)
与Python不同,R没有字典(哈希表)对象。大多数情况下,可以使用命名向量(或列表)代替(但要小心名称重复)。否则,可以使用环境作为哈希,但这超出了本课程的范围。
3.8 类(Classes)
R支持至少三种不同的面向对象编程(OOP)系统。大多数R用户不需要创建自己的类,但了解这些系统以处理现有的包是值得的。我们将简要讨论其中两个:S3和S4,让我们从S3系统开始。在OOP范式中,每个变量都根据其类进行处理。R允许向任何变量添加属性,可以使用属性或attr
函数访问、设置和修改属性。
> v = c(a=1,b=10,z=7)
> attributes(v)
$names
[1] "a" "b" "z"
因此,向量值的名称是向量属性之一。通常,所有属性都通过特定函数(例如names
)访问。S3系统使用称为class
的属性,可以使用函数class
访问。我们将使用factor
类来说明S3系统。因子是为存储分类信息(例如性别(男/女)或物种(狗/猫/人))而开发的类。分类信息可以存储为文本,但有时因子很有用。
> f = factor(c('m','m','f'),levels = c('m','f','unk'))
> typeof(f)
[1] "integer"
> class(f)
[1] "factor"
> f
[1] m m f
Levels: m f unk
> f2 = unclass(f)
> class(f2)
[1] "integer"
> f2
[1] 1 1 2
attr(,"levels")
[1] "m" "f" "unk"
一些R函数可以分派函数调用,即根据其参数调用特定函数。在这种情况下,它只是调用一个函数,该函数的名称是由点分隔的通用函数名和类名组合而成:
> print.factor(f2)
[1] 1 1 2
Levels: m f unk
虽然f2现在不是一个因子,但如果我们手动调用相应的函数,它仍然可以被打印为因子。
3.9 二维数据结构
到目前为止我们讨论的类型都是一维的,但有些数据(基因到细胞表达矩阵,或样本元数据)需要二维(甚至三维)结构(又名表)来存储。R中有两种二维结构:数组(arrays)和数据框(data.frames)。数组允许仅存储单一类型的值,因为数组内部是向量。Data.frames可以有不同类型的列,但每列只能包含单一类型的值。Data.frames内部是列的列表。
3.9.1 数组(Arrays)
> a = matrix(1:12,ncol=3)
> a
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> typeof(a)
[1] "integer"
> class(a)
[1] "matrix" "array"
> attributes(a)
$dim
[1] 4 3
> dim(a)
[1] 4 3
> nrow(a)
[1] 4
> ncol(a)
[1] 3
> colnames(a) = letters[1:ncol(a)]
> rownames(a) = LETTERS[1:nrow(a)]
> a
a b c
A 1 5 9
B 2 6 10
C 3 7 11
D 4 8 12
可以使用相同的三种方法(按数字、按名称和逻辑)执行数组取子集,但索引将分别应用于行和列:
> a[1:2,3:1]
c b a
A 9 5 1
B 10 6 2
> a[,2:3]
b c
A 5 9
B 6 10
C 7 11
D 8 12
> a[c(4,2,3),]
a b c
D 4 8 12
B 2 6 10
C 3 7 11
> a[c('D','C'),c('b','b')]
b b
D 8 8
C 7 7
> a[,c(T,F,T)]
a c
A 1 9
B 2 10
C 3 11
D 4 12
> a[a[,1]>2,]
a b c
C 3 7 11
D 4 8 12
> a[-2,c('c','b')]
c b
A 9 5
C 11 7
D 12 8
3.9.2 数据框(Data.frames)
Data.frame与矩阵非常相似,但它允许在不同的列中存储不同类型的值。Data.frame可以通过指定列通过data.frame
函数创建,所有列应为相同长度的向量。
> d = data.frame(name=c('Sam','John','Sara'),age=c(40,14,51),sex=factor('m','m','f'))
> class(d)
[1] "data.frame"
> typeof(d)
[1] "list"
> d
name age sex
1 Sam 40 f
2 John 14 f
3 Sara 51 f
与数组类似,data.frames可以有行名和列名。唯一的区别是data.frame行名应该是唯一的:
> colnames(d)
[1] "name" "age" "sex"
> rownames(d) = c('Sm','Jn','Sr')
> d
name age sex
Sm Sam 40 f
Jn John 14 f
Sr Sara 51 f
data.frames的索引与数组索引相同:
> d[c(3,1),c('sex','name')]
sex name
Sr f Sara
Sm f Sam
但由于data.frames是列表,因此也可以使用运算符$
来获取单列:
> d$age
[1] 40 14 51
往期内容:
重生之我在剑桥大学学习单细胞RNA-seq分析——2. scRNA-Seq原始测序数据处理(1)
重生之我在剑桥大学学习单细胞RNA-seq分析——2. scRNA-Seq原始测序数据处理(2)
重生之我在剑桥大学学习单细胞RNA-seq分析——3. 单细胞分析中的R/Bioconductor简介(1)