主要的dplyr函数在函数中

时间:2014-09-23 17:01:28

标签: r dplyr

我已经看过几篇关于如何使用dplyr函数编写自己的函数的帖子。例如,您可以看到如何在this post中使用group_by (regroup)summarise。我认为看看我是否可以使用主要dplyr函数编写函数会很有趣。我希望我们可以进一步了解如何使用dplyr函数编写函数。

数据

country <- rep(c("UK", "France"), each = 5)
id <- rep(letters[1:5], times = 2)
value <- runif(10, 50, 100)
foo <- data.frame(country, id, value, stringsAsFactors = FALSE)

目标

我想在函数中编写以下过程。

foo %>%
    mutate(new = ifelse(value > 60, 1, 0)) %>%
    filter(id %in% c("a", "b", "d")) %>%
    group_by(country) %>%
    summarize(whatever = sum(value))

TRY

### Here is a function which does the same process

myFun <- function(x, ana, bob, cathy) x %>%
    mutate(new = ifelse(ana > 60, 1, 0)) %>%
    filter(bob %in% c("a", "b", "d")) %>%
    regroup(as.list(cathy)) %>%
    summarize(whatever = sum(ana))

myFun(foo, value, id, "country")

Source: local data frame [2 x 2]

  country whatever
1  France 233.1384
2      UK 245.5400

您可能会发现arrange()不存在。这是我正在努力的那个。这是两个观察结果。第一个实验是成功的。这些国家的顺序从英国 - 法国变为法国 - 英国。但第二个实验并不成功。

### Experiment 1: This works for arrange()

myFun <- function(x, ana) x %>%
         arrange(ana)

myFun(foo, country)

   country id    value
1   France  a 90.12723
2   France  b 86.64229
3   France  c 74.93320
4   France  d 80.69495
5   France  e 72.60077
6       UK  a 84.28033
7       UK  b 67.01209
8       UK  c 94.24756
9       UK  d 79.49848
10      UK  e 63.51265


### Experiment2: This was not successful.

myFun <- function(x, ana, bob) x %>%
         filter(ana %in% c("a", "b", "d")) %>%
         arrange(bob)

myFun(foo, id, country)

Error: incorrect size (10), expecting :6

### This works, by the way.
foo %>%
filter(id %in% c("a", "b", "d")) %>%
arrange(country)

鉴于第一个实验成功,我很难理解为什么第二个实验失败了。在第二个实验中可能有一些事情要做有人有想法吗?感谢您抽出宝贵时间。

2 个答案:

答案 0 :(得分:7)

关闭issue 352后,我安装了 dplyr 0.3 lazyeval ,看看如何在其他功能中使用dplyr功能。在阅读vignette on non-standard evaluation后,看起来{strong> lazyeval 中的interp与以_结尾的新功能相结合是一种选择。注意group_by_现在替换regroup

set.seed(16)
foo = data.frame(country = rep(c("UK", "France"), each = 5), 
               id = rep(letters[1:5], times = 2), 
               value = runif(10, 50, 100), stringsAsFactors = FALSE)

首先是函数外的代码/结果:

library(lazyeval)
library(dplyr)

foo %>%
    mutate(new = ifelse(value > 60, 1, 0)) %>%
    filter(id %in% c("a", "b", "d")) %>%
    group_by(country) %>%
    summarize(whatever = sum(value))

Source: local data frame [2 x 2]

  country whatever
1  France 213.0009
2      UK 207.8331

然后将上述过程转换为函数:

myFun = function(x, ana, bob, cathy) {
    x %>%
        mutate_(new = interp(~ifelse(var > 60 , 1, 0), var = as.name(ana))) %>%
        filter_(interp(~var %in% c("a", "b", "d"), var = as.name(bob))) %>%
        group_by_(cathy) %>%
        summarize_(whatever = interp(~sum(var), var = as.name(ana)))
}

这会产生预期的效果。

myFun(foo, "value", "id", "country")
Source: local data frame [2 x 2]

  country whatever
1  France 213.0009
2      UK 207.8331

对于arrange的第二个问题,我尝试了

myfun2 = function(x, ana, bob) x%>%
    filter_(interp(~var %in% c("a", "b", "d"), var = as.name(ana))) %>%
    arrange_(as.name(bob))

myfun2(foo, "id", "country")

答案 1 :(得分:3)

实际上,您的实验不起作用,您将遇到所有这些问题的范围问题。看起来它们正在工作,因为您已在全局环境中定义了向量countryidvalue,但未删除它们。因此,当您调用函数时,他们正在使用全局环境中的向量。

要显示此信息,请在调用函数之前删除这些向量:

创建向量和data.frame:

library(dplyr)
country <- rep(c("UK", "France"), each = 5)
id <- rep(letters[1:5], times = 2)
value <- runif(10, 50, 100)
foo <- data.frame(country, id, value, stringsAsFactors = FALSE)

定义你的第一个功能:

myFun <- function(x, ana, bob, cathy) x %>%
  mutate(new = ifelse(ana > 60, 1, 0)) %>%
  filter(bob %in% c("a", "b", "d")) %>%
  regroup(as.list(cathy)) %>%
  summarize(whatever = sum(ana))

在不删除向量的情况下调用(看起来它会起作用,但它实际上是使用全局环境中的向量):

myFun(foo, value, id, "country")
Source: local data frame [2 x 2]

  country whatever
1  France 208.1008
2      UK 192.4287

现在删除向量并调用你的函数(现在它不起作用,因为它无法找到向量):

rm(country, id, value)
myFun(foo, value, id, "country")
  

mutate_impl(.data,named_dots(...),environment())出错:
  对象&#39;价值&#39;找不到

这就解释了为什么你的安排例子在其他人做的时候不起作用。您的第二个实验调用的向量是全局环境中的向量country,它有10个元素。但是函数排列只期望6个元素,这是过滤矢量的结果。

您有不同的策略可以让您的功能发挥作用。例如,请查看t his answer by G. Grothendieck以获得有关如何操作的一些见解。或者等一下,正如哈德利指出的那样,programming in dplyr is a future feature coming soon.