重生之我在剑桥大学学习单细胞RNA-seq分析——3. 单细胞分析中的R/Bioconductor简介(2)

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)

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容