使用 purrr 通过多个映射跨多个列重新编码

Cla*_*eri 5 r dplyr recode purrr tidyverse

我有一个带有问卷响应标签的数据框。我总是喜欢用项目答案定义制作一个小标题,然后用dplyr::recode()它们相应的定义替换所有项目标签。为了便于使用,定义 tibblerecode_df将这些对应关系存储为字符串,并且dplyr::recode()可以使用 bangbangbang 解压它们!!!并对其进行评估。在下面的玩具示例中,有 4 个项目,其中两个 forqa和两个 forqb共享相同的答案定义。

library(tidyverse)
set.seed(42)

# columns starting with `qa` and `qb` share the same answer structure 
data_df <- tibble(
  qa_1 = sample(c(0, 1), 5, replace = TRUE),
  qa_2 = sample(c(0, 1), 5, replace = TRUE),
  qb_1 = sample(1:5, 5, replace = TRUE),
  qb_3 = sample(1:5, 5, replace = TRUE)
)

# `answer` column stores string definitions for use with `dplyr::recode()`
recode_df <- tibble(
  question = c("qa", "qb"),
  answer = c(
    'c("0" = "foo0", "1" = "foo1")',
    'c("1" = "bar1", "2" = "bar2", "3" = "bar3", "4" = "bar5", "5" = "bar5")'
  )
)  

# Desired result
data_df %>%
  mutate(
    across(
      .cols = starts_with("qa"),
      .fns = ~recode(., !!!eval(parse(text = recode_df$answer[str_detect(recode_df$question, "qa")])))
    ),
    across(
      .cols = starts_with("qb"),
      .fns = ~recode(., !!!eval(parse(text = recode_df$answer[str_detect(recode_df$question, "qb")])))
    )
  )
#> # A tibble: 5 x 4
#>   qa_1  qa_2  qb_1  qb_3 
#>   <chr> <chr> <chr> <chr>
#> 1 foo0  foo1  bar5  bar2 
#> 2 foo0  foo1  bar1  bar3 
#> 3 foo0  foo1  bar5  bar1 
#> 4 foo0  foo0  bar5  bar1 
#> 5 foo1  foo1  bar2  bar3
Run Code Online (Sandbox Code Playgroud)

创建于 2023-02-26,使用reprex v2.0.2

我可以通过对每一行使用一个mutate()and 来达到我想要的结果,但我确信有一个优雅的解决方案可以迭代和重新编码而无需重复代码。谢谢。acrossrecode_dfpurrr

jay*_*.sf 1

你可以买更便宜的。

data_df[] <- lapply(names(data_df), \(x) if (grepl('qa', x)) paste0('foo', data_df[[x]]) else paste0('bar', data_df[[x]]))
Run Code Online (Sandbox Code Playgroud)

如果有更多列,您可以使用一个简单的字典,该字典dc由一个命名向量组成,其中数据前缀作为元素,列前缀作为名称。

dc <- c(qa='foo', qb='bar')
## alternatively using `grep` to identify columns
# dc <- setNames(c('foo', 'bar'), unique(gsub('_\\d+$', '', names(data_df))))
Run Code Online (Sandbox Code Playgroud)

我们现在可以输入startsWith名称列名称和dc-name 来识别 中的正确条目dc

data_df[] <- lapply(names(data_df), \(x) paste0(dc[startsWith(x, names(dc))], data_df[[x]]))

data_df
#   qa_1 qa_2 qb_1 qb_3
# 1 foo0 foo1 bar4 bar2
# 2 foo0 foo1 bar1 bar3
# 3 foo0 foo1 bar5 bar1
# 4 foo0 foo0 bar4 bar1
# 5 foo1 foo1 bar2 bar3
Run Code Online (Sandbox Code Playgroud)

这也应该适用于数百列。可能很难避免定义一次翻译。