R 的 magrittr
套件提供了一個管線運算子,可以讓函數或運算式串聯在一起,以資料流的方式處理資料的傳遞。
在 Unix/Linux 系統上的各種指令都可以運用管線(pipe)的方式串接起來使用,以資料流的方式來處理各種資料,使用管線並不會改變程式實際執行的動作,主要的差異只在於讓程式碼更容易被撰寫與閱讀。
而在 R 中我們則可以使用 magrittr
套件來達到相同的效果,以下介紹 R 傳統的程式撰寫方式以及改用此套件後的寫法。
若要計算 LogSumExp 函數,以傳統的作法是這樣寫:
log(sum(exp(my.var)), exp(1))
這樣的寫法會讓許多函數與小括號擠在一起,造成程式碼不好閱讀,為了讓程式碼看起來更清晰,有些人會喜歡改成這樣的寫法:
my.var <- exp(my.var) my.var <- sum(my.var) log(my.var, exp(1))
這種寫法雖然可讓程式碼的邏輯很清楚的呈現出來,但是缺點就是 my.var
這個字眼重複出現好幾次。
以上兩種寫法各有優缺點,傳統的 R 語言寫法只能從兩者之間擇一使用,而後來新的 magrittr
套件結合上述兩種寫法的優點,提供了一種嶄新的簡潔語法。
magrittr
套件導入一種管線(pipe)的語法,以串流的方式來處理資料的運算,讓程式碼更簡潔、語意更清楚。以下是 magrittr
套件的使用方式教學與範例。
首先安裝並載入 magrittr
套件:
install.packages("magrittr") library(magrittr)
%>%
管線運算子magrittr
套件中最重要的功能就是 %>%
管線運算子,它的作用在於將左側的運算結果傳遞至右側函數的第一個參數,舉例來說,假側我們有一個傳統的 R 運算式如下:
exp(my.var)
這個運算式是將 my.var
傳遞至 exp
函數中進行冪運算,若以 %>%
管線運算子的方式,則可以改寫為:
my.var %>% exp()
在包含 %>%
的運算式中,若一個函數沒有其餘的參數,也可以將小括號省略,簡寫成這樣:
my.var %>% exp
這樣的寫法可以將許多層函數包裹在一起的運算拆解開來,以上述的 LogSumExp 函數來說,用 %>%
管線運算子改寫之後就會變成這樣:
my.var %>% exp %>% sum %>% log(exp(1))
預設的狀況下,%>%
管線運算子會將資料傳遞至右側函數的第一個參數,如果需要改變參數的位置,可以使用句點 .
的方式指定資料安插的位置。以下是拿 iris
這個鳶尾花資料集做簡單線性迴歸模型的例子:
iris.lm <- lm(Sepal.Length ~ Sepal.Width, data = iris) summary(iris.lm)
我們可以使用 %>%
管線運算子配合句點 .
將其改寫成:
iris %>% lm(Sepal.Length ~ Sepal.Width, data = .) %>% summary
第一個 %>%
管線運算子會將 iris
安插在 lm
參數列中句點出現的位置,所以執行起來的效果就跟原來的程式一模一樣。
%$%
運算子R 的許多函數都會使用 data
參數來指定資料來源的 data frame,然後在函數中取用該 data frame 中的變數,而 %$%
運算子可以讓其左方的物件套用至右方函數的 data
參數中,例如:
iris %$% lm(Sepal.Length ~ Sepal.Width) %>% summary
這樣的用法跟上面 %>%
管線運算子配合句點 .
的方式類似,不過可讓程式碼更簡潔。
這是另外一個計算相關係數的例子:
mtcars %$% cor(disp, mpg)
%<>%
運算子%<>%
運算子除了具有 %>%
管線運算子的串接功能之外,還可以將其右方的運算結果儲存至左方的變數中。
假設我們想要讓一個變數進行一連串的運算後,再將結果儲存回原來的變數中,典型的寫法大概是像這樣:
set.seed(3) x <- rnorm(5) x <- x %>% abs %>% sqrt
這種情況我們就可以用 %<>%
運算子將上面的程式碼改寫為:
set.seed(3) x <- rnorm(5) x %<>% abs %>% sqrt
%T>%
tee 運算子%T>%
運算子的功能也是類似 %>%
管線運算子,只不過在運算完成後,它會傳回原本其左方的輸入值,而不是最終右方運算式計算完的結果。
假設我們產生了一個含有兩個行(column)的矩陣,想要將資料畫出來,並且同時也計算出兩行數值的總和,一般普通的寫法會像這樣:
set.seed(3) x <- matrix(rnorm(200), ncol = 2) plot(x) colSums(x)
這裡的資料流結構跟前面的狀況不太一樣,第二行所建立的 x
同時傳給第三行與第四行來使用,這種將資料一分為二的情況就要使用 %T>%
tee 運算子來處理,經過 %T>%
改寫後就會變成:
set.seed(3) rnorm(200) %>% matrix(ncol = 2) %T>% plot %>% colSums
這裡使用 %T>%
的效果就是會讓 matrix
的計算結果同時傳給 plot
與 colSums
兩個數,達到預期的計算結果。