自动将二进制变量编码为因子?

automatically code binary variables as factors?

我有一个问题:是否有 R 函数可以自动将二进制变量编码为因子?

我有超过 80 个变量(列),其中许多是布尔性质的(0、1 和 NA),R 作为 numeric 导入。因为我想避免手动将它们转换为 因子 ,所以我想知道是否有一个函数能够自动检测 二进制数值变量 data.frame(或 tibble)并将它们转换为因数?我可以自己创建这样一个函数,但如果它已经存在,何必呢?

您可以使用 where tidyselect 函数:

library(dplyr)
data %>% 
  mutate(across(where(~all(unique(.[!is.na(.)]) %in% c("0","1"))), as.factor))

where的参数必须是returnsTRUEFALSE的函数。这里我使用 unique 来确保所有的值都是 01。使用 %in% 有助于处理二进制变量实际编码在字符向量中的边缘情况。由于 0L %in% "0"0 %in% "0""0" %in% "0" 都计算 TRUE

然后仅当提供给 where 的函数计算 TRUE.

时,交叉才将 as.factor 应用于列
data %>% 
  dplyr::summarise(across(everything(), class))
#       V1      V2      V3      V4      V5      V6      V7      V8      V9     V10
#1 numeric numeric numeric numeric numeric numeric numeric numeric numeric numeric

data %>%
  mutate(across(where(~all(unique(.[!is.na(.)]) %in% c("0","1"))), as.factor)) %>% 
  dplyr::summarise(across(everything(), class))
#      V1     V2     V3     V4     V5      V6      V7      V8      V9     V10
#1 factor factor factor factor factor numeric numeric numeric numeric numeric

一些示例数据:

data <- setNames(as.data.frame(cbind(replicate(5,sample(c(0,1,NA),10, replace = TRUE)),
                                     replicate(5,runif(10,0,100)))),paste0("V",1:10))

下面我们假设一个列只要

就被认为是二进制的
  • 不全是 NA 并且
  • 除了 NA 之外,它仅由数字 0 和 1 值组成。

请注意,完全为 0 和 NA 或完全为 1 和 NA 的列被视为二进制,但如果这是不可取的,我们将展示如何更改代码以要求二进制列同时具有 0 和 1。

首先定义一个函数is_binary,定义一个列是否被视为二进制。如果你想改变二进制的定义,这个函数可以改变。如果一列必须同时具有 0 和 1 才能将其视为二进制,请特别在下面的代码中将 1:2 更改为 2。如果需要,可以使用其他定义。

接下来将 is_binary 应用于每一列,返回一个逻辑向量 ok,如果该列是二进制的,则每列一个分量为 TRUE,否则为 FALSE。

在计算答案 DF2 的行中,我们使用参数 levels = 0:1factor 应用于每个二进制列,以确保仅具有 0 或仅具有 1 的列仍然具有两者级别。

没有使用包。

DF <- data.frame(a = c(0:1, NA), b = 1:3, c = NA, d = 0) # test data frame

is_binary <- function(x) {
  x0 <- na.omit(x)
  is.numeric(x) && length(unique(x0)) %in% 1:2 && all(x0 %in% 0:1)
}
ok <- sapply(DF, is_binary)
DF2 <- replace(DF, ok, lapply(DF[ok], factor, levels = 0:1))

str(DF2)
## 'data.frame':   3 obs. of  4 variables:
##  $ a: Factor w/ 2 levels "0","1": 1 2 NA
##  $ b: int  1 2 3
##  $ c: logi  NA NA NA
##  $ d: Factor w/ 2 levels "0","1": 1 1 1

我们可以像这样将 dplyr 与 is_binary 交替使用:

DF %>% mutate(across(where(is_binary), ~ factor(., levels = 0:1)))

如果您喜欢 tidyverse,那么将 @G.Grothendieck 的 is_binary()mutate_if 结合使用效果很好。

library(dplyr)
DF <- data.frame(a = c(0:1, NA), b = 1:3, c = NA, d = 0) # test data frame
is_binary <- function(x) {
 x0 <- na.omit(x)
 length(unique(x0)) %in% 1:2 && all(x0 %in% 0:1)
}
DF %>% mutate_if(is_binary, factor)