2015-10-01 50 views
3

我想使用mutate_()創建多個列,其中每個列都基於使用不同輸入調用的自定義函數。我可以使用paste()創建多個帶引號的函數調用,但這不起作用,因爲dplyr的NSE需要公式(〜)而不是帶引號的字符串才能找到該函數。我該如何寫下面的「dots =」這一行,以便找到該功能?我試着用〜,as.formula()和lazyeval :: interp()來試驗,但沒有任何工作。我的實際「前綴」是一個長向量,所以我不想單獨寫出每個新列的函數調用。由於使用dplyr非標準評估創建多個函數

library(dplyr) 
library(lazyeval) 
library(nycflights13) 

myfunc = function(x, y) { x - y } 

# this works 
flights1 <- mutate(flights, dep_time_sched = myfunc(dep_time, dep_delay), 
          arr_time_sched = myfunc(arr_time, arr_delay)) 

# this doesn't - Error: could not find function "myfunc" 
prefixes <- c('dep', 'arr') 
dots = as.list(paste0('myfunc(', 
         paste0(prefixes, '_time'), ', ', 
         paste0(prefixes, '_delay)'))) 
flights2 <- mutate_(flights, .dots = setNames(dots, paste0(prefixes, '_time_sched'))) 

回答

5

您可以通過使用interplapply通過您的前綴所需格式爲mutate_接近這個循環,並得到一個列表。

dots = lapply(prefixes, function(var) interp(~myfunc(x, y), 
             .values = list(x = as.name(paste0(var, "_time")), 
                y = as.name(paste0(var, "_delay"))))) 
    dots 

[[1]] 
~myfunc(dep_time, dep_delay) 
<environment: 0x0000000019e51f00> 

[[2]] 
~myfunc(arr_time, arr_delay) 
<environment: 0x0000000019f1e5b0> 

這給出了與您的flights1相同的結果。

flights2 = mutate_(flights, .dots = setNames(dots, paste0(prefixes, '_time_sched'))) 
identical(flights1, flights2) 
[1] TRUE 
3

我實際的「前綴」是一個漫長的載體,所以我不想單獨寫出來供每個新列的函數調用。

如果是這樣的話,您應該真正將您的數據轉換爲長格式。爲了澄清我的意思,讓我們來看看一個小例子:

mydat <- flights[1:5, c(paste0(prefixes,"_time"), paste0(prefixes,"_delay"))] 
# dep_time arr_time dep_delay arr_delay 
#  (int) (int)  (dbl)  (dbl) 
# 1  517  830   2  11 
# 2  533  850   4  20 
# 3  542  923   2  33 
# 4  544  1004  -1  -18 
# 5  554  812  -6  -25 

library(data.table) 

longdat <- setDT(mydat)[, .( 
    pref = rep(prefixes, each=.N), 
    time = unlist(mget(paste0(prefixes,"_time"))), 
    delay = unlist(mget(paste0(prefixes,"_delay"))) 
)] 

longdat[, time_sched := myfunc(time, delay) ] 
#  pref time delay time_sched 
# 1: dep_ 517  2  515 
# 2: dep_ 533  4  529 
# 3: dep_ 542  2  540 
# 4: dep_ 544 -1  545 
# 5: dep_ 554 -6  560 
# 6: arr_ 830 11  819 
# 7: arr_ 850 20  830 
# 8: arr_ 923 33  890 
# 9: arr_ 1004 -18  1022 
# 10: arr_ 812 -25  837 

除了是簡單,調用函數一個單一的時間採取它的矢量化的優勢。

雖然我用data.table來構造longdat,但我確定有一個工具可以在tidyr包(與dplyr配套)中執行相同的操作。同樣,time_sched列的添加僅爲mutate。重塑由於@akrun的


替代方式,這裏是另一種方式去longdat,使用melt函數的語法,將在data.table的下一個版本(1.9.8可用,沒有公佈尚):

longdat <- melt(mydat, 
    measure  = patterns('time$','delay$'), 
    variable.name = "pref", 
    value.name  = c('time', 'delay') 
)[, pref := prefixes[pref]] 

或者,還得益於@akrun,這裏是一個方式來重塑自動構建的前綴,給出的後綴(timedelay),使用@ AnandaMahto的splitstackshape包:

library(splitstackshape) 
longdat <- merged.stack(transform(mydat, ind=1:nrow(mydat)), 
    var.stubs = c('_time', '_delay'), 
    sep = 'var.stubs', 
    atStart = FALSE) 
+1

再次感謝@akrun。我已經添加了它。 – Frank

相關問題