2014-09-23 82 views
3

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

DATA

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) 

鉴于第一个实验是成功的,我很难理解第二个实验失败的原因。在第二次实验中可能有一件事需要做。有没有人有想法?感谢您抽出时间。

回答

3

实际上,您的实验无法正常工作,您将面临所有问题的范围问题。看起来他们正在工作,因为您已经在Global Environment上定义了矢量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)) 

无需调用去除矢量(它看起来像是有效的,但它实际上是使用来自全局env的矢量):

在mutate_impl

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

错误(。数据,named_dots(:

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

    country whatever 
1 France 208.1008 
2  UK 192.4287 

现在去除载体和调用你的函数(现在它不工作,因为它无法找到矢量) ...),环境()):
对象“价值”没有找到

所以这解释了为什么而其他没有你的安排例子没有工作。第二个实验所调用的矢量是全球环境矢量country,其中有10个元素。但函数安排只需要6个元素,这是滤波矢量的结果。

你有不同的策略,使您的功能工作。例如,请查看t​​以了解如何执行此操作。或只是等待一点点,如哈德利指出,programming in dplyr is a future feature coming soon.

+1

Deparsing和粘贴字符串是_永远_写答案。 – hadley 2014-09-23 22:49:48

+0

@hadley ok,在这种情况下,您会推荐“创建列表”方法? – 2014-09-23 22:53:15

+2

我推荐使用'substitute()',或者等待https://github.com/hadley/dplyr/issues/352 – hadley 2014-09-23 22:54:15

7

我安装dplyr 0.3lazyeval一次issue 352被关闭,看看它如何工作在其他功能使用dplyr功能。看完vignette on non-standard evaluation后,看起来好像interplazyeval结合以_结尾的新功能是一种选择。注意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") 
+0

非常感谢您的更新。看来用'dplyr'编写函数的方式现在比我想象的要简单。这是很棒的东西。 – jazzurro 2014-10-01 16:10:05

+0

嘿,我今天一直在玩你的代码,我正在努力'排列'。 'arrange_(as.name(ana),as.name(bob))'工作正常。但是,我想为bob添加“desc”。 'arrange_(as.name(ana),〜desc(as.name(bob))))'没有错误,bur不起作用。 'arrange_(interp(as.name(ana),〜desc(as.name(bob))))'是一样的。你有什么想法? – jazzurro 2014-10-03 15:22:44

+0

我现在明白了。 ''''''''''我还是很困惑,但因为'desc'是另外一个函数,所以你必须执行'interp() '在'arrange_' – jazzurro 2014-10-03 15:42:34