我希望通过使用变量传递列名来动态地使用dplyr变异数据帧的一列。例如,我有以下数据框:
DF <- data.frame(A = 1:10,
B = 11:20,
C = c(23:30, 21:22),
D = c(39:40, 31:38),
E = c(TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE))
DF
A B C D E
1 1 11 23 39 TRUE
2 2 12 24 40 TRUE
3 3 13 25 31 TRUE
4 4 14 26 32 TRUE
5 5 15 27 33 TRUE
6 6 16 28 34 TRUE
7 7 17 29 35 TRUE
8 8 18 30 36 TRUE
9 9 19 21 37 TRUE
10 10 20 22 38 TRUE
现在我想将那些
行的列E的值更改为FALSE因此结果数据框应如下所示:
A B C D E
1 1 11 23 39 FALSE
2 2 12 24 40 FALSE
3 3 13 25 31 FALSE
4 4 14 26 32 TRUE
5 5 15 27 33 TRUE
6 6 16 28 34 TRUE
7 7 17 29 35 TRUE
8 8 18 30 36 FALSE
9 9 19 21 37 FALSE
10 10 20 22 38 FALSE
我编写了一个脚本,它只基于一行来改变数据框,并且效果很好:
DF <- DF %>%
dplyr::mutate(E = if_else(B < quantile(B, 0.9), E, FALSE)) %>%
dplyr::mutate(E = if_else(B > quantile(B, 0.1), E, FALSE))
DF
A B C D E
1 1 11 23 39 FALSE
2 2 12 24 40 TRUE
3 3 13 25 31 TRUE
4 4 14 26 32 TRUE
5 5 15 27 33 TRUE
6 6 16 28 34 TRUE
7 7 17 29 35 TRUE
8 8 18 30 36 TRUE
9 9 19 21 37 TRUE
10 10 20 22 38 FALSE
然而,当我试图让它变得动态时,它不起作用:
for (col in cols) {
DF <- DF %>%
dplyr::mutate_(E = if_else(col < quantile(col, 0.9), E, FALSE)) %>%
dplyr::mutate_(E = if_else(col > quantile(col, 0.1), E, FALSE))
}
Error in (1 - h) * qs[i] : non-numeric argument to binary operator
我该如何解决这个问题?
答案 0 :(得分:1)
我们可以使用interp
library(dplyr)
library(lazyeval)
for (col in cols) {
DF <- DF %>%
mutate_(E = interp(~if_else(Col<quantile(Col, 0.9), E, FALSE),
Col=as.name(col))) %>%
mutate_(E = interp(~if_else(Col>quantile(Col, 0.1), E, FALSE),
Col = as.name(col)))
}
DF
# A B C D E
#1 1 11 23 39 FALSE
#2 2 12 24 40 FALSE
#3 3 13 25 31 FALSE
#4 4 14 26 32 TRUE
#5 5 15 27 33 TRUE
#6 6 16 28 34 TRUE
#7 7 17 29 35 TRUE
#8 8 18 30 36 FALSE
#9 9 19 21 37 FALSE
#10 10 20 22 38 FALSE
其中
cols <- names(DF)[2:4]
如果我们还需要传递'E'列
for (col in cols) {
DF <- DF %>%
mutate_(.dots = setNames(list(interp(~if_else(Col < quantile(Col, 0.9), Col2, FALSE),
.values = list(Col= as.name(col), Col2 = as.name(names(DF)[5])))), names(DF)[5])) %>%
mutate_(.dots = setNames(list(interp(~if_else(Col > quantile(Col, 0.1), Col2, FALSE),
.values = list(Col= as.name(col), Col2 = as.name(names(DF)[5])))), names(DF)[5]))
}
DF
# A B C D E
#1 1 11 23 39 FALSE
#2 2 12 24 40 FALSE
#3 3 13 25 31 FALSE
#4 4 14 26 32 TRUE
#5 5 15 27 33 TRUE
#6 6 16 28 34 TRUE
#7 7 17 29 35 TRUE
#8 8 18 30 36 FALSE
#9 9 19 21 37 FALSE
使用devel版本的dplyr
(很快就会发布0.6.0
),我们也可以将变量作为quosures传递,并通过取消引用mutate
进行评估
varN <- quo(E)
cols <- rlang::parse_quosures(paste(names(DF)[2:4], collapse=";"))
varN1 <- quo_name(varN)
for(i in seq_along(cols)) {
DF <- DF %>%
mutate(!!varN1 := if_else((!!cols[[i]]) < quantile((!!cols[[i]]), 0.9),
(!!varN), FALSE),
!!varN1 := if_else((!!cols[[i]]) > quantile((!!cols[[i]]), 0.1),
(!!varN), FALSE))
}
DF
# A B C D E
#1 1 11 23 39 FALSE
#2 2 12 24 40 FALSE
#3 3 13 25 31 FALSE
#4 4 14 26 32 TRUE
#5 5 15 27 33 TRUE
#6 6 16 28 34 TRUE
#7 7 17 29 35 TRUE
#8 8 18 30 36 FALSE
#9 9 19 21 37 FALSE
#10 10 20 22 38 FALSE
或另一个选项是data.table
library(data.table)
setDT(DF)[, E := Reduce(`&`, lapply(.SD, function(x) x < quantile(x, 0.9) &
x > quantile(x, .1))), .SDcols = 2:4]
DF
# A B C D E
#1: 1 11 23 39 FALSE
#2: 2 12 24 40 FALSE
#3: 3 13 25 31 FALSE
#4: 4 14 26 32 TRUE
#5: 5 15 27 33 TRUE
#6: 6 16 28 34 TRUE
#7: 7 17 29 35 TRUE
#8: 8 18 30 36 FALSE
#9: 9 19 21 37 FALSE
#10:10 20 22 38 FALSE
或仅使用base R
个功能
DF$E <- Reduce(`&`, lapply(DF[2:4], function(x) x < quantile(x, 0.9) & x > quantile(x, .1)))
DF
# A B C D E
#1 1 11 23 39 FALSE
#2 2 12 24 40 FALSE
#3 3 13 25 31 FALSE
#4 4 14 26 32 TRUE
#5 5 15 27 33 TRUE
#6 6 16 28 34 TRUE
#7 7 17 29 35 TRUE
#8 8 18 30 36 FALSE
#9 9 19 21 37 FALSE
#10 10 20 22 38 FALSE
注意:没有使用外部包
注2:所有选项都返回相同的输出
答案 1 :(得分:0)
您可以直接在mutate
:
DF %>% mutate(E = apply(sapply(list(B, C, D),
function(x){x < quantile(x, .9) & x > quantile(x, .1)}),
1, all))
## A B C D E
## 1 1 11 23 39 FALSE
## 2 2 12 24 40 FALSE
## 3 3 13 25 31 FALSE
## 4 4 14 26 32 TRUE
## 5 5 15 27 33 TRUE
## 6 6 16 28 34 TRUE
## 7 7 17 29 35 TRUE
## 8 8 18 30 36 FALSE
## 9 9 19 21 37 FALSE
## 10 10 20 22 38 FALSE
或使用purrr,
library(tidyverse)
DF %>% mutate(E = list(B, C, D) %>%
map(~.x < quantile(.x, .9) & .x > quantile(.x, .1)) %>%
pmap_lgl(all))
或全力投入矩阵:
DF %>% mutate(E = cbind(B, C, D) %>%
apply(2, function(x){x < quantile(x, .9) & x > quantile(x, .1)}) %>%
apply(1, all))
所有人都回报同样的事情。
如果您愿意,可以用between
替换不平等,例如between(x, quantile(x, .1), quantile(x, .9))
,但因为它被定义为x >= left & x <= right
,当边界重要时,它可能会有所不同。
答案 2 :(得分:0)
最简单的解决方案。使用 get() 基础 R 函数 -
for (col in cols) {
DF <- DF %>%
dplyr::mutate(E = if_else(get(col) < quantile(get(col), 0.9), E, FALSE)) %>%
dplyr::mutate(E = if_else(get(col) > quantile(get(col), 0.1), E, FALSE))
}