使用Tidyverse工具(dplyr、purrr等),如何将丑陋的编码值替换为数据库字典中人类可读的值?

jxct1oxe  于 2022-12-06  发布在  其他
关注(0)|答案(3)|浏览(121)

我有两个文件:一个.csv文件,其中包含难看的编号文件和一个字典。下面是一个类似的.csv文件的简化示例:

responses <- tribble(
  ~n_case, ~movie, ~song, ~sex,
  1, 2, 2, 0,
  2, 1, 1, 0,
  3, 2, 4, 1
  
)

下面是字典数据库的一个类似的简化示例:

# Note the jump from 2 to 4 in 'song' is deliberate,
# as this appears in the actual database that I am working with
dic <- tribble(
  ~name, ~value, ~tag,
  "movie", 1, "Shrek",
  "movie", 2, "Lego",
  "song", 1, "Hallelujah",
  "song", 2, "Happy Birthday",
  "song", 4, "Melancholy Hill",
  "sex", 0, "male",
  "sex", 1, "female"
)

我能做些什么来用人类可读的“标签”来替换丑陋的“值”呢?我想得出这样的结论:

> responses_human
# A tibble: 3 × 4
  n_case movie song            sex   
   <dbl> <chr> <chr>           <chr> 
1      1 Lego  Happy Birthday  male  
2      2 Shrek Hallelujah      male  
3      3 Lego  Melancholy Hill female

如果你好奇的话,我正在使用Guatemala's person census(与房屋或家庭普查相反)。
我试着通过过滤每个“名字”(调查问题的答案;例如“movie”、“song”、“sex”),抓取结果并从中创建新的tibble。这样,我就得到了几十个tibble,每个tibble都是每个调查问题答案(movie、song、sex等)的迷你字典。然后,我会逐个left_join这些过滤后的迷你字典,这样就可以去掉难看的数字,只保留可读的“标签”。
然而,这个解决方案需要命名几十个变量,因此是一个缓慢的过程。请注意,有84个变量,每个变量都有多个编号/丑陋的“值”和人类可读的“标签”。此外,我可能会使用其他(房屋和家庭)人口普查,这提出了同样的问题。
我有一种预感,有一种更高效、更自动化的方法来完成这项工作,只是我还不知道是什么。

vdzxcuhz

vdzxcuhz1#

一种方法是首先将数据字典拆分为list,其中包含每个name的重编码向量。第二步,可以使用across中的list对数据集的列进行重编码:

library(dplyr, w = FALSE)
library(tibble)

dic_split <- split(dic, dic$name) %>%
  lapply(function(x) {
    x %>%
      select(-name) %>%
      tibble::deframe()
  })

rec_helper <- function(x, col) {
  recode(x, !!!dic_split[[col]])
}

responses %>%
  mutate(across(
    all_of(intersect(names(dic_split), names(responses))),
    ~ rec_helper(.x, cur_column())
  ))
#> # A tibble: 3 × 4
#>   n_case movie song            sex   
#>    <dbl> <chr> <chr>           <chr> 
#> 1      1 Lego  Happy Birthday  male  
#> 2      2 Shrek Hallelujah      male  
#> 3      3 Lego  Melancholy Hill female
4xrmg8kj

4xrmg8kj2#

你可以做得更长、更宽、更广:

library(tidyverse)

responses |>
  pivot_longer(-n_case) |>
  left_join(dic, by = c("name", "value")) |>
  select(-value) |>
  pivot_wider(names_from = name, values_from = tag)
#> # A tibble: 3 x 4
#>   n_case movie song            sex   
#>    <dbl> <chr> <chr>           <chr> 
#> 1      1 Lego  Happy Birthday  male  
#> 2      2 Shrek Hallelujah      male  
#> 3      3 Lego  Melancholy Hill female

或具有因子:

responses |>
  mutate(across(movie:sex, \(x) as.character(factor(x,
                                                    levels = dic[dic$name == cur_column(),]$value,
                                                    labels = dic[dic$name == cur_column(),]$tag))))
#> # A tibble: 3 x 4
#>   n_case movie song            sex   
#>    <dbl> <chr> <chr>           <chr> 
#> 1      1 Lego  Happy Birthday  male  
#> 2      2 Shrek Hallelujah      male  
#> 3      3 Lego  Melancholy Hill female
but5z9lq

but5z9lq3#

您可以将字典重新调整为宽格式,然后使用它在响应数据中查找值:

library(dplyr)
library(tidyr)

dic_wide <- dic %>%
  pivot_wider(names_from = name, values_from = tag)

responses %>%
  mutate(across(-n_case, ~ dic_wide[[cur_column()]][match(.x, dic_wide$value)]))

# A tibble: 3 × 4
  n_case movie song            sex   
   <dbl> <chr> <chr>           <chr> 
1      1 Lego  Happy Birthday  male  
2      2 Shrek Hallelujah      male  
3      3 Lego  Melancholy Hill female

相关问题