逐行将值分配给多个列

时间:2015-08-14 09:16:50

标签: r

问题陈述:根据多列中的值生成虚拟变量。

根据列在其他“多列”中的存在,为列分配值(更像是虚拟变量)。以下代码使用数据框。

解释

  • V2列表示值2.如果变量A1或A4,则具有 值2然后V2 = 1且V1,V3:V12 = 0
  • 同样,如果A1 = 1且A2 = 4,那么 V1 = 1,V4 = 1,V2,V3,V5:V12 = 0

代码用于解释所需的输出。

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

我想对使用数据表的代码提出建议:=运算符,以便进程可以更快。感谢

1 个答案:

答案 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。我不确定这是否非常有效,因为我们在tabledata.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/1set方法是有效的,因为它避免了[.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)