2016-03-22 32 views
9

我經常需要在另一個函數中創建一個函數調用,然後再對其進行評估。因此我傾向於使用eval(parse(text = "what_needs_to_be_done")) ,並使用paste0()構建文本。但是,這不是一個好的方法。下面是一個例子:R:以編程方式創建函數調用

select_data <- function(x, A = NULL, B = NULL, C = NULL) { 
    kall <- as.list(match.call()) 
    vars <- names(kall)[names(kall) %in% c("A", "B", "C")] 
    selection_criteria <- paste0(vars, " == ", kall[vars], collapse = ", ") 
    txt <- paste0("dplyr::filter(x, ", selection_criteria, ")") 
    res <- eval(parse(text = txt)) 
    return(res) 
} 

DF <- data.frame(A = c(1,1,2,2,3,3), B = c(1,2,1,2,1,2), C = c(1,1,1,2,2,2)) 
select_data(DF, A = 2, C = 2) 

這僅僅是一個示例,在大多數情況下,可以構成功能更復雜和廣泛。但是,該示例顯示了一般問題。我現在所做的第一件事情是將paste0與函數調用結合起來,這樣我就可以在控制檯輸入它,然後對它進行評估。

我已經篡改了替代方法substitute,lazyeval,bquote,但我不太明白他們真正做了什麼,因此無法讓他們工作。

你能幫我找到一個更好的方法來構建調用,然後評估它嗎?

+0

這裏是鏈接到其他有同樣類型的問題[Dplyr編程(HTTP掙扎://計算器。(非標準評估)(http://stackoverflow.com/questions/26492280/non-standard-questions/36139624/dplyr-filter-where-two-columns-in-data-frame-are-equal)評價-NSE-在-dplyrs濾波器拉取數據從MySQL的)。也有作者https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html這個小插曲。 –

回答

9

更新4.29.17 - 即將發佈dplyr 0.6.0將解決這些問題。新的答案已被添加到下面的問題。有關使用dplyr編程的更多信息,請參閱see this vignette


您有正確的想法。您可以縮短代碼一點與?filter_和點的說法...

select_data <- function(x, ...) { 
    kall <- list(...) 
    filter_(.data=x, paste0(names(kall), "==", unlist(kall), collapse="&")) 
} 
select_data(DF, A = 2, C = 2) 
# A B C 
# 1 2 2 2 

更新

編程與dplyr甚至可以中級程序員非常具有挑戰性。作者承認,非標準評估的優勢與功能性編程的難度相關。有運行到同樣的問題,一些SO用戶:

standard evaluation in dplyr

dplyr function does not work

Using dplyr functions within another function

Major dplyr functions in a function Pass arguments to dplyr functions

dplyr: filter where two columns in data.frame are equal

聖已採取eps解決這些問題。有一個vignette to outline the basic fixes。然而,在我看來,小插曲對函數式編程的解釋是不夠的。沒有一個函數被寫爲例子。它也沒有涉及通常出現的任何混雜的例子。希望隨着NSE修復電話的增加,我們最終可能會得到足夠的迴應。

作爲非標準評估可能導致編程混亂的最後一個例子,我試圖爲這個用戶解決方案一段時間沒有用。很簡單,就是要求使用summarise編程:

Sub-function in grouping function using dplyr