2017-05-07 69 views
1

我想執行下面的dplyr任務,但在一個函數內。函數與dplyr與兩個變量

library("dplyr") 

iris %>% 
    group_by(Species) %>% 
    summarise(N = sum(Petal.Width == 0.2, na.rm = T)) 

我正在考慮以下內容,因爲我對語法不清楚,所以我並不完整。

getSummary <- function(varName,level) { 
    summary <- iris %>% 
     group_by(Species %>% 
     summarise_(N = interp(~sum(var == ilevel, na.rm = T), 
        var = as.name(varName)))) 
    sums <- summary$N  
} 

在這種情況下,水平是數字0.2。如果值是字符「0.2」,是否有任何更改?

+0

你的函數參數是'level',但是你在'summarise'中使用'ilevel'? – neilfws

+0

你錯過了'group_by'的括號,你需要返回'summary'或者不要將它作爲變量存儲在第一位。 – alistaire

回答

3

dplyr正在從lazyeval驅動的NSE系統切換到an rlang-powered one。在(現已通過the GitHub version,並很快通過CRAN)的新版本,你可以使用

library(dplyr) 

getSummary <- function(varName, level) { 
    varName <- enquo(varName) # parse and quote variable name 
    iris %>% 
     group_by(Species) %>% 
     summarise(N = sum((!!varName) == level), # unquote with !! to use 
        var = rlang::quo_text(varName)) # turn quosure to string 
} 

getSummary(Petal.Width, 0.2) 
#> # A tibble: 3 × 3 
#>  Species  N   var 
#>  <fctr> <int>  <chr> 
#> 1  setosa 29 Petal.Width 
#> 2 versicolor  0 Petal.Width 
#> 3 virginica  0 Petal.Width 

# or make it accept strings 
getSummary <- function(varName, level) { 
    iris %>% 
     group_by(Species) %>% 
     summarise(N = sum((!!rlang::sym(varName)) == level), 
        var = varName) 
} 

getSummary('Sepal.Length', 5.0) 
#> # A tibble: 3 × 3 
#>  Species  N   var 
#>  <fctr> <int>  <chr> 
#> 1  setosa  8 Sepal.Length 
#> 2 versicolor  2 Sepal.Length 
#> 3 virginica  0 Sepal.Length 

要使用舊lazyeval語法,它看起來像

getSummary <- function(varName, level) { 
    iris %>% 
     group_by(Species) %>% 
     summarise_(N = lazyeval::interp(~sum(x == y), # formula to substitute into 
             x = lazyeval::lazy(varName), # substituted but unevaluated name 
             y = level), # value to substitute 
        var = ~lazyeval::expr_text(varName)) # convert expression to string (equivalent to `deparse(substitute(...))`) 
} 

getSummary(Sepal.Length, 5.0) 
#> # A tibble: 3 × 3 
#>  Species  N   var 
#>  <fctr> <int>  <chr> 
#> 1  setosa  8 Sepal.Length 
#> 2 versicolor  2 Sepal.Length 
#> 3 virginica  0 Sepal.Length 

# or make it accept strings 
getSummary <- function(varName, level) { 
    iris %>% 
     group_by(Species) %>% 
     summarise_(N = lazyeval::interp(~sum(x == y), 
             x = as.name(varName), 
             y = level), 
        var = ~varName) 
} 

getSummary('Petal.Width', 0.2) 
#> # A tibble: 3 × 3 
#>  Species  N   var 
#>  <fctr> <int>  <chr> 
#> 1  setosa 29 Petal.Width 
#> 2 versicolor  0 Petal.Width 
#> 3 virginica  0 Petal.Width 
+0

謝謝。關於在我原來的問題中獲取語法的任何建議。我不確定如何爲varName和level指定類似「as.name」的內容。 – julieth

+0

解讀lazyeval在這一點上的工作方式並沒有太多意義,但我編輯了它的樣子。 [這是舊的小插曲](https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html),這個解釋了一下。最重要的是,所有事情都必須以公式或其他方式引用,並且實際上以字符串結尾,您需要引用字符串。 – alistaire

+0

...並澄清,如果您傳遞的是變量字符串而不是未加引號的表達式,則可能需要'as.name'。 rlang相當於'rlang :: sym'。 – alistaire