2017-07-17 136 views
3

從(1)速度的角度來說,有沒有在R函數內部使用magrittr管是不利的情況,以及(2)有效調試的能力?R函數中的Magrittr管

+1

您是否問過關於開發時間的執行速度或速度? – Dason

+1

無論哪種方式,有些人會問你是否有任何情況下使用magrittr管道在速度或調試能力方面是有利的... – Dason

+0

要回答這個問題的唯一方法是設置幾個示例並對其進行基準測試。你有嘗試過嗎? –

回答

4

在功能中使用管道有優點和缺點。最大的優點是在閱讀代碼時更容易看到函數內發生了什麼。最大的缺點是錯誤信息變得難以解釋,管道破壞了R的一些評估規則。

下面是一個例子。假設我們想對mtcars數據集進行無意義的轉換。下面是我們如何能做到這一點與管...

library(tidyverse) 
tidy_function <- function() { 
    mtcars %>% 
    group_by(cyl) %>% 
    summarise(disp = sum(disp)) %>% 
    mutate(disp = (disp^4)/10000000000) 
} 

你可以清楚地看到發生了什麼,在每一個階段,即使它沒有做什麼有用的東西。現在,讓我們來看看使用Dagwood夾心方法的時間碼...

base_function <- function() { 
    mutate(summarise(group_by(mtcars, cyl), disp = sum(disp)), disp = (disp^5)/10000000000) 
} 

更難讀,即使它給了我們同樣的結果...

​​

的最常用的方法避免使用一個管或一個Dagwood夾心是每個步驟的結果保存到一箇中間變量...

intermediate_function <- function() { 
    x <- mtcars 
    x <- group_by(x, cyl) 
    x <- summarise(x, disp = sum(disp)) 
    mutate(x, disp = (disp^5)/10000000000) 
} 

比上次功能更多可讀和R會給你更詳細一點信息出現錯誤時。而且它遵守傳統的評估規則。再次,它給出了相同的結果,其他兩個函數...

all.equal(tidy_function(), intermediate_function()) 
# [1] TRUE 

您專門問左右的速度,所以讓我們通過運行它們中的每1000次比較這三種功能...

library(microbenchmark) 
timing <- 
    microbenchmark(tidy_function(), 
       intermediate_function(), 
       base_function(), 
       times = 1000L) 
timing 
#Unit: milliseconds 
        #expr  min  lq  mean median  uq  max neval cld 
     #tidy_function() 3.809009 4.403243 5.531429 4.800918 5.860111 23.37589 1000 a 
#intermediate_function() 3.560666 4.106216 5.154006 4.519938 5.538834 21.43292 1000 a 
     #base_function() 3.610992 4.136850 5.519869 4.583573 5.696737 203.66175 1000 a 

即使在這個微不足道的例子中,管道比其他兩個選項稍慢一點。

結論

隨意使用管道在你的函數,如果它是最舒服的方式爲你寫的代碼。如果你開始遇到問題,或者如果你需要你的代碼儘可能的快速,那麼就切換到另一個模式。

+2

您的Dagwood三明治只需要一些換行符和縮進,並且它非常易讀。 – Roland

+1

有誰知道使用管道操作員的任何軟件包?除了在腳本示例中,我還沒有看到它的使用。 – user2506086

+0

對我來說,管道似乎更接近於如何編寫指令來做某些事情,所以我希望在需要我的代碼非常易讀的情況下使用它。另一方面,我遇到了調試困難。如果您嘗試調試到管道中,則必須通過'%>%'函數進行調試,並找出要進入的線路。看起來好像是我爲其他人編寫了一個軟件包來使用它,不管我使用管道是在​​閱讀代碼的自然程度,以及調試代碼的容易程度之間取得平衡。 – user2506086