如何避免使用dplyr重复重复图案列名称上的代码?

时间:2015-10-15 19:43:59

标签: r dplyr

我有一张这样的表:

require(dplyr)
y = data.frame(a.foo=rnorm(10),b.foo=rnorm(10), a.bar=rnorm(10), b.bar=rnorm(10), a.baz=rnorm(10), b.baz=rnorm(10))

我经常最终做这样的事情(在这个例子中简化为+

y %>% mutate(z.foo=(a.foo+b.foo),z.bar=(a.bar+b.bar),z.baz=(a.baz+b.baz))

有时会有各种各样的这些,我想知道是否有使用像matches这样的简写方式,因为唯一的模式是我通常想做的z.* = a.* + b.*。有没有一种优雅的方式来表达dplyr中没有硬编码的情况?

2 个答案:

答案 0 :(得分:2)

你可以通过标准评估和lazyeval来做到这一点,虽然乍一看似乎有很多工作,但我不确定优雅是否适用。

我们的想法是在interp循环中使用lapply来浏览感兴趣的后缀,并为每个匹配的变量对设置一个函数。

为避免对后缀进行硬编码,您可以将它们从数据集中拉出来。这适用于您所拥有的简单情况,但如果您的实际数据更复杂,可能需要更多考虑。

suffix = unique(sub(".*\\.", "", names(y)))
suffix
[1] "foo" "bar" "baz"

现在循环,在'+'(x, y)中创建简单函数x + y(又名interp)。 xy的变量通过paste相应的后缀设置,全部包含在as.name中。

dots = lapply(suffix, 
                function(suff) interp(~'+'(x, y), 
                                    x = as.name(paste("a", suff, sep = ".")),
                                    y = as.name(paste("b", suff, sep = "."))))
dots

[[1]]
~a.foo + b.foo
<environment: 0x036bf4b8>

[[2]]
~a.bar + b.bar
<environment: 0x036c189c>

[[3]]
~a.baz + b.baz
<environment: 0x036c4c14>

然后只需使用mutate_列表dots来计算新变量。

mutate_(y, .dots = dots)

感兴趣的列如下:

   a.foo + b.foo a.bar + b.bar a.baz + b.baz
1     -2.7750933     2.2524274    0.52665909
2     -1.6001349     0.7894692   -0.13340202
3      0.8031004     1.1632274    0.46272597
4     -0.9941492     1.4346315   -0.06327656
5     -1.7558620     1.4079703   -1.14218434
6     -0.6322581    -1.5661146    1.40710596
7      0.4077698    -2.9227982    1.33316137
8     -0.2664580     1.5139438    1.95130283
9     -0.4476210    -0.7926471   -0.44932288
10    -0.6217235    -1.2043056   -0.19059357

要获取新名称,您需要添加使用setNames,再次使用paste根据suffix向量创建名称。

mutate_(y, .dots = setNames(dots, paste("z", suffix, sep = ".")))

新栏目:

        z.foo      z.bar       z.baz
1  -2.7750933  2.2524274  0.52665909
2  -1.6001349  0.7894692 -0.13340202
3   0.8031004  1.1632274  0.46272597
4  -0.9941492  1.4346315 -0.06327656
5  -1.7558620  1.4079703 -1.14218434
6  -0.6322581 -1.5661146  1.40710596
7   0.4077698 -2.9227982  1.33316137
8  -0.2664580  1.5139438  1.95130283
9  -0.4476210 -0.7926471 -0.44932288
10 -0.6217235 -1.2043056 -0.19059357

答案 1 :(得分:0)

正如@aosmith所提到的,您可以将lazyeval::interp结合使用以dplyr结尾的_函数进行解决方案的非标准评估,参见vignette("nse"))帮助你。如果您想要更加通用而不必对+操作进行硬编码(也许您有很多要汇总的列?),我还会在contains中使用select来申请直接将您的函数添加到所有相关列:

require(lazyeval)
suffix = unique(gsub(".*\\.", "", names(y)))
myNewColsValues = lapply(suffix, 
                         function(pattern) interp(~ select(y, contains(patt)) 
                                                  %>% rowSums, 
                                                  patt=pattern) )
y %>% mutate_( .dots = setNames(myNewColsValues, paste0('z.', suffix)) )