Cách sử dụng các toán tử pipes trong R

Sự ra đời của các toán tử pipes trong package magrittr đã tạo ra những thay đổi lớn mang tính cách mạng cho ngôn ngữ R. Biết cách sử dụng linh hoạt các toán tử này chính là chìa khóa để rút ngắn thời gian viết code cũng như giúp cho code dễ đọc và dễ bảo trì hơn.

Ở bài này tôi note lại cách dùng của 4 toán tử pipes cho bạn nào cần:

  • %>% : Forward-pipe operator

  • %<>% : Compound assignment pipe-operator

  • %T>% : Tee Operator

  • %$% : Exposition pipe-operator

Mục đích của việc sử dụng các toán tử pipes trong R:

  • Tránh gọi lồng các hàm

  • Giảm việc tạo và sử dụng các biến trung gian

  • Tổ chức tập hợp các câu lệnh thành một chuỗi thống nhất, dễ hiểu.

Nạp các thư viện cần thiết vào phiên làm việc của R để thực hành:

library(tidyverse)
library(magrittr)

Chú ý: Khi nạp gói tidyverse thì pipe %>% được nạp tự động, tuy nhiên để dùng các toán từ khác thì chúng ta cần nạp thêm cả gói magrittr.

1. Toán tử %>% (forward-pipe operator)

Đây là pipe được sử dụng nhiều nhất trong R, hầu như mỗi công việc thực hiện trên R tôi đều sử dụng nó rất nhiều lần.

Nguyên lý của pipe %>%: chuyển toàn bộ vế bên trái (có thể là kết quả của hàm đi trước) thành dữ liệu đầu vào cho hàm bên phải tạo thành một dòng chảy dữ liệu từ trái qua phải.

Ví dụ với tập dữ liệu diamonds:

head(diamonds)
## # A tibble: 6 x 10
##   carat cut       color clarity depth table price     x     y     z
##   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.23  Ideal     E     SI2      61.5    55   326  3.95  3.98  2.43
## 2 0.21  Premium   E     SI1      59.8    61   326  3.89  3.84  2.31
## 3 0.23  Good      E     VS1      56.9    65   327  4.05  4.07  2.31
## 4 0.290 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63
## 5 0.31  Good      J     SI2      63.3    58   335  4.34  4.35  2.75
## 6 0.24  Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48
diamonds %>%
  filter(color == "I") %>%
  group_by(cut) %>%
  summarize(price = mean(price))
## # A tibble: 5 x 2
##   cut       price
##   <ord>     <dbl>
## 1 Fair      4685.
## 2 Good      5079.
## 3 Very Good 5256.
## 4 Premium   5946.
## 5 Ideal     4452.

Tương đương với cách truyền thống như sau:

diamonds_1 <- filter(diamonds, color == "I")
diamonds_2 <- group_by(diamonds_1, cut)
(diamonds_3 <- summarize(diamonds_2, price = mean(price)))
## # A tibble: 5 x 2
##   cut       price
##   <ord>     <dbl>
## 1 Fair      4685.
## 2 Good      5079.
## 3 Very Good 5256.
## 4 Premium   5946.
## 5 Ideal     4452.

2. Toán tử %<>% (compound assignment pipe-operator)

Nguyên lý của pipe %<>%: Thực hiện nhiệm vụ tương tự như với toán tử %>%, tuy nhiên kết quả cuối cùng của dòng chảy dữ liệu được gán lại vào đối tượng ban đầu của dòng chảy.

Ví dụ:

diamonds %<>%
  filter(color == "I") %>% select(carat, cut, color)
diamonds
## # A tibble: 5,422 x 3
##    carat cut       color
##    <dbl> <ord>     <ord>
##  1 0.290 Premium   I    
##  2 0.24  Very Good I    
##  3 0.3   Ideal     I    
##  4 0.3   Good      I    
##  5 0.24  Premium   I    
##  6 0.33  Ideal     I    
##  7 0.33  Ideal     I    
##  8 0.32  Ideal     I    
##  9 0.3   Ideal     I    
## 10 0.3   Very Good I    
## # ... with 5,412 more rows

3. Toán tử %T% (Tee Operator)

Nguyên lý của pipe %T>%: Dòng chảy dữ liệu trong toán tử này có thể được hình dung tương tự như ống nước hình chữ T. Dữ liệu đầu vào của 1 hàm đi trước sẽ được truyền cho 2 nhánh tương ứng cho hai hàm phía sau

Ví dụ:

rnorm(200) %>%
    matrix(ncol = 2) %T>%
    plot %>%
    colSums

## [1] -10.96542 -12.71731

Tương đương với:

rnorm(200) %>%
    matrix(ncol = 2) %>%
    { plot(.); . } %>%
    colSums

## [1] -10.652905   2.284913

Hoặc viết theo cách truyền thống:

m <- matrix(rnorm(200), ncol = 2)
plot(m)

colSums(m)
## [1] -27.205778  -2.992818

4. Toán tử %$% (exposition pipe-operator)

Nguyên lý của pipe %$%: Toán tử cho phép trích xuất đích danh một đối tượng trong kết quả của hàm đi trước để sử dụng như dữ liệu đầu vào cho hàm đi sau.

Ví dụ:

iris %>%
    subset(Sepal.Length > mean(Sepal.Length)) %$%
    cor(Sepal.Length, Sepal.Width)
## [1] 0.3361992

Tương đương với việc sử dụng hàm with():

with(subset(iris, Sepal.Length > mean(Sepal.Length)),
     cor(Sepal.Length, Sepal.Width))
## [1] 0.3361992
Cuong Sai
Cuong Sai
PhD student

My research interests include Industrial AI (Intelligent predictive maintenance), Machine and Deep learning, Time series forecasting, Intelligent machinery fault diagnosis, Prognostics and health management, Error metrics / forecast evaluation.

comments powered by Disqus

Related