将数字变量重新编码为有意义的因子变量的过程自动化

Automating the process of recoding numeric variables to meaningful factor variables

我有一个大数据框(数百个变量宽),其中所有分类变量的值都保存为数字,例如,1、2、8,代表否、是和未知。 然而,这并不总是一致的。有十个或更多类别的变量,其中 88 个表示未知等

data <- data.frame("ID" = c(1:5),
                   "Var1" = c(2,2,8,1,8),
                   "Var2" = c(5,8,4,88,10))

对于每个变量,我都有关于哪个值代表哪个类别的所有信息。目前,我将此信息存储在每个正确排序的向量中,例如

> Var1_values
[1] 8 2 1

对应的向量包含以下类别:

> Var1_categories
[1] "unknown" "yes" "no"

但我无法弄清楚如何将这些信息整合在一起,以便将重新编码过程自动化到预期结果,例如

| ID | Var1    | Var2              |
|----|---------|-------------------|
| 1  | yes     | condition E       |
| 2  | yes     | condition H       |
| 3  | unknown | condition D       |
| 4  | no      | unknown condition |
| 5  | unknown | condition H       |

其中每一列都是一个有意义的因子变量。

正如我所说,数据框非常宽,内部可能会发生变化,因此不能手动执行此操作。我觉得自己很愚蠢,因为我拥有现成的所有必要信息,所以任何见解都将不胜感激,一杯咖啡是我至少可以提供的有用建议。

// 编辑:

我忘了说我已经制作了某种映射数据框,但我还不能真正使用它。它看起来像这样:

mapping <- data.frame("Variable" = c("Var1", "Var2", "Var3", "Var4"),
                      "Value1" = c(2,2,2,7),
                      "Word1" = c("yes","yes","yes","condition A"),
                      "Value2" = c(1,1,1,6),
                      "Word2" = c("no","no","no","Condition B"),
                      "Value3" = c(8,8,8,5),
                      "Word3" = c("unk","unk","unk", "Condition C"),
                      "Value4" = c(NA,NA,NA,4),
                      "Word4" = c(NA,NA,NA,"Condition B")
                      )

我想对它进行“长”转换,以便我可以将它与@r2evan 的解决方案一起使用。

这是一个想法,尽管它需要重塑(两次)数据。

mapping <- data.frame(
  Var = c(rep("Var1", 3), rep("Var2", 5)),
  Val = c(1, 2, 8, 4, 5, 8, 10, 88),
  Words = c("no", "yes", "unk", "D", "E", "H", "H", "unk")
)
mapping
#    Var Val Words
# 1 Var1   1    no
# 2 Var1   2   yes
# 3 Var1   8   unk
# 4 Var2   4     D
# 5 Var2   5     E
# 6 Var2   8     H
# 7 Var2  10     H
# 8 Var2  88   unk

library(dplyr)
library(tidyr) # pivot_*
data %>%
  pivot_longer(-ID, names_to = "Var", values_to = "Val") %>%
  left_join(mapping, by = c("Var", "Val")) %>%
  pivot_wider(ID, names_from = "Var", values_from = "Words")
# # A tibble: 5 x 3
#      ID Var1  Var2 
#   <int> <chr> <chr>
# 1     1 yes   E    
# 2     2 yes   H    
# 3     3 unk   D    
# 4     4 no    unk  
# 5     5 unk   H    

使用此方法,您可以控制每个变量的数字到单词的映射。


另一种选择是使用地图列表,与上面类似,但不需要双重整形。

maplist <- list(
  Var1 = c("1" = "no", "2" = "yes", "8" = "unk"),
  Var2 = c("4" = "D", "5" = "E", "8" = "H", "10" = "H", "88" = "unk")
)
maplist
# $Var1
#     1     2     8 
#  "no" "yes" "unk" 
# $Var2
#     4     5     8    10    88 
#   "D"   "E"   "H"   "H" "unk" 
nms <- c("Var1", "Var2")
data[,nms] <- Map(function(val, lookup) lookup[as.character(val)], 
                  data[nms], maplist[nms])
data
#   ID Var1 Var2
# 1  1  yes    E
# 2  2  yes    H
# 3  3  unk    D
# 4  4   no  unk
# 5  5  unk    H

在这两者之间,如果您的数据不会因为重塑它而惩罚您,我想我更喜欢第一个(很多事情可能会降低它的吸引力)。它很好的一个原因是维护 mapping 可以像维护 CSV 一样简单(这可以在您最喜欢的电子表格工具中完成,例如 Excel 或 Calc)。

这是一种不需要重新调整原始数据的方法,并且可以想象地应用于任意数量的列。首先,将所有现有的“值”和“类别”向量放入列表中,将所有内容格式化为字符:

library(tidyverse)

# Recreating your existing vectors
Var1_values <- c(8, 2, 1)
Var2_values <- c(88, 10, 8, 5, 4)
Var1_categories <- c("unknown", "yes", "no")
Var2_categories <- c("unknown condition", "condition H", "condition H", "condition E", "condition D")

Var_values <- list(Var1_values, Var2_values) %>%
  map(as.character)

Var_categories <- list(Var1_categories, Var2_categories)

使用 Var_valuesVar_categories 中每个向量的每个元素添加名称,并获取要从数据集中重新编码的变量名称列表:

for (i in 1:length(Var_categories)) {
  names(Var_categories[[i]]) <- Var_values[[i]]
}

vars_names <- str_subset(colnames(data), "Var")

然后,使用 map2 重新编码所有目标变量,然后转换为带有 ID 列的 tibble。

  data_recoded <- map2(vars_names, Var_categories, ~ dplyr::recode(unlist(data[.x], use.names = F), !!!.y)) %>%
    as_tibble(.name_repair = ~ vars_names) %>%
    add_column(ID = 1:5, .before = "Var1")

输出(data_recoded):

     ID Var1    Var2             
  <int> <chr>   <chr>            
1     1 yes     condition E      
2     2 yes     condition H      
3     3 unknown condition D      
4     4 no      unknown condition
5     5 unknown condition H