我正在尝试使用recode和mutate_all来重新编码列。但是,出于某种原因,我收到了一个错误。我相信这篇文章与how to recode (and reverse code) variables in columns with dplyr类似,但该帖子中的答案使用了lapply函数。
这是我在阅读dplyr软件包的帮助pdf后尝试的内容。
by_species<-matrix(c(1,2,3,4),2,2)
tbl_species<-as_data_frame(by_species)
tbl_species %>% mutate_all(funs(. * 0.4))
# A tibble: 2 x 2
V1 V2
<dbl> <dbl>
1 0.4 1.2
2 0.8 1.6
所以,这很好用。
然而,这不起作用:
grades<-matrix(c("A","A-","B","C","D","B-","C","C","F"),3,3)
tbl_grades <- as_data_frame(grades)
tbl_grades %>% mutate_all(funs(dplyr::recode(.,A = '4.0')))
我收到此错误:
Error in vapply(dots[missing_names], function(x) make_name(x$expr), character(1)) :
values must be length 1,
but FUN(X[[1]]) result is length 3
有人可以解释一下问题是什么以及为什么上面的代码无效?
我很感激任何帮助。
由于
答案 0 :(得分:7)
@Mir在描述问题方面做得很好。这是一种可能的解决方法。由于问题在于生成名称,您可以提供自己的名称
tbl_grades %>% mutate_all(funs(recode=recode(.,A = '4.0')))
现在这会添加列而不是替换它们。这是一个“忘记”你提供这些名字的函数
dropnames<-function(x) {if(is(x,"lazy_dots")) {attr(x,"has_names")<-FALSE}; x}
tbl_grades %>% mutate_all(dropnames(funs(recode=dplyr::recode(.,A = '4.0'))))
这应该像原版一样。虽然真的
tbl_grades %>% mutate_all(dropnames(funs(recode(.,A = '4.0'))))
因为dplyr经常有一些函数的特殊c ++版本,如果它能识别这些函数(例如lag
)就可以使用它,但是如果你还指定了命名空间(如果使用{{1 }})。
答案 1 :(得分:4)
如果我们在没有dplyr::
的情况下调用它,那么它可以正常工作。
funs(recode(., A = '4.0'))
<fun_calls>
$ recode: recode(., A = "4.0")
tbl_grades %>% mutate_all(funs(recode(. ,A = '4.0')))
# A tibble: 3 x 3
V1 V2 V3
<chr> <chr> <chr>
1 4.0 C C
2 A- D C
3 B B- F
问题在于funs
电话。如果我们提取该部分,则会出现相同的错误。
funs(dplyr::recode(., A = '4.0'))
Error in vapply(dots[missing_names], function(x) make_name(x$expr), character(1)) :
values must be length 1, but FUN(X[[1]]) result is length 3
问题归结为::
本身就是一个功能。 (见?`::`
)。为了更好地将其可视化,我们将查看函数的中缀和前缀两种方式。
`::`(dplyr, recode)
function (.x, ..., .default = NULL, .missing = NULL)
{
UseMethod("recode")
}
<environment: namespace:dplyr>
dplyr::recode
function (.x, ..., .default = NULL, .missing = NULL)
{
UseMethod("recode")
}
<environment: namespace:dplyr>
funs
尝试通过抓取调用对象的第一个元素并在其上调用as.character
来提取其参数的函数名称。调用对象的第一个元素是调用函数,后续元素是参数值。例如:
as.call(quote(recall(., A = '4.0')))
recall(., A = "4.0")
as.call(quote(recall(., A = '4.0')))[[1]]
recall
as.call(quote(recall(., A = '4.0')))[[2]]
.
as.call(quote(recall(., A = '4.0')))[[3]]
"4.0"
as.call(quote(recall(., A = '4.0')))[[4]]
Error in as.call(quote(recall(., A = "4.0")))[[4]] :
subscript out of bounds
当使用dplyr::recode
时会遇到问题,因为这会创建一个嵌套的调用对象。当我们获取第一个元素时,我们不仅得到一个函数的名称,而且还得到一个完整的函数调用。
as.call(quote(dplyr::recall(., A = '4.0')))
dplyr::recall(., A = "4.0")
as.call(quote(dplyr::recall(., A = '4.0')))[[1]]
dplyr::recall
as.call(quote(dplyr::recall(., A = '4.0')))[[1]][[1]]
`::`
as.call(quote(dplyr::recall(., A = '4.0')))[[1]][[2]]
dplyr
as.call(quote(dplyr::recall(., A = '4.0')))[[1]][[3]]
recall
与没有recode
时调用dplyr::
的情况相反。
as.call(quote(recall(., A = '4.0')))[[1]][[1]]
Error in as.call(quote(recall(., A = "4.0")))[[1]][[1]] :
object of type 'symbol' is not subsettable
因为包含dplyr::
的第一个元素是一个完整的函数调用,as.character
会产生一个既包含函数名称又包含参数的向量。
as.call(quote(dplyr::recall(., A = '4.0')))[[1]] %>% as.character()
[1] "::" "dplyr" "recall"
Funs
合理地期望函数的名称只有一个元素,而不是三个元素,因而错误输出。