识别编码为 1/2 的变量(虚拟变量)并转换为 0/1

Identify variables (dummies) coded as 1/2 and transform to 0/1

在更大的数据集中,我想识别编码为 1/2 的变量(虚拟变量)并将它们转换为 0/1。它们可能包含缺失。

## test dataset:
df <- data.frame(
  c(1,2,2,1,2,NA,NA,1,2,NA),
  c(1,2,2,1,2,1,2,1,2,2),
  c(0,1,NA,1,1,0,NA,1,NA,0),
  c(0,1,1,1,1,0,0,1,1,0))
names(df) <- c("A","B","C","D")

应转换列 A 和 B,列 C 和 D 应保持不变。

## attempts:
df2 <- select(df, function(x) {x %in% c(1,2,NA)})
df2 <- sapply(df, function(x) {(x %in% c(1,2,NA))})

一旦确定(我还无法实现),我想像这样转换这些列:1 到 0,2 到 1。最后我的目标是让 df2 与 df 具有相同的维度。

提前致谢!!

您可以减去 1 或测试是否等于 2

i <- colSums(df == 2, na.rm=TRUE) > 0 & colSums(df == 0, na.rm=TRUE) == 0
#i <- sapply(df, function(x) all(x[!is.na(x)] %in% 1:2)) #Alternative
#Will not work in case there is only 1 in the column

df[, i] <- df[, i] - 1
#df[, i] <- +(df[, i] == 2) #Alternative

df
#    A B  C D
#1   0 0  0 0
#2   1 1  1 1
#3   1 1 NA 1
#4   0 0  1 1
#5   1 1  1 1
#6  NA 0  0 0
#7  NA 1 NA 0
#8   0 0  1 1
#9   1 1 NA 1
#10 NA 1  0 0

如果您想有条件地通过 tidyverse 进行操作;

library(dplyr)

df %>%
mutate(A = case_when(A==1 ~ 0,
                     A==2 ~ 1),
       B = case_when(B==1 ~ 0,
                     B==2 ~ 1))

输出;

       A     B     C     D
   <dbl> <dbl> <dbl> <dbl>
 1     0     0     0     0
 2     1     1     1     1
 3     1     1    NA     1
 4     0     0     1     1
 5     1     1     1     1
 6    NA     0     0     0
 7    NA     1    NA     0
 8     0     0     1     1
 9     1     1    NA     1
10    NA     1     0     0

您只需使用ifelse

df$A = ifelse(df$A == 1, 0, 1)
df$B = ifelse(df$A == 1, 0, 1)
    A B  C D AA
1   0 0  0 0  0
2   1 1  1 1  1
3   1 1 NA 1  1
4   0 0  1 1  0
5   1 1  1 1  1
6  NA 0  0 0 NA
7  NA 1 NA 0 NA
8   0 0  1 1  0
9   1 1 NA 1  1
10 NA 1  0 0 NA

在每列中检查是否所有非 NA 值都在 1:2 中,如果是,则从每个值中减去 1。

library(dplyr)
df2 <- df %>%
  mutate(across(where(~ all(na.omit(.) %in% 1:2)), ~ .x - 1))

或仅使用基数 R:

ok <- sapply(df, function(x) all(na.omit(x) %in% 1:2))
df2 <- replace(df, ok, df[ok] - 1)

注意问题中固有的歧义(尽管幸运的是 none 问题中的列具有这种歧义)——即,如果一列仅包含 1 或仅包含 1 和NA 那么我们无法知道它代表的是 0:1 还是 1:2 列。为了解决歧义,上面的代码假定前者,但是如果下面返回的集合中有任何列,那么如果这个默认值不能正确解决它,那么就需要使用应用程序知识来解决歧义。

which(sapply(df, function(x) all(na.omit(x) == 1)))