生物信息学生R入门教程–R的数据结构

Vectors

无论是atomic vector还是list,都属于vector。这两者构成了R最基本的两大类数据结构。Atomic vector与list的区别在于,前者的元素都必须是由同一数据类型组成的,也就是说atomic vector都是同质的,而list中的元素可以是异质的。Atomic在这里的意思,就是说它就如同R中的原子一样,是构成其它数据结构的基础。

除了vector中保存的数据以外,它还有三个属性:typeof() (是什么), length() (有多少元素)和attributes() (有哪些注释数据)。最常用到的attributes就应该是names(),也就是每个元素的名字。

Atomic vector

Atomic vector常见的是由logical, integer, double, 或者character组成,很罕见的是由raw或者complex组成。我们使用c()(combine的首字母)函数来创建长度大于1的atomic vector。

> x <- c(1, 3.5, 5.6)
> i <- c(1L, 2L, 10L)  ## L后缀便于R自动识别输入的数字为整型
> b <- c(TRUE, FALSE, T, F)  ## 通常而言,在标准的代码书写过程中应该避免使用不完整的缩写T和F。
> ch <- c("who", "am", "I")

在任何时候,c()函数都是可以圈套使用的,但其结果不会产生分层,而全部会展平为一层。比如

> c(1, c(2, 3)) == c(1, 2, 3)
## [1] TRUE TRUE TRUE

示例使用typeof(), length()以及attributes()查看vector的属性。

> a <- 1:3  ## 冒号(:)是seq()函数的缩写, 用于生成序列数
> typeof(a)
## [1] "integer"
> is.integer(a)
## [1] TRUE
> is.numeric(a)
## [1] TRUE
> length(a)
## [1] 3
> attributes(a)
## NULL
> names(a) <- letters[1:3]
> attributes(a)
## $names
## [1] "a" "b" "c"
> names(a)
## [1] "a" "b" "c"
> 
> LETTERS  ## LETTERS预存了26个大写字母
##  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q"
## [18] "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
> typeof(LETTERS)
## [1] "character"
> length(LETTERS)
## [1] 26

当不同类型的数据使用c()函数创建atomic vector时,因为atomic vector的元素都必须是同质的,所以系统会依照character, double, integer, logical的顺序对数据类型进行转换。例如:

> c(9, "a", 1.5, FALSE)  ##全部转换为character
## [1] "9"     "a"     "1.5"   "FALSE"
> c(9, 1.5, FALSE)  ##全部转换为double
## [1] 9.0 1.5 0.0
> c(FALSE, 9)  ##全部转换为integer
## [1] 0 9

下面我们来尝试对atomic vector排序。

> a <- c(4, 2, 1, 3)
> b <- sort(a)
> b
## [1] 1 2 3 4
Factor

Factor是R中非常具有特点的一类atomic vector。首先它是atomic vector,所以它的所有元素必须是同质的,准确地讲其基础类型应该是character。但是它又不同于普通的character型atomic vector。它是将相同字符归类后使用特定格式存放的数据。它有levels()方法,可以得到一个factor中所有的水平(去除重复后所有的元素)。它的创建分为三个步骤,1,将输入的数据转换成character型;2,对所有的水平进行排序(可能是指定的排序,或者自然排序),将排序后的水平保存在levels中;3,使用levels中的水平序列号重新编码输入的元素。

> a <- factor(c(2, 1, 5, 10, 5))
> a
## [1] 2  1  5  10 5 
## Levels: 1 2 5 10
> levels(a)  ## a中保存的所有水平
## [1] "1"  "2"  "5"  "10"
> a[4]  ## a的第四个元素
## [1] 10
## Levels: 1 2 5 10
> as.numeric(a)  ##强制将a转换成数字
## [1] 2 1 3 4 3
> as.numeric(as.character(a))  ##将a正确地还原为原始数据
## [1]  2  1  5 10  5
> 
> b <- factor(letters[c(2, 1, 5, 10, 5)])
> b
## [1] b a e j e
## Levels: a b e j
> levels(b)
## [1] "a" "b" "e" "j"
> b[4]
## [1] j
## Levels: a b e j
> as.numeric(b)  ##与之前的强制转换比较,就发现,这里得到的数字只是重新编码后的数字。
## [1] 2 1 3 4 3
> as.character(b)
## [1] "b" "a" "e" "j" "e"

Factor的值必须是levels中包含的值,否值无法对其编码。

> a <- factor(1:4)
> a[4] <- 5  ## 会得到一个警告
## Warning: invalid factor level, NA generated
> a
## [1] 1    2    3    <NA>
## Levels: 1 2 3 4
> ## 正确的做法是先改变其levels,然后再变更其值
> levels(a) <- c(levels(a), 5)
> a[4] <- 5
> a
## [1] 1 2 3 5
## Levels: 1 2 3 4 5

如果想修改factor中所有等于某值的数据为level中不存在的另一数值,应该直接修改其levels。

> a <- factor(c(letters[1:5], letters[5:1]))
> a
##  [1] a b c d e e d c b a
## Levels: a b c d e
> a[2] <- "a"  ##是level中存在的值,是可以的。
> a
##  [1] a a c d e e d c b a
## Levels: a b c d e
> levels(a)[3] <- "z"
> a
##  [1] a a z d e e d z b a
## Levels: a b z d e

Factor的出现除了存贮空间的考虑,更主要是它可以被广泛地应用到公式中。这里简单的示例依靠factor的split()函数的应用。split()是将输入的第一个对象按照输入的第二个(强制转换的)factor的水平进行分割。得到的结果将是一个list。

> x <- sample(1:10, 100, replace = TRUE)
> x
##   [1]  6  1  4  9  3  9  1  5  7  1  4  2  8  2  9  4 10  8  2  1 10  2  4
##  [24]  6  4  8  8  6  5  3  2  3 10  6  1  1  7  5  2  4  1  1  3  2  6  9
##  [47]  7 10  3  5  1  1  3  5  7  5  8 10  2  3  8 10  3  6  9  7  2  8  4
##  [70]  1  5  2  1  1  1 10  3 10  3  4  7  9  1  3  5  5  5  5  4 10 10  6
##  [93] 10  8  8  3  4  1  7  2
> y <- 1:100
> split(y, x)
## $`1`
##  [1]  2  7 10 20 35 36 41 42 51 52 70 73 74 75 83 98
## 
## $`2`
##  [1]  12  14  19  22  31  39  44  59  67  72 100
## 
## $`3`
##  [1]  5 30 32 43 49 53 60 63 77 79 84 96
## 
## $`4`
##  [1]  3 11 16 23 25 40 69 80 89 97
## 
## $`5`
##  [1]  8 29 38 50 54 56 71 85 86 87 88
## 
## $`6`
## [1]  1 24 28 34 45 64 92
## 
## $`7`
## [1]  9 37 47 55 66 81 99
## 
## $`8`
## [1] 13 18 26 27 57 61 68 94 95
## 
## $`9`
## [1]  4  6 15 46 65 82
## 
## $`10`
##  [1] 17 21 33 48 58 62 76 78 90 91 93

List

同属于vector的list也是一维的,但是其元素可以是任何一种vector,当然也就包括了list。可以用目录来类比list。目录下可以存放不同的文件,包括目录,list也是一样的,只不过文件变成了vector。

构建list使用list()函数,对于除了Atomic vectors和list以外的对象或者混合对象时有时候也可以使用c()。

> a <- list(1:3, letters[1:3], c(FALSE, TRUE), c(1, 1))
> str(a)
## List of 4
##  $ : int [1:3] 1 2 3
##  $ : chr [1:3] "a" "b" "c"
##  $ : logi [1:2] FALSE TRUE
##  $ : num [1:2] 1 1
> x <- list(list(list()))
> str(x)
## List of 1
##  $ :List of 1
##   ..$ : list()
> is.recursive(x)
## [1] TRUE
> x <- list(list(1, 2), c(3, 4))
> y <- c(list(1, 2), c(3, 4))  # y会是一个展平为一层的list
> str(x)
## List of 2
##  $ :List of 2
##   ..$ : num 1
##   ..$ : num 2
##  $ : num [1:2] 3 4
> str(y)
## List of 4
##  $ : num 1
##  $ : num 2
##  $ : num 3
##  $ : num 4
> a <- c(1:3, letters[1:3], c(FALSE, TRUE), list(1, 1))
> str(a)
## List of 10
##  $ : int 1
##  $ : int 2
##  $ : int 3
##  $ : chr "a"
##  $ : chr "b"
##  $ : chr "c"
##  $ : logi FALSE
##  $ : logi TRUE
##  $ : num 1
##  $ : num 1

有些时候,我们也可以视list为二维,甚至多维数据。这取决于读者的理解。从本质上看,list是一种有长度的链表数据,每一个元素其实都是一个指针,它可以指向任何一种数据结构。从这个意义上来讲,它又是同质的。

List与atomic vector的区别与联系

Atomic vector和list一样都可以使用索引号或者名称来访问其元素,但方法会略有不同。

> a <- list(num = 8, alphabet = letters[1:3], logi = TRUE, num = c(1, 1))
> a[[1]]
## [1] 8
> a[1]
## $num
## [1] 8
> is.atomic(a[1])
## [1] FALSE
> is.atomic(a[[1]])
## [1] TRUE
> is.list(a[1])
## [1] TRUE
> names(a)
## [1] "num"      "alphabet" "logi"     "num"
> a[["alphabet"]]
## [1] "a" "b" "c"
> a["alphabet"]  ## 注意[与[[的不同
## $alphabet
## [1] "a" "b" "c"
> a$alphabet
## [1] "a" "b" "c"
> b <- letters[1:8]
> names(b) <- LETTERS[1:8]
> is.atomic(b)
## [1] TRUE
> names(b)
## [1] "A" "B" "C" "D" "E" "F" "G" "H"
> b["C"]
##   C 
## "c"
> b$C  ## 会得到一个错误
## Error: $ operator is invalid for atomic vectors

从上面的例子可以看出,atomic vector可以是list的元素,这也是它为什么可atomic的原因。list访问元素的方式为'[['或者'$',取子集的方式为'[';atomic vector访问元素和取子集的方式均为'['。list和atomic vector都可以通过索引号和名称访问其元素。

如果想去除atomic vector中的某些元素,可以使用'-'号;如果想去除list中的某些元素,可以使用'-'号或者赋值为NULL。也可以使用TRUE/FALSE来取舍。

> a <- 1:4
> a[-c(1, 4)]
## [1] 2 3
> a[2] <- NULL  ## 会得到一个错误
## Error: replacement has length zero
> a[c(TRUE, FALSE, TRUE, FALSE)]
## [1] 1 3
> a <- as.list(a)
> a
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 2
## 
## [[3]]
## [1] 3
## 
## [[4]]
## [1] 4
> a[-c(1, 3)]
## [[1]]
## [1] 2
## 
## [[2]]
## [1] 4
> a[[-3]]  ## 会得到一个错误
## Error: attempt to select more than one element
> a[[3]] <- NULL
> a
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 2
## 
## [[3]]
## [1] 4
> a[c(TRUE, FALSE, TRUE)]
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 4

3 thoughts on “生物信息学生R入门教程–R的数据结构

  1. 老师,您好,刚看到您讲的vector这里;我试着
    a<-c(1,2,3)
    typeof(a) 得到的类型却是double,class(a) 类型则是numeric,为什么不是integer,请老师解答。

  2. 嗯,在rstudio里试了一下,确实可以了,在网上也找到了一篇博客,专门提到了这个问题,供大家参考:http://blog.sina.com.cn/s/blog_b37ea00701018uwo.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注