purrr 包之 list 处理系列函数

purrr 包还包含了一系列的 list 处理函数,主要包括 filtersummarisetransform 3 个类型。

上次介绍了 purrr 包的类似于 apply 家族的 map 系列,这次介绍这个包对 list 进行筛选的一系列函数。

1、filter

filter 系列有 6 个子函数来对 list 来进行筛选:

purrr 包之 list 处理系列函数 - 图1

pluck:

  • pluck 函数根据 list 的索引值,名称或属性来筛选结果:
    • 示例:
  1. library(purrr)
  2. # 新建list
  3. obj1 <- list("a", list(1, elt = "foo"))
  4. obj2 <- list("b", list(2, elt = "bar"))
  5. x <- list(obj1, obj2)
  6. # 根据索引值取元素,类似于[[]]符号
  7. # x[[1]]
  8. pluck(x, 1)
  9. [[1]]
  10. [1] "a"
  11. [[2]]
  12. [[2]][[1]]
  13. [1] 1
  14. [[2]]$elt
  15. [1] "foo"
  16. # 取第一个列表的第二个元素
  17. # x[[1]][[2]]
  18. pluck(x, 1, 2)
  19. [[1]]
  20. [1] 1
  21. $elt
  22. [1] "foo"
  23. # 根据第一个列表的第二个元素的名称取值
  24. # x[[1]][[2]][["elt"]]
  25. pluck(x, 1, 2, "elt")
  26. [1] "foo"
  27. # 如果元素不存在则返回null
  28. pluck(x, 10)
  29. NULL

keep:

  • keep 函数保存通过逻辑判断的 list 元素:
    • 示例:
  1. # 生成10组含有5个数的随机数,取出均值大于6的list
  2. rep(10, 10) %>%
  3. map(sample, 5) %>%
  4. keep(function(x) mean(x) > 6)
  5. [[1]]
  6. [1] 6 10 5 8 2
  7. [[2]]
  8. [1] 5 3 9 7 8
  9. [[3]]
  10. [1] 10 5 3 7 6
  11. # 筛选出NA
  12. x <- list(1,2,3,NA,5,NA)
  13. x %>% keep(is.na)
  14. [[1]]
  15. [1] NA
  16. [[2]]
  17. [1] NA

discard:

  • discard 函数保存没有通过逻辑判断的 list 元素:
    • 示例:
  1. # 筛选出不是NA的值
  2. x <- list(1,2,3,NA,5,NA)
  3. x %>% discard(is.na)
  4. [[1]]
  5. [1] 1
  6. [[2]]
  7. [1] 2
  8. [[3]]
  9. [1] 3
  10. [[4]]
  11. [1] 5

compact:

  • mpact 函数丢弃为 null 的元素:
    • 示例:
  1. list(a = "a", b = NULL, c = integer(0), d = NA, e = list()) %>%
  2. compact()
  3. $a
  4. [1] "a"
  5. $d
  6. [1] NA

head/tail_while:

  • head/tail_while 函数返回没有通过条件判断之前或之后的元素:
    • 示例:
  1. # 输出直到大于0或小于0的元素
  2. pos <- function(x) x >= 0
  3. head_while(5:-5, pos)
  4. [1] 5 4 3 2 1 0
  5. tail_while(5:-5, negate(pos))
  6. [1] -1 -2 -3 -4 -5

2、summarise

summarise 也有 6 个函数对 list 元素进行判断和筛选:

purrr 包之 list 处理系列函数 - 图2

every:

  • every 函数对 list 每个元素进行判断,返回逻辑值,所有元素都满足条件则返回 TRUE,否则返回 FALSE:
    • 示例:
  1. y <- list(0:10, 5.5)
  2. y %>% every(is.numeric)
  3. [1] TRUE
  4. y <- list(0:10, 5.5,'test')
  5. y %>% every(is.numeric)
  6. [1] FALSE

some:

  • some 函数判断是否存在元素通过条件,如果存在则返回 TRUE,否则返回 FALSE:
    • 示例:
  1. # 判断是否存在整形
  2. y <- list(0:10, 5.5,'test')
  3. y %>% some(is.integer)
  4. [1] TRUE
  5. # 判断是否存在NA
  6. y %>% some(is.na)
  7. [1] FALSE

has_element:

  • has_element 函数判断是否存在某个元素,如果存在则返回 TRUE,否则返回 FALSE:
    • 示例:
  1. # 判断是否存在1:10
  2. x <- list(1:10, 5, 9.9)
  3. x %>% has_element(1:10)
  4. [1] TRUE
  5. # 判断是否存在3
  6. x %>% has_element(3)
  7. [1] FALSE

detect/detect_index:

  • detect/detect_index 函数寻找第一个满足条件的元素并返回其值(前者)或索引值(后者)
    • 示例:
  1. # 判断第一个能整除2的元素
  2. is_even <- function(x) x %% 2 == 0
  3. 3:10 %>% detect(is_even)
  4. [1] 4
  5. # 返回索引值
  6. 3:10 %>% detect_index(is_even)
  7. [1] 2
  8. # 从后向前寻找
  9. 3:10 %>% detect(is_even, .dir = "backward")
  10. [1] 10
  11. # 索引值
  12. 3:10 %>% detect_index(is_even, .dir = "backward")
  13. [1] 8

vec_depth:

  • vec_depth 函数返回索引级别的数量:
    • 示例:
  1. x <- list(
  2. list(),
  3. list(list()),
  4. list(list(list(1)))
  5. )
  6. vec_depth(x)
  7. [1] 5

3、transform

transform 有 4 个子函数对 list 进行转换:

purrr 包之 list 处理系列函数 - 图3

modify:

  • modify 函数对 list 每个元素应用函数:map, map_chr, map_dbl, map_dfc, map_dfr, map_int, map_lgl 等:

modify_at:

  • modify_at 函数对指定位置或指定名称的元素应用函数:

modify_if:

  • modify_if 函数对通过条件判断的元素应用函数:

modify_depth:

  • modify_depth 函数对 list 特定等级的元素应用函数:
    • 综合示例:
  1. # 把factor转化为character
  2. iris %>%
  3. modify_if(is.factor, as.character) %>%
  4. str()
  5. 'data.frame': 150 obs. of 5 variables:
  6. $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
  7. $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
  8. $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
  9. $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
  10. $ Species : chr "setosa" "setosa" "setosa" "setosa" ...
  11. # 对指定列进行转换为character
  12. mtcars %>% modify_at(c(1, 4, 5), as.character) %>% str()
  13. 'data.frame': 32 obs. of 11 variables:
  14. $ mpg : chr "21" "21" "22.8" "21.4" ...
  15. $ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
  16. $ disp: num 160 160 108 258 360 ...
  17. $ hp : chr "110" "110" "93" "110" ...
  18. $ drat: chr "3.9" "3.9" "3.85" "3.08" ...
  19. $ wt : num 2.62 2.88 2.32 3.21 3.44 ...
  20. $ qsec: num 16.5 17 18.6 19.4 17 ...
  21. $ vs : num 0 0 1 1 0 1 0 1 1 1 ...
  22. $ am : num 1 1 1 0 0 0 0 0 0 0 ...
  23. $ gear: num 4 4 4 3 3 3 3 4 4 4 ...
  24. $ carb: num 4 4 1 1 2 1 4 2 2 4 ...
  25. # 用指定列名来转换为character
  26. mtcars %>% modify_at(c("cyl", "am"), as.character) %>% str()
  27. 'data.frame': 32 obs. of 11 variables:
  28. $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
  29. $ cyl : chr "6" "6" "4" "6" ...
  30. $ disp: num 160 160 108 258 360 ...
  31. $ hp : num 110 110 93 110 175 105 245 62 95 123 ...
  32. $ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
  33. $ wt : num 2.62 2.88 2.32 3.21 3.44 ...
  34. $ qsec: num 16.5 17 18.6 19.4 17 ...
  35. $ vs : num 0 0 1 1 0 1 0 1 1 1 ...
  36. $ am : chr "1" "1" "1" "0" ...
  37. $ gear: num 4 4 4 3 3 3 3 4 4 4 ...
  38. $ carb: num 4 4 1 1 2 1 4 2 2 4 ...
  39. # 构建多层嵌套list,pbj为第一层,pro为第二层,param为第三层
  40. l1 <- list(
  41. obj1 = list(
  42. prop1 = list(param1 = 1:2, param2 = 3:4),
  43. prop2 = list(param1 = 5:6, param2 = 7:8)
  44. ),
  45. obj2 = list(
  46. prop1 = list(param1 = 9:10, param2 = 11:12),
  47. prop2 = list(param1 = 12:14, param2 = 15:17)
  48. )
  49. )
  50. # 对第三层元素进行加和
  51. l1 %>% modify_depth(3, sum) %>% str()
  52. List of 2
  53. $ obj1:List of 2
  54. ..$ prop1:List of 2
  55. .. ..$ param1: int 3
  56. .. ..$ param2: int 7
  57. ..$ prop2:List of 2
  58. .. ..$ param1: int 11
  59. .. ..$ param2: int 15
  60. $ obj2:List of 2
  61. ..$ prop1:List of 2
  62. .. ..$ param1: int 19
  63. .. ..$ param2: int 23
  64. ..$ prop2:List of 2
  65. .. ..$ param1: int 39
  66. .. ..$ param2: int 48
  67. # 用名字取对应的值
  68. l1 %>% modify(c("prop1", "param2")) %>% str()
  69. List of 2
  70. $ obj1: int [1:2] 3 4
  71. $ obj2: int [1:2] 11 12
  72. # 对第二层的list用指定名称取值
  73. l1 %>% modify_depth(2, "param2") %>% str()
  74. List of 2
  75. $ obj1:List of 2
  76. ..$ prop1: int [1:2] 3 4
  77. ..$ prop2: int [1:2] 7 8
  78. $ obj2:List of 2
  79. ..$ prop1: int [1:2] 11 12
  80. ..$ prop2: int [1:3] 15 16 17
  81. # 对第二层级的每个元素结合pmap函数
  82. l1 %>% modify_depth(2, ~ pmap(., paste, sep = " / ")) %>% str()
  83. List of 2
  84. $ obj1:List of 2
  85. ..$ prop1:List of 2
  86. .. ..$ : chr "1 / 3"
  87. .. ..$ : chr "2 / 4"
  88. ..$ prop2:List of 2
  89. .. ..$ : chr "5 / 7"
  90. .. ..$ : chr "6 / 8"
  91. $ obj2:List of 2
  92. ..$ prop1:List of 2
  93. .. ..$ : chr "9 / 11"
  94. .. ..$ : chr "10 / 12"
  95. ..$ prop2:List of 3
  96. .. ..$ : chr "12 / 15"
  97. .. ..$ : chr "13 / 16"
  98. .. ..$ : chr "14 / 17"