问题陈述:根据多列中的值生成虚拟变量。
根据列在其他“多列”中的存在,为列分配值(更像是虚拟变量)。以下代码使用数据框。
解释
代码用于解释所需的输出。
set.seed(12345)
df<- data.frame(A1=c(1L,2L),A2=LETTERS[1:3],A3=round(rnorm(4),4),A4=1:12)
df
names= paste0("V",c(1:12))
df[,c(names)]=0
for ( i in 1:nrow(df)){ df[i,c(names)]=match(c(1:12),df[i,c("A1","A4")])}
df[,c(names)][!is.na(df[,c(names)])]=1
df[,c(names)][is.na(df[,c(names)])]=0
df
我想对使用数据表的代码提出建议:=运算符,以便进程可以更快。感谢
答案 0 :(得分:3)
我们可以使用lapply
循环df
的'A1'和'A4'列,与sapply
的值1:12进行比较,使用Reduce
|
并将list
输出折叠为单个矩阵。 +
用于将逻辑矩阵转换为二进制格式。在最后一步中,我们cbind
使用原始数据集
cbind(df, +(Reduce('|', lapply(df[c(1,4)], function(x) sapply(1:12, '==', x)))))
没有循环的另一个base R
选项将是table
。我们unlist
感兴趣的列,即'A1','A4',获得table
1:12
值,双反否(!!
)使'0'值为FALSE使用+
将逻辑矩阵强制转换为二进制1/0
,将cbind
强制转换为原始数据集。
subDF <- df[c('A1', 'A4')]
newdf <- cbind(df, +(!!table(rep(1:12, ncol(subDF)), unlist(subDF))))
colnames(newdf)[5:ncol(newdf)] <- paste0('V', 1:12)
newdf
# A1 A2 A3 A4 V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12
#1 1 A 0.5855 1 1 0 0 0 0 0 0 0 0 0 0 0
#2 2 B 0.7095 2 0 1 0 0 0 0 0 0 0 0 0 0
#3 1 C -0.1093 3 1 0 1 0 0 0 0 0 0 0 0 0
#4 2 A -0.4535 4 0 1 0 1 0 0 0 0 0 0 0 0
#5 1 B 0.5855 5 1 0 0 0 1 0 0 0 0 0 0 0
#6 2 C 0.7095 6 0 1 0 0 0 1 0 0 0 0 0 0
#7 1 A -0.1093 7 1 0 0 0 0 0 1 0 0 0 0 0
#8 2 B -0.4535 8 0 1 0 0 0 0 0 1 0 0 0 0
#9 1 C 0.5855 9 1 0 0 0 0 0 0 0 1 0 0 0
#10 2 A 0.7095 10 0 1 0 0 0 0 0 0 0 1 0 0
#11 1 B -0.1093 11 1 0 0 0 0 0 0 0 0 0 1 0
#12 2 C -0.4535 12 0 1 0 0 0 0 0 0 0 0 0 1
我们也可以使用data.table
。我不确定这是否非常有效,因为我们在table
内data.table
。方法是首先将'data.frame'转换为'data.table'(setDT(df)
),unlist
.SDcols
中指定的列,获取seq_len
行数(.N
),即示例中的1:12,通过'{1}}的'{1}}复制(rep
),得到length
。< / p>
我们从table
类(data.table
)创建table
,通过使用split(tbl..
循环遍历列,我们for
的值为set
二进制0/1
。 set
方法是有效的,因为它避免了[.data.table
的开销。稍后,我们可以cbind
使用原始数据集。
library(data.table)
nm1 <- c('A1', 'A4')
tbl <- setDT(df)[, table(rep(seq_len(.N),length(nm1)), unlist(.SD)), .SDcols=nm1]
dt1 <- setDT(split(tbl, col(tbl)))[]
for(j in seq_along(dt1)) {
set(dt1, i=NULL, j=j, value=+(!!dt1[[j]]))
}
cbind(df, dt1)