[关闭]
@evilking 2018-03-03T08:00:08.000000Z 字数 4369 阅读 990

R基础篇

列表

向量的元素要求都是同类型的,而列表却可以组合多个不同类型的对象,而且列表中还可以包含列表,即递归列表,有点像C语言中的结构体

列表在R中扮演至关重要的角色,是数据框和面向对象编程的基础

本篇会讲列表的创建,值操作,列表上常用的一些函数

创建列表

  1. > x <- list(name = "Tom",salary = 5000, union=T) #创建字段带有标签的列表
  2. > x
  3. $name
  4. [1] "Tom"
  5. $salary
  6. [1] 5000
  7. $union
  8. [1] TRUE
  9. > (y <- list("Ketty", 5500, F)) #使用默认标签的方式创建列表
  10. [[1]]
  11. [1] "Ketty"
  12. [[2]]
  13. [1] 5500
  14. [[3]]
  15. [1] FALSE
  16. > (z <- vector(mode = "list")) #使用"list"属性的方式创建列表
  17. list()
  18. > z[["name"]] <- "Hello"
  19. > z[["salary"]] <- 6000
  20. > z[["union"]] <- T
  21. > z
  22. $name
  23. [1] "Hello"
  24. $salary
  25. [1] 6000
  26. $union
  27. [1] TRUE
  28. > (w <- list(x,y,z,count = 3)) #列表中包含列表
  29. [[1]]
  30. [[1]]$name
  31. [1] "Tom"
  32. [[1]]$salary
  33. [1] 5000
  34. [[1]]$union
  35. [1] TRUE
  36. [[2]]
  37. [[2]][[1]]
  38. [1] "Ketty"
  39. [[2]][[2]]
  40. [1] 5500
  41. [[2]][[3]]
  42. [1] FALSE
  43. [[3]]
  44. [[3]]$name
  45. [1] "Hello"
  46. [[3]]$salary
  47. [1] 6000
  48. [[3]]$union
  49. [1] TRUE
  50. $count
  51. [1] 3
  52. > c(list(y,z),recursive=T) #将递归属性去掉,得到的是一个向量
  53. name salary union
  54. "Ketty" "5500" "FALSE" "Hello" "6000" "TRUE"
  55. >

这里举出了四种创建列表的方式,从技术上讲,列表就是向量,之前我们接触过的普通向量都称为"原子型"(atomic)向量,即向量的元素已经是最小的、不可再分的。而列表则属于"递归型"(recursive)向量

第一个例子是创建列表的各个组件带有名称的列表,其中这些名称就叫做标签(tags),如name="Tom"中的name就是一个标签;标签的运用可以方便查看该组件代表的含义,同时也可以使用标签去访问某个组件,可以使代码更清晰

当然标签也是可选的,如第二个例子就是创建不带标签的列表,则标签名默认就是按数字排列下去,如[[1]] [[2]] [[3]];我们一般推荐使用带标签的方式来创建列表

列表本质上也是向量,可以用vector()函数来创建,只是该向量具有"list"模式,然后给列表的组件赋值,如果该组件不存在列表中,则会自动创建该标签的组件;如第三个例子就是先创建了一个空的列表,然后给列表的组件赋值,此时这些组件原先是不存在的,赋值的同时也是创建了对应标签的组件

在第四个例子中,我们用列表对象去创建一个新列表,那么列表w的前三个元素,每个元素都是一个子列表,第四个元素是一个向量;由于并没有给前三个元素设置标签名,那么就是用默认的[[1]]来索引;从这个例子还可以看出列表的每个元素的类型确实可以不同

在最后的例子中,用c()函数去拼接,而c()函数有个可选参数recursive,决定在拼接列表的时候,是否把原列表"压平",就是把所有组件的元素都提取出来,组合成一个向量


值操作

赋值

  1. > x #使用上一步创建的列表x
  2. $name
  3. [1] "Tom"
  4. $salary
  5. [1] 5000
  6. $union
  7. [1] TRUE
  8. > x[[1]] <- "Hello Tom" #使用"[[1]]"的方式索引组件
  9. > x
  10. $name
  11. [1] "Hello Tom"
  12. $salary
  13. [1] 5000
  14. $union
  15. [1] TRUE
  16. > x[["salary"]] <- 3400 #使用[["salary"]]的方式索引组件
  17. > x
  18. $name
  19. [1] "Hello Tom"
  20. $salary
  21. [1] 3400
  22. $union
  23. [1] TRUE
  24. > x$union <- FALSE #使用$符合的方式索引组件
  25. > x
  26. $name
  27. [1] "Hello Tom"
  28. $salary
  29. [1] 3400
  30. $union
  31. [1] FALSE

上面列举了三种访问列表中的组件的方式,返回值就是对应的组件,返回值的类型就是对应组件元素的数据类型,这一点很重要,因为还有一种访问组件的方式,如下:

  1. > x[1] #使用单括号索引取值
  2. $name
  3. [1] "Hello Tom"
  4. > x["salary"] #使用单括号+标签的方式取值
  5. $salary
  6. [1] 3400
  7. > class(x[1]) #查看单括号取值结果的数据类型
  8. [1] "list"
  9. > class(x["salary"])
  10. [1] "list"
  11. > class(x[[1]]) #查看双括号索引取值的数据类型
  12. [1] "character"
  13. > class(x[["salary"]])
  14. [1] "numeric"
  15. > x[1:2] #使用单括号+索引序列的方式取值
  16. $name
  17. [1] "Hello Tom"
  18. $salary
  19. [1] 3400
  20. > x[[1:2]] #体会与上面单括号的区别
  21. Error in x[[1:2]] : 下标出界
  22. >

上述例子展示了使用单括号索引取值及它的返回值类型;可以看出当使用单括号索引时,取的是原列表的子列表,这个子列表包含了取值时对应的标签索引和数值索引;而双重中括号[[]]一次只能提取列表的一个组件,返回值是组件本身的类型,而不是列表


增加或删除列表元素

  1. > x #依然使用上面创建的列表对象
  2. $name
  3. [1] "Hello Tom"
  4. $salary
  5. [1] 3400
  6. $union
  7. [1] FALSE
  8. > x[["aa"]] <- "aabb" #添加一个标签为"aa"的组件,并赋值为"aabb"
  9. > x
  10. $name
  11. [1] "Hello Tom"
  12. $salary
  13. [1] 3400
  14. $union
  15. [1] FALSE
  16. $aa
  17. [1] "aabb"
  18. > x$bb <- "bbcc" #添加一个标签为"bb"的组件,赋值为"bbcc"
  19. > x
  20. $name
  21. [1] "Hello Tom"
  22. $salary
  23. [1] 3400
  24. $union
  25. [1] FALSE
  26. $aa
  27. [1] "aabb"
  28. $bb
  29. [1] "bbcc"
  30. > x[[6]] <- "ccdd" #赋值一个不存在的索引组件时,会添加该组件
  31. > x
  32. $name
  33. [1] "Hello Tom"
  34. $salary
  35. [1] 3400
  36. $union
  37. [1] FALSE
  38. $aa
  39. [1] "aabb"
  40. $bb
  41. [1] "bbcc"
  42. [[6]]
  43. [1] "ccdd"
  44. > x[[4]] <- "ddee" #给一个存在的组件赋值时,就是简单的为组件赋值了
  45. > x
  46. $name
  47. [1] "Hello Tom"
  48. $salary
  49. [1] 3400
  50. $union
  51. [1] FALSE
  52. $aa
  53. [1] "ddee"
  54. $bb
  55. [1] "bbcc"
  56. [[6]]
  57. [1] "ccdd"
  58. > x[[6]] <- NULL #删除指定索引元素
  59. > x
  60. $name
  61. [1] "Hello Tom"
  62. $salary
  63. [1] 3400
  64. $union
  65. [1] FALSE
  66. $aa
  67. [1] "ddee"
  68. $bb
  69. [1] "bbcc"
  70. >

上述例子展示了如何去添加新组件,就是只需要给指定索引的组件赋值就可以了,如果该索引的组件不存在,就会创建新组件;如果要删除指定索引的组件,只需要将它赋值为NULL就可以了


上面介绍了单括号表示取列表的子列表,当然可以利用单括号和索引序列去批量添加或删除组件了,如下:

  1. > x[6:8] <- c(FALSE,TRUE,TRUE) #添加新组件
  2. > x
  3. $name
  4. [1] "Hello Tom"
  5. $salary
  6. [1] 3400
  7. $union
  8. [1] FALSE
  9. $aa
  10. [1] "ddee"
  11. $bb
  12. [1] "bbcc"
  13. [[6]]
  14. [1] FALSE
  15. [[7]]
  16. [1] TRUE
  17. [[8]]
  18. [1] TRUE
  19. > x[5:8] <- NULL #删除子列表
  20. > x
  21. $name
  22. [1] "Hello Tom"
  23. $salary
  24. [1] 3400
  25. $union
  26. [1] FALSE
  27. $aa
  28. [1] "ddee"
  29. >

列表的数据展开

  1. > x
  2. $name
  3. [1] "Hello Tom"
  4. $salary
  5. [1] 3400
  6. $union
  7. [1] FALSE
  8. $aa
  9. [1] "ddee"
  10. > unlist(x) #展开列表x,则不在具有list属性
  11. name salary union aa
  12. "Hello Tom" "3400" "FALSE" "ddee"
  13. > mode(unlist(x)) #去掉了list属性
  14. [1] "character"
  15. > names(w) #查看列表w的标签
  16. [1] "" "" "" "count"
  17. > names(x)
  18. [1] "name" "salary" "union" "aa"
  19. > names(y)
  20. NULL
  21. > names(z)
  22. [1] "name" "salary" "union"
  23. > unlist(w) #循环列表的每个元素也是依次展开
  24. name salary union name salary union
  25. "Tom" "5000" "TRUE" "Ketty" "5500" "FALSE" "Hello" "6000" "TRUE"
  26. count
  27. "3"
  28. > (x <- unname(unlist(x))) #使用unname()函数可以去掉元素名
  29. [1] "Hello Tom" "3400" "FALSE" "ddee"
  30. >

如果一个列表的各个元素含有标签,就可以使用names()获取它的标签

unlist()函数返回的值是一个向量,向量的元素的元素名就来自原列表的标签

列表上的常用函数

  1. > w
  2. [[1]]
  3. [[1]]$name
  4. [1] "Tom"
  5. [[1]]$salary
  6. [1] 5000
  7. [[1]]$union
  8. [1] TRUE
  9. [[2]]
  10. [[2]][[1]]
  11. [1] "Ketty"
  12. [[2]][[2]]
  13. [1] 5500
  14. [[2]][[3]]
  15. [1] FALSE
  16. [[3]]
  17. [[3]]$name
  18. [1] "Hello"
  19. [[3]]$salary
  20. [1] 6000
  21. [[3]]$union
  22. [1] TRUE
  23. $count
  24. [1] 3
  25. > length(x) #查看列表x的长度
  26. [1] 4
  27. > length(w) #查看循环列表w的长度
  28. [1] 4
  29. >

由于列表是向量,可以使用length()得到列表的组件个数


  1. > lapply(list("a" = 1:5,"b" = 10:20),sum)
  2. $a
  3. [1] 15
  4. $b
  5. [1] 165
  6. >

lapply()函数与矩阵的apply()函数的用法类似,对列表中的每个组件应用给定的函数,并返回另一个列表,lapply即代表list apply

上例中按照lapply()函数的规则,分别对"a"组件和"b"组件应用sum()函数求和,则序列1:5求和就是15,序列10:20求和就是165,则结果就如上展示的这个新列表


  1. > sapply(list(1:5,10:20),median)
  2. [1] 3 15
  3. >

在某些情况下,lapply()返回的列表可以转化为矩阵或向量的形式,于是可以用sapply()函数,代表simplified [l]apply,返回的是一个向量

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注