R 以编程方式在数据框中对选定列进行因式分解,整洁的方式?

R 以编程方式在数据框中对选定列进行因式分解,整洁的方式?,r,dplyr,tidyverse,purrr,R,Dplyr,Tidyverse,Purrr,以下是一个简化的示例: library(tidyverse) frame <- tribble( ~a, ~b, ~c, 1, 1, 2, 5, 4, 7, 2, 3, 4, 3, 1, 6 ) key <- tribble( ~col, ~name, ~type, ~labels, 1, "a", "f", c("one", "two", "three", "four", "five"), 2

以下是一个简化的示例:

library(tidyverse)

frame <- tribble(
  ~a, ~b, ~c,
   1,  1,  2,
   5,  4,  7,
   2,  3,  4, 
   3,  1,  6
)

key <- tribble(
  ~col, ~name, ~type, ~labels,
     1,   "a",   "f",     c("one", "two", "three", "four", "five"),
     2,   "b",   "f",     c("uno", "dos", "tres", "cuatro"),
     3,   "c",   "f",     1:7
)
到目前为止,我拥有的最好的解决方案是使用
purr
map2()
,但分配的任务不是最优雅的:

frame[key$col] <- map2(key$col, key$labels, 
        function(x, y) factor(frame[[x]], levels = 1:length(y), labels = y))

frame[key$col]我不知道这个答案是否满足了你的整洁要求,因为它使用了一个普通的旧for循环。但它确实起到了作用,而且在我看来,它很容易阅读/理解,而且速度也相当快

library(tidyverse)
frame <- tribble(
 ~a, ~b, ~c,
 1,  1,  2,
 5,  4,  7,
 2,  3,  4, 
 3,  1,  6
)

key <- tribble(
 ~col, ~name, ~type, ~labels,
 1,   "a",   "f",     c("one", "two", "three", "four", "five"),
 2,   "b",   "f",     c("uno", "dos", "tres", "cuatro"),
 3,   "c",   "f",     1:7
)

for (i in 1:nrow(key)) {
 var <- key$name[[i]]
 x <- frame[[var]]
 labs <- key$labels[[i]]
 lvls <- 1:max(length(x), length(labs)) # make sure to have the right lengths

 frame <- frame %>% mutate(!! var := factor(x, levels = lvls, labels = labs))
}

frame
#> # A tibble: 4 x 3
#>        a      b      c
#>   <fctr> <fctr> <fctr>
#> 1    one    uno      2
#> 2   five cuatro      7
#> 3    two   tres      4
#> 4  three    uno      6

我很想看看还有什么其他的解决方案。我唯一的建议是稍微更改建议的解决方案,以便更清楚地看到,
frame
将以某种方式进行修改,而不是将其留在
map2
使用的函数体中

例如,在调用
map2
时,将
frame
作为附加参数传递:

frame[key$col] <- map2(key$col, key$labels, 
                       function(x, y, z) factor(z[[x]], levels = 1:length(y), labels = y), 
                       frame)

对于此问题,您可以使用基本R代码:

(A=`names<-`(data.frame(mapply(function(x,y)x[y],key$labels,frame)),key$name))
      a      b c
1   one    uno 2
2  five cuatro 7
3   two   tres 4
4 three    uno 6

 sapply(A,class)
   a        b        c 
"factor" "factor" "factor" 

(A=`names这里是另一个解决方案。我不确定它有多“优雅”。希望有人能改进它。

SuppressPackageStatupMessages(库(tidyverse))
帧%
设置_名称(colnames(frame))%>%
作为_tible()
#>#tibble:4 x 3
#>a、b、c
#>     
#>1 1 uno 2
#>2五个cuatro 7
#>3两条路4
#>4三个uno 6

Hadley有一个
forcats
软件包,如果这听起来很有趣的话。谢谢,我给了它一个外观,它很不错-但是它没有直接提供我想要的操作数据帧的函数…谢谢@David非常详细的回答!看起来我提出的原始解决方案要快一点…谢谢对于这个建议,我将把你的帖子标记为已回答,似乎这是目前为止的最佳方法。
frame[key$col] <- map2(key$col, key$labels, 
                       function(x, y, z) factor(z[[x]], levels = 1:length(y), labels = y), 
                       frame)
frame[key$col] <- frame %>%
  { map2(key$col, key$labels, 
         function(x, y, z) factor(z[[x]], levels = 1:length(y), labels = y), .) }
(A=`names<-`(data.frame(mapply(function(x,y)x[y],key$labels,frame)),key$name))
      a      b c
1   one    uno 2
2  five cuatro 7
3   two   tres 4
4 three    uno 6

 sapply(A,class)
   a        b        c 
"factor" "factor" "factor"