Hay hỏi thì biết rộng, tự dụng thì hẹp hòi
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()
library(broom)
Trong phần này tiếp tục giới thiệu 1 số hàm của purrr dùng để kiểm soát lỗi của hàm. Khi sử dụng hàm map để chạy các vòng lặp, khả năng mắc lỗi trong các hàm là rất cao, nhiều trường hợp nằm ngoài tính toán của người viết. Khi đó, chúng ta cần phải biết vì sao phần lớn cho kết quả đúng, nhưng một số trường hợp gặp lỗi.
Cho kết quả là 1 list gồm 2 phần tử
result: Trả về kết quả của hàm. Nếu gặp lỗi thì = NULL
error : Trả về lỗi của object. Nếu không gặp lỗi thì = NULL
(hàm safely tương tự với hàm try của gói base)
Ví dụ với hàm log
safe_log <- safely(log)
str(safe_log(10))
## List of 2
## $ result: num 2.3
## $ error : NULL
str(safe_log("a"))
## List of 2
## $ result: NULL
## $ error :List of 2
## ..$ message: chr "non-numeric argument to mathematical function"
## ..$ call : language .Primitive("log")(x, base)
## ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
Thiết kế của hàm safely được sử dụng tốt với hàm map
x <- list(1, 10, "a")
y <- x %>% map(safely(log))
str(y)
## List of 3
## $ :List of 2
## ..$ result: num 0
## ..$ error : NULL
## $ :List of 2
## ..$ result: num 2.3
## ..$ error : NULL
## $ :List of 2
## ..$ result: NULL
## ..$ error :List of 2
## .. ..$ message: chr "non-numeric argument to mathematical function"
## .. ..$ call : language .Primitive("log")(x, base)
## .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
Kết hợp với hàm purrr:transpose sẽ tách được riêng list thành 2 phần: 1 phần result và 1 phần là error
y <- y %>% transpose()
str(y)
## List of 2
## $ result:List of 3
## ..$ : num 0
## ..$ : num 2.3
## ..$ : NULL
## $ error :List of 3
## ..$ : NULL
## ..$ : NULL
## ..$ :List of 2
## .. ..$ message: chr "non-numeric argument to mathematical function"
## .. ..$ call : language .Primitive("log")(x, base)
## .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
Đầu ra của result và error
is_ok <- y$error %>% map_lgl(is_null)
x[!is_ok]
## [[1]]
## [1] "a"
y$result[is_ok] %>% flatten_dbl() # flatten_ tương tự với hàm unlist
## [1] 0.000000 2.302585
Tương tự với hàm safely() luôn cho kết quả succeed. Nhưng hàm này đơn giản hơn safely() vì nó cho phép gán giá trị default khi gặp lỗi
x <- list(1, 10, "a")
x %>% map_dbl(possibly(log, NA_real_))
## [1] 0.000000 2.302585 NA
Tương tự như safely() nhưng thay vì đầu ra là error, hàm này cho ra output, messages và warnings
x <- list(1, -1)
x %>% map(quietly(log)) %>% str()
## List of 2
## $ :List of 4
## ..$ result : num 0
## ..$ output : chr ""
## ..$ warnings: chr(0)
## ..$ messages: chr(0)
## $ :List of 4
## ..$ result : num NaN
## ..$ output : chr ""
## ..$ warnings: chr "NaNs produced"
## ..$ messages: chr(0)
Chú ý: Các hàm bắt lỗi khác với các hàm thông thường ở chỗ: hàm thông thường ~ verb, còn các hàm này ~ adverb. Tức là chỉ ra cách thức thực hiện các hàm thông thường