识别编码为 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)))
在更大的数据集中,我想识别编码为 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)))