dplyr

时间:2016-08-06 23:07:54

标签: r dplyr

我正在尝试使用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

有人可以解释一下问题是什么以及为什么上面的代码无效?

我很感激任何帮助。

由于

2 个答案:

答案 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合理地期望函数的名称只有一个元素,而不是三个元素,因而错误输出。