在 R 中:将列名作为参数传递并在函数中使用 dplyr::mutate() 和 lazyeval::interp()
In R: pass column name as argument and use it in function with dplyr::mutate() and lazyeval::interp()
这个问题链接到 除了这里我想使用在 mutate_()
中指定为函数 arg 的变量。如果我在 mutate_()
:
中不做任何 "calculations" 它会起作用
data <-
data.frame(v1=c(1,2),
v2=c(3,4))
func1 <- function(df, varname){
res <-
df %>%
mutate_(v3=varname)
return(res)
}
func1(data, "v1")
这给出了预期:
v1 v2 v3
1 1 3 1
2 2 4 2
但如果我这样做,似乎我没有正确指定 "v3":
func2 <- function(df, varname){
res <-
df %>%
mutate_(v3=sum(varname))
return(res)
}
func2(data, "v1")
不起作用;为什么它不等同于函数外的this?:
data %>%
mutate(v3=sum(v1))
给出:
v1 v2 v3
1 1 3 3
2 2 4 3
更新(在@docendo discimus 的解决方案之后):
关于使用 lazyeval::interp()
的解决方案有效。但是,如果功能稍微复杂一点,我似乎会打很多字。例如。我想要一个函数,它可以 return 对计数数据帧中 N-P 的所有组合进行得分和费舍尔的 2x2 pvalue,c.
require(plyr)
require(dplyr)
require(lazyeval)
set.seed(8)
df <-
data.frame(
N = sample(c("n1","n2","n3","n4"),20, replace=T),
P = sample(c("p1","p2","p3","p4"),20, replace=T),
c = round(runif(20,0,10),0)) %>%
distinct()
所以我开始使用 group_by
和 mutate
的很多行来制作一个函数 test.df
。没有 lazyeval 它不起作用(当然),但看起来像这样:
test.df <- function(df=NULL, N=NULL, P=NULL, count=NULL, ...){
require(plyr)
require(dplyr)
test <- function(a,b,c,d){
data <- matrix(c(a,b,c,d),ncol=2)
c(p = fisher.test(data)$p.value,
OR = fisher.test(data)$estimate)
}
df %>%
ungroup() %>%
mutate(n.total = sum(count)) %>%
group_by(N) %>%
mutate(n.N=sum(count)) %>%
group_by(P) %>%
mutate(n.P = sum(count)) %>%
rowwise() %>%
mutate(score(count/n.N)/(n.P/n.total), #simple enrichment score
p=test(count,n.N-count,n.P-count,n.total-n.N-n.P+2*count)[[1]], #p values
OR=test(count,n.N-count,n.P-count,n.total-n.N-n.P+2*count)[[2]]) #Odds ratio
ungroup() %>%
mutate(p_adj=p.adjust(p, method="BH"))
}
然后我转向了lazyval-way,它成功了!:
test.df <- function(df=NULL, N=NULL, P=NULL, count=NULL, ...){
require(plyr)
require(dplyr)
require(lazyeval)
test <- function(a,b,c,d){
data <- matrix(c(a,b,c,d),ncol=2)
c(p = fisher.test(data)$p.value,
OR = fisher.test(data)$estimate)
}
df %>%
ungroup() %>%
mutate_(n.total = interp(~sum(count), count=as.name(count))) %>%
group_by_(interp(~N, N=as.name(N))) %>%
mutate_(n.N = interp(~sum(count), count=as.name(count))) %>%
group_by_(interp(~P, P=as.name(P))) %>%
mutate_(n.P = interp(~sum(count), count=as.name(count))) %>%
rowwise() %>%
mutate_(score=interp(~(count/n.N)/(n.P/n.total),
.values=list(count=as.name(count),
n.N=quote(n.N),
n.P=quote(n.P),
n.total=quote(n.total))),
p=interp(~(test(count,n.N-count,n.P-count,n.total-n.N-n.P+2*count)[[1]]),
.values=list(fisher=quote(fisher),
count=as.name(count),
n.N=quote(n.N),
n.P=quote(n.P),
n.total=quote(n.total))),
OR=interp(~(test(count,n.N-count,n.P-count,n.total-n.N-n.P+2*count)[[2]]),
.values=list(fisher=quote(fisher),
count=as.name(count),
n.N=quote(n.N),
n.P=quote(n.P),
n.total=quote(n.total)))) %>%
ungroup() %>%
mutate_(p_adj=interp(~p.adjust(p, method="BH"),
.values=list(p.adjust=quote(p.adjust),
p=quote(p))))
}
给出:
N P c n.total n.N n.P score p OR p_adj
1 n2 p1 9 89 23 27 1.2898551 1.856249e-01 2.0197105 0.309374904
2 n1 p2 3 89 21 16 0.7946429 1.000000e+00 0.7458441 1.000000000
3 n4 p3 5 89 20 30 0.7416667 5.917559e-01 0.6561651 0.724442095
4 n3 p1 9 89 25 27 1.1866667 3.053538e-01 1.7087545 0.469775140
5 n2 p3 3 89 23 30 0.3869565 2.237379e-02 0.2365142 0.074579284
6 n3 p4 3 89 25 16 0.6675000 5.428536e-01 0.5696359 0.723804744
7 n2 p1 5 89 23 27 0.7165862 4.412042e-01 0.6216888 0.630291707
8 n4 p3 2 89 20 30 0.2966667 1.503170e-02 0.1733288 0.060126805
9 n4 p3 10 89 20 30 1.4833333 5.406588e-02 2.9136831 0.108131750
10 n3 p4 1 89 25 16 0.2225000 3.524192e-02 0.1410289 0.091433058
11 n2 p1 1 89 23 27 0.1433172 1.312078e-03 0.0731707 0.008747184
12 n1 p3 1 89 21 30 0.1412698 1.168232e-03 0.0704372 0.008747184
13 n2 p4 1 89 23 16 0.2418478 6.108872e-02 0.1598541 0.111070394
14 n3 p1 3 89 25 27 0.3955556 3.793658e-02 0.2475844 0.091433058
15 n1 p2 10 89 21 16 2.6488095 8.710747e-05 10.5125558 0.001742149
16 n4 p2 3 89 20 16 0.8343750 1.000000e+00 0.8027796 1.000000000
17 n1 p4 7 89 21 16 1.8541667 4.114488e-02 3.6049777 0.091433058
18 n2 p4 4 89 23 16 0.9673913 1.000000e+00 1.0173534 1.000000000
19 n2 p2 0 89 23 16 0.0000000 9.115366e-03 0.0000000 0.045576831
20 n3 p3 9 89 25 30 1.0680000 6.157758e-01 1.3880504 0.724442095
我是不是没有正确使用lazyeval,或者以愚蠢的方式构建函数?在这里非常感谢一些意见。
你必须使用惰性求值(使用包 lazyeval
),例如:
library(lazyeval)
func2 <- function(df, varname){
df %>%
mutate_(v3=interp(~sum(x), x = as.name(varname)))
}
func2(data, "v1")
# v1 v2 v3
#1 1 3 3
#2 2 4 3
使用 dplyr
(0.5.0
) 的开发版本或新版本(0.6.0
- 等待 2017 年 4 月发布),这可以使用稍微不同的语法来完成
library(dplyr)
funcN <- function(dat, varname){
expr <- enquo(varname)
dat %>%
mutate(v3 = sum(!!expr))
#or
#mutate(v3 = sum(UQ(expr)))
}
funcN(data, v1)
# v1 v2 v3
#1 1 3 3
#2 2 4 3
在这里,enquo
通过计算函数参数将参数和returns值作为quosure
(类似于base R
中的substitute
)懒惰地在 summarise
中,我们要求它 unquote
(!!
或 UQ
)以便它得到评估。
这个问题链接到 mutate_()
中指定为函数 arg 的变量。如果我在 mutate_()
:
data <-
data.frame(v1=c(1,2),
v2=c(3,4))
func1 <- function(df, varname){
res <-
df %>%
mutate_(v3=varname)
return(res)
}
func1(data, "v1")
这给出了预期:
v1 v2 v3
1 1 3 1
2 2 4 2
但如果我这样做,似乎我没有正确指定 "v3":
func2 <- function(df, varname){
res <-
df %>%
mutate_(v3=sum(varname))
return(res)
}
func2(data, "v1")
不起作用;为什么它不等同于函数外的this?:
data %>%
mutate(v3=sum(v1))
给出:
v1 v2 v3
1 1 3 3
2 2 4 3
更新(在@docendo discimus 的解决方案之后):
关于使用 lazyeval::interp()
的解决方案有效。但是,如果功能稍微复杂一点,我似乎会打很多字。例如。我想要一个函数,它可以 return 对计数数据帧中 N-P 的所有组合进行得分和费舍尔的 2x2 pvalue,c.
require(plyr)
require(dplyr)
require(lazyeval)
set.seed(8)
df <-
data.frame(
N = sample(c("n1","n2","n3","n4"),20, replace=T),
P = sample(c("p1","p2","p3","p4"),20, replace=T),
c = round(runif(20,0,10),0)) %>%
distinct()
所以我开始使用 group_by
和 mutate
的很多行来制作一个函数 test.df
。没有 lazyeval 它不起作用(当然),但看起来像这样:
test.df <- function(df=NULL, N=NULL, P=NULL, count=NULL, ...){
require(plyr)
require(dplyr)
test <- function(a,b,c,d){
data <- matrix(c(a,b,c,d),ncol=2)
c(p = fisher.test(data)$p.value,
OR = fisher.test(data)$estimate)
}
df %>%
ungroup() %>%
mutate(n.total = sum(count)) %>%
group_by(N) %>%
mutate(n.N=sum(count)) %>%
group_by(P) %>%
mutate(n.P = sum(count)) %>%
rowwise() %>%
mutate(score(count/n.N)/(n.P/n.total), #simple enrichment score
p=test(count,n.N-count,n.P-count,n.total-n.N-n.P+2*count)[[1]], #p values
OR=test(count,n.N-count,n.P-count,n.total-n.N-n.P+2*count)[[2]]) #Odds ratio
ungroup() %>%
mutate(p_adj=p.adjust(p, method="BH"))
}
然后我转向了lazyval-way,它成功了!:
test.df <- function(df=NULL, N=NULL, P=NULL, count=NULL, ...){
require(plyr)
require(dplyr)
require(lazyeval)
test <- function(a,b,c,d){
data <- matrix(c(a,b,c,d),ncol=2)
c(p = fisher.test(data)$p.value,
OR = fisher.test(data)$estimate)
}
df %>%
ungroup() %>%
mutate_(n.total = interp(~sum(count), count=as.name(count))) %>%
group_by_(interp(~N, N=as.name(N))) %>%
mutate_(n.N = interp(~sum(count), count=as.name(count))) %>%
group_by_(interp(~P, P=as.name(P))) %>%
mutate_(n.P = interp(~sum(count), count=as.name(count))) %>%
rowwise() %>%
mutate_(score=interp(~(count/n.N)/(n.P/n.total),
.values=list(count=as.name(count),
n.N=quote(n.N),
n.P=quote(n.P),
n.total=quote(n.total))),
p=interp(~(test(count,n.N-count,n.P-count,n.total-n.N-n.P+2*count)[[1]]),
.values=list(fisher=quote(fisher),
count=as.name(count),
n.N=quote(n.N),
n.P=quote(n.P),
n.total=quote(n.total))),
OR=interp(~(test(count,n.N-count,n.P-count,n.total-n.N-n.P+2*count)[[2]]),
.values=list(fisher=quote(fisher),
count=as.name(count),
n.N=quote(n.N),
n.P=quote(n.P),
n.total=quote(n.total)))) %>%
ungroup() %>%
mutate_(p_adj=interp(~p.adjust(p, method="BH"),
.values=list(p.adjust=quote(p.adjust),
p=quote(p))))
}
给出:
N P c n.total n.N n.P score p OR p_adj
1 n2 p1 9 89 23 27 1.2898551 1.856249e-01 2.0197105 0.309374904
2 n1 p2 3 89 21 16 0.7946429 1.000000e+00 0.7458441 1.000000000
3 n4 p3 5 89 20 30 0.7416667 5.917559e-01 0.6561651 0.724442095
4 n3 p1 9 89 25 27 1.1866667 3.053538e-01 1.7087545 0.469775140
5 n2 p3 3 89 23 30 0.3869565 2.237379e-02 0.2365142 0.074579284
6 n3 p4 3 89 25 16 0.6675000 5.428536e-01 0.5696359 0.723804744
7 n2 p1 5 89 23 27 0.7165862 4.412042e-01 0.6216888 0.630291707
8 n4 p3 2 89 20 30 0.2966667 1.503170e-02 0.1733288 0.060126805
9 n4 p3 10 89 20 30 1.4833333 5.406588e-02 2.9136831 0.108131750
10 n3 p4 1 89 25 16 0.2225000 3.524192e-02 0.1410289 0.091433058
11 n2 p1 1 89 23 27 0.1433172 1.312078e-03 0.0731707 0.008747184
12 n1 p3 1 89 21 30 0.1412698 1.168232e-03 0.0704372 0.008747184
13 n2 p4 1 89 23 16 0.2418478 6.108872e-02 0.1598541 0.111070394
14 n3 p1 3 89 25 27 0.3955556 3.793658e-02 0.2475844 0.091433058
15 n1 p2 10 89 21 16 2.6488095 8.710747e-05 10.5125558 0.001742149
16 n4 p2 3 89 20 16 0.8343750 1.000000e+00 0.8027796 1.000000000
17 n1 p4 7 89 21 16 1.8541667 4.114488e-02 3.6049777 0.091433058
18 n2 p4 4 89 23 16 0.9673913 1.000000e+00 1.0173534 1.000000000
19 n2 p2 0 89 23 16 0.0000000 9.115366e-03 0.0000000 0.045576831
20 n3 p3 9 89 25 30 1.0680000 6.157758e-01 1.3880504 0.724442095
我是不是没有正确使用lazyeval,或者以愚蠢的方式构建函数?在这里非常感谢一些意见。
你必须使用惰性求值(使用包 lazyeval
),例如:
library(lazyeval)
func2 <- function(df, varname){
df %>%
mutate_(v3=interp(~sum(x), x = as.name(varname)))
}
func2(data, "v1")
# v1 v2 v3
#1 1 3 3
#2 2 4 3
使用 dplyr
(0.5.0
) 的开发版本或新版本(0.6.0
- 等待 2017 年 4 月发布),这可以使用稍微不同的语法来完成
library(dplyr)
funcN <- function(dat, varname){
expr <- enquo(varname)
dat %>%
mutate(v3 = sum(!!expr))
#or
#mutate(v3 = sum(UQ(expr)))
}
funcN(data, v1)
# v1 v2 v3
#1 1 3 3
#2 2 4 3
在这里,enquo
通过计算函数参数将参数和returns值作为quosure
(类似于base R
中的substitute
)懒惰地在 summarise
中,我们要求它 unquote
(!!
或 UQ
)以便它得到评估。