可以使用非标准评估在dplyr中使用filter_和count_但不是不同_

时间:2016-12-16 17:09:22

标签: r dplyr

我正在尝试编写一个使用dplyr来计算z的所有唯一值的函数。当我将变量实际命名为z时,我的函数工作正常。但是,如果变量名为x,则会出现错误(代码下方)。

test.data<-data.frame(y=c(1:10),
                  x=c(letters[1:10]))
test.data$x<-as.character(test.data$x)
obsfunction<-function(z,y,data){
filter_(data,
          !is.na(deparse(substitute(y))))%>%
    distinct_(., deparse(substitute(z)))%>% #the line that breaks it
    count_(.)
}
obsfunction(z=x,y,data=test.data)

所以,上面的代码不起作用并给出了这个错误:

 >Error in eval(substitute(expr), envir, enclos) : unknown column 'z'

在函数中将z更改为x(或将x重命名为z)使其工作,但我不想重命名所有内容,特别是考虑到y使用不同的名称。

我已根据vignettethis questionthis question尝试了lazyeval :: interp和quote()。

distinct_(lazyeval::interp(as.name(z)))%>%
>Error in as.name(z) : object 'x' not found 

distinct_(quote(z))%>%
>Error in eval(substitute(expr), envir, enclos) : unknown column 'z' 

我错过了什么?如何让z接受x作为列名?

3 个答案:

答案 0 :(得分:3)

由于dplyr标准评估了解字符串,我尝试了以下代码并附加了测试数据,看起来很有用。我首先提取变量名,然后使用字符串构造表达式:

<!DOCTYPE html>
<html>
<head>
<title>Counter File</title>

</head>

<body>
    ID Number: <input type="text" name="IDNumb" id="IDNumb">
</body>

<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script>
    $("input").on("keydown", function (e) 
    {
        return e.which !== 32;
    }); 
</script>  
</html>

答案 1 :(得分:2)

您可以使用match.call捕获函数参数并在传递给 dplyr SE函数之前将它们转换为字符:

obsfunction<-function(z, y, data){
    cl = match.call()
    y = as.character(cl['y'])
    z = as.character(cl['z'])

    data %>% filter_(paste('!is.na(', y, ')', sep = '')) %>%
             distinct_(z) %>%
             count_(.)
}

obsfunction(z = x, y = y, data = test.data)

# A tibble: 1 × 1
#      n
#  <int>
#1    10

obsfunction(x, y, test.data)

# A tibble: 1 × 1
#      n
#  <int>
#1    10

答案 2 :(得分:1)

另一个lazyeval/dplyr变体,其中变量作为公式传递,f_interpuq(x)替换为传递给它的公式,类似于deparse(substitute(x))

library(dplyr)
library(lazyeval)

test.data<-data.frame(y=c(1:10),
                  x=c(letters[1:10]))
test.data$x<-as.character(test.data$x)


obsfunction<-function(z, y, data){
  data %>% filter_(f_interp(~!is.na(uq(y)))) %>%
    distinct_(f_interp(~uq(z))) %>% count()
}

obsfunction(z=~x,~y,data=test.data)

 #A tibble: 1 × 1
 #     n
 #  <int>
 #1    10

test.data.NA <- data.frame(
  y=c(1:4, NA, NA, 7:10),
  x=c(letters[c(1:8, 8, 8)]),
  stringsAsFactors = FALSE)


obsfunction(z=~x,~y,data=test.data.NA)
 # # A tibble: 1 × 1
 #        n
 #      <int>
 # 1      6