2015-10-15 101 views
0

我有一個表是這樣的:如何避免重複使用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中有沒有優雅的方式來表達這種情況,而不對這些情況進行硬編碼?

+0

在你的情況下,你可以在沒有任何包的情況下簡單地執行'y [c(T,F)] + y [c(F,T)]',但你的例子非常簡單。 –

+0

是的,我在那裏有其他列,只是想在上面匹配正則表達式的對上應用這個二進制函數。 –

回答

2

你可以通過標準的評估和lazyeval做到這一點,儘管它可能看起來像乍一看大量的工作,我不知道優雅適用。

想法是在lapply循環中使用interp來查看感興趣的後綴併爲每個匹配的變量對設置一個函數。

爲避免對後綴進行硬編碼,可以將它們從數據集中提取出來。這種情況適用於您的簡單情況,但如果您的真實數據更復雜,則可能需要更多考慮。

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

現在的循環,在interp使得簡單的函數'+'(x, y)(又名x + y)。 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 
0

由於@aosmith提到,您可以結合使用lazyeval::interp有一個解決非標評價(dplyr函數_結束,看到vignette("nse"))來幫助你那裏。如果你想成爲更通用,而不必硬編碼+操作(也許你有很多列來總結?),我也以直接的功能適用於所有相關列使用containsselect

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)))