Trong mỗi chúng ta đều có một thiên tài đang ngủ, chỉ có điều càng ngày anh ta ngủ càng say

library(tidyverse)
## ── Attaching packages ────────────────────────────────────────────────────── tidyverse 1.2.1 ──
## ✔ ggplot2 3.1.1       ✔ purrr   0.3.2  
## ✔ tibble  2.1.1       ✔ dplyr   0.8.0.1
## ✔ tidyr   0.8.3       ✔ stringr 1.4.0  
## ✔ readr   1.3.1       ✔ forcats 0.4.0
## ── Conflicts ───────────────────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()

1 Giới thiệu

Nhanh quá! purrr cũng không có quá nhiều thứ để học nhưng mà càng học càng sợ nhanh hết, mà quan trọng hơn càng đọc càng thấy hay

Trong phần này tiếp tục giới thiệu 1 số tiện ích của purrr

2 invoke_map()

Cú pháp:

invoke_map(.f, .x = list(NULL), …, .env = NULL)

Lấy ý tưởng từ hàm do.call nhưng được viết lại dễ sử dụng hơn với pipe. invoke_map() làm việc với 1 list các hàm (invoke chỉ làm với 1 hàm)

Ví dụ:

  • Với nhiều hàm có cùng object như nhau (đều có đầu vào là n)
invoke_map(list(runif, rnorm), n = 5)
## [[1]]
## [1] 0.5840509 0.3287739 0.7719973 0.8382072 0.4159901
## 
## [[2]]
## [1] -0.3270957 -1.9810410  0.2708896  0.9089078  0.5063823
  • Với 1 hàm list argument đầu tiên
set.seed(158)
invoke_map("runif", list(5, 10)) # invoke_map("runif", list(list(n = 5), list(n = 10)))
## [[1]]
## [1] 0.7971946 0.9885000 0.6124226 0.4691508 0.3604160
## 
## [[2]]
##  [1] 0.4601691 0.1228639 0.7343001 0.6868546 0.5806192 0.1728769 0.9669770
##  [8] 0.5230550 0.5934103 0.4695439
  • Nhiều hàm, nhiều agrument khác nhau
f <- c("runif", "rnorm", "rpois")
param <- list(
    list(min = -1, max = 1),
    list(sd = 5),
    list(lambda = 10)
)

invoke_map(f, param, n = 5) %>% str()
## List of 3
##  $ : num [1:5] -0.0692 -0.8097 -0.2257 -0.8307 0.7163
##  $ : num [1:5] 1.1 -3.71 -9.87 5.63 -1.95
##  $ : int [1:5] 9 8 6 11 24
  • Sử dụng với toán tử pipe
list(m1 = mean, m2 = median) %>% invoke_map(x = rcauchy(100))
## $m1
## [1] -0.3312988
## 
## $m2
## [1] 0.1682701

3 pwalk()

Hàm pwalk() tương tự như các hàm map nhưng không trả về giá trị, chỉ thực hiện hàm

plots <- mtcars %>%
  split(.$cyl) %>%
  map(~ggplot(., aes(mpg, wt)) + geom_point())

paths <- stringr::str_c(names(plots), ".pdf")

pwalk(list(paths, plots), ggsave, path = tempdir())
## Saving 7 x 5 in image
## Saving 7 x 5 in image
## Saving 7 x 5 in image

4 keep() và discard()

là 1 dạng loop như map, giữ hoặc loại bỏ phần tử nếu thỏa điều kiện

iris %>% keep(is.factor) %>% str()
## 'data.frame':    150 obs. of  1 variable:
##  $ Species: Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
iris %>% discard(is.factor) %>% str()
## 'data.frame':    150 obs. of  4 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
rep(10, 10) %>%
  map(sample, 5) %>%
  keep(~ mean(.x) > 6)
## [[1]]
## [1]  4 10  9  8  6
## 
## [[2]]
## [1] 10  8  6  7  1
## 
## [[3]]
## [1]  2  7  8  6 10
## 
## [[4]]
## [1]  5  8  4  7 10

5 some() và every()

Kiểm tra tất cả các phần tử với cùng 1 điều kiện

x <- list(1:5, letters, list(10))
x %>% some(is_character)
## [1] TRUE
x %>% every(is_vector)
## [1] TRUE

6 detect() và dectect_index()

x <- sample(10)
x
##  [1]  8  5 10  3  1  4  7  9  2  6
x %>% detect(~ . > 5)
## [1] 8
x %>% detect_index(~ . > 5)
## [1] 1

7 reduce()

Đưa 1 list tương đối phức tạp về dạng đơn giản hơn bằng việc lặp lại hàm trong reduce với các phần tử của list

Ví dụ:

dfs <- list(
age = tibble(name = "John", age = 30),
sex = tibble(name = c("John", "Mary"), sex = c("M", "F")),
trt = tibble(name = "Mary", treatment = "A")
)

dfs %>% reduce(full_join)
## Joining, by = "name"
## Joining, by = "name"
## # A tibble: 2 x 4
##   name    age sex   treatment
##   <chr> <dbl> <chr> <chr>    
## 1 John     30 M     <NA>     
## 2 Mary     NA F     A
vs <- list(
c(1, 3, 5, 6, 10),
c(1, 2, 3, 7, 8, 10),
c(1, 2, 3, 4, 8, 9, 10)
)
vs %>% reduce(intersect)
## [1]  1  3 10

8 accumulate()

Cho ra kết quả của từng bước reduce

x <- sample(10)

x %>% accumulate(`+`)
##  [1]  7 12 22 25 33 39 43 45 54 55
x %>% reduce(`+`)
## [1] 55
LS0tCnRpdGxlOiAiSMaw4bubbmcgZOG6q24gc+G7rSBk4bulbmcgcHVycnIgcGFja2FnZSBwYXJ0IDQiCmF1dGhvcjogIk5ndXnhu4VuIE5n4buNYyBCw6xuaCIKZGF0ZTogIjE0IEFwciAyMDE5IgpvdXRwdXQ6CiAgIGh0bWxfZG9jdW1lbnQ6IAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgIyBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0aGVtZTogImRlZmF1bHQiCiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQogICAgZGV2OiAnc3ZnJwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCgpgYGAKCj4gVHJvbmcgbeG7l2kgY2jDum5nIHRhIMSR4buBdSBjw7MgbeG7mXQgdGhpw6puIHTDoGkgxJFhbmcgbmfhu6csIGNo4buJIGPDsyDEkWnhu4F1IGPDoG5nIG5nw6B5IGFuaCB0YSBuZ+G7pyBjw6BuZyBzYXkKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKCiMgR2nhu5tpIHRoaeG7h3UKCk5oYW5oIHF1w6EhIHB1cnJyIGPFqW5nIGtow7RuZyBjw7MgcXXDoSBuaGnhu4F1IHRo4bupIMSR4buDIGjhu41jIG5oxrBuZyBtw6AgY8OgbmcgaOG7jWMgY8Ogbmcgc+G7oyBuaGFuaCBo4bq/dCwgbcOgIHF1YW4gdHLhu41uZyBoxqFuIGPDoG5nIMSR4buNYyBjw6BuZyB0aOG6pXkgaGF5CgpUcm9uZyBwaOG6p24gbsOgeSB0aeG6v3AgdOG7pWMgZ2nhu5tpIHRoaeG7h3UgMSBz4buRIHRp4buHbiDDrWNoIGPhu6dhIHB1cnJyCgojIGludm9rZV9tYXAoKQoKQ8O6IHBow6FwOgoKPiBpbnZva2VfbWFwKC5mLCAueCA9IGxpc3QoTlVMTCksIC4uLiwgLmVudiA9IE5VTEwpCgpM4bqleSDDvSB0xrDhu59uZyB04burIGjDoG0gZG8uY2FsbCBuaMawbmcgxJHGsOG7o2Mgdmnhur90IGzhuqFpIGThu4Ugc+G7rSBk4bulbmcgaMahbiB24bubaSBwaXBlLiBpbnZva2VfbWFwKCkgbMOgbSB2aeG7h2MgduG7m2kgMSBsaXN0IGPDoWMgaMOgbSAoaW52b2tlIGNo4buJIGzDoG0gduG7m2kgMSBow6BtKQoKVsOtIGThu6U6CgotIFbhu5tpIG5oaeG7gXUgaMOgbSBjw7MgY8O5bmcgb2JqZWN0IG5oxrAgbmhhdSAoxJHhu4F1IGPDsyDEkeG6p3UgdsOgbyBsw6AgbikKYGBge3J9Cmludm9rZV9tYXAobGlzdChydW5pZiwgcm5vcm0pLCBuID0gNSkKYGBgCgotIFbhu5tpIDEgaMOgbSBsaXN0IGFyZ3VtZW50IMSR4bqndSB0acOqbgpgYGB7cn0Kc2V0LnNlZWQoMTU4KQppbnZva2VfbWFwKCJydW5pZiIsIGxpc3QoNSwgMTApKSAjIGludm9rZV9tYXAoInJ1bmlmIiwgbGlzdChsaXN0KG4gPSA1KSwgbGlzdChuID0gMTApKSkKYGBgCgotIE5oaeG7gXUgaMOgbSwgbmhp4buBdSBhZ3J1bWVudCBraMOhYyBuaGF1CmBgYHtyfQpmIDwtIGMoInJ1bmlmIiwgInJub3JtIiwgInJwb2lzIikKcGFyYW0gPC0gbGlzdCgKICAgIGxpc3QobWluID0gLTEsIG1heCA9IDEpLAogICAgbGlzdChzZCA9IDUpLAogICAgbGlzdChsYW1iZGEgPSAxMCkKKQoKaW52b2tlX21hcChmLCBwYXJhbSwgbiA9IDUpICU+JSBzdHIoKQpgYGAKCi0gU+G7rSBk4bulbmcgduG7m2kgdG/DoW4gdOG7rSBwaXBlCmBgYHtyfQpsaXN0KG0xID0gbWVhbiwgbTIgPSBtZWRpYW4pICU+JSBpbnZva2VfbWFwKHggPSByY2F1Y2h5KDEwMCkpCmBgYAoKCiMgcHdhbGsoKQoKSMOgbSBwd2FsaygpIHTGsMahbmcgdOG7sSBuaMawIGPDoWMgaMOgbSBtYXAgbmjGsG5nIGtow7RuZyB0cuG6oyB24buBIGdpw6EgdHLhu4ssIGNo4buJIHRo4buxYyBoaeG7h24gaMOgbQoKYGBge3J9CnBsb3RzIDwtIG10Y2FycyAlPiUKICBzcGxpdCguJGN5bCkgJT4lCiAgbWFwKH5nZ3Bsb3QoLiwgYWVzKG1wZywgd3QpKSArIGdlb21fcG9pbnQoKSkKCnBhdGhzIDwtIHN0cmluZ3I6OnN0cl9jKG5hbWVzKHBsb3RzKSwgIi5wZGYiKQoKcHdhbGsobGlzdChwYXRocywgcGxvdHMpLCBnZ3NhdmUsIHBhdGggPSB0ZW1wZGlyKCkpCmBgYAoKCiMga2VlcCgpIHbDoCBkaXNjYXJkKCkKCmzDoCAxIGThuqFuZyBsb29wIG5oxrAgbWFwLCBnaeG7ryBob+G6t2MgbG/huqFpIGLhu48gcGjhuqduIHThu60gbuG6v3UgdGjhu49hIMSRaeG7gXUga2nhu4duCgpgYGB7cn0KaXJpcyAlPiUga2VlcChpcy5mYWN0b3IpICU+JSBzdHIoKQpgYGAKCmBgYHtyfQppcmlzICU+JSBkaXNjYXJkKGlzLmZhY3RvcikgJT4lIHN0cigpCmBgYAoKYGBge3J9CnJlcCgxMCwgMTApICU+JQogIG1hcChzYW1wbGUsIDUpICU+JQogIGtlZXAofiBtZWFuKC54KSA+IDYpCmBgYAoKIyBzb21lKCkgdsOgIGV2ZXJ5KCkKCktp4buDbSB0cmEgdOG6pXQgY+G6oyBjw6FjIHBo4bqnbiB04butIHbhu5tpIGPDuW5nIDEgxJFp4buBdSBraeG7h24KCmBgYHtyfQp4IDwtIGxpc3QoMTo1LCBsZXR0ZXJzLCBsaXN0KDEwKSkKeCAlPiUgc29tZShpc19jaGFyYWN0ZXIpCgp4ICU+JSBldmVyeShpc192ZWN0b3IpCmBgYAoKIyBkZXRlY3QoKSB2w6AgZGVjdGVjdF9pbmRleCgpCmBgYHtyfQp4IDwtIHNhbXBsZSgxMCkKeAoKeCAlPiUgZGV0ZWN0KH4gLiA+IDUpCgp4ICU+JSBkZXRlY3RfaW5kZXgofiAuID4gNSkKYGBgCgoKIyByZWR1Y2UoKQoKxJDGsGEgMSBsaXN0IHTGsMahbmcgxJHhu5FpIHBo4bupYyB04bqhcCB24buBIGThuqFuZyDEkcahbiBnaeG6o24gaMahbiBi4bqxbmcgdmnhu4djIGzhurdwIGzhuqFpIGjDoG0gdHJvbmcgcmVkdWNlIHbhu5tpIGPDoWMgcGjhuqduIHThu60gY+G7p2EgbGlzdAoKVsOtIGThu6U6CgpgYGB7cn0KZGZzIDwtIGxpc3QoCmFnZSA9IHRpYmJsZShuYW1lID0gIkpvaG4iLCBhZ2UgPSAzMCksCnNleCA9IHRpYmJsZShuYW1lID0gYygiSm9obiIsICJNYXJ5IiksIHNleCA9IGMoIk0iLCAiRiIpKSwKdHJ0ID0gdGliYmxlKG5hbWUgPSAiTWFyeSIsIHRyZWF0bWVudCA9ICJBIikKKQoKZGZzICU+JSByZWR1Y2UoZnVsbF9qb2luKQpgYGAKCmBgYHtyfQp2cyA8LSBsaXN0KApjKDEsIDMsIDUsIDYsIDEwKSwKYygxLCAyLCAzLCA3LCA4LCAxMCksCmMoMSwgMiwgMywgNCwgOCwgOSwgMTApCikKdnMgJT4lIHJlZHVjZShpbnRlcnNlY3QpCmBgYAoKIyBhY2N1bXVsYXRlKCkKCkNobyByYSBr4bq/dCBxdeG6oyBj4bunYSB04burbmcgYsaw4bubYyByZWR1Y2UKCmBgYHtyfQp4IDwtIHNhbXBsZSgxMCkKCnggJT4lIGFjY3VtdWxhdGUoYCtgKQp4ICU+JSByZWR1Y2UoYCtgKQpgYGAKCg==