2016-08-11 75 views
5

我有一个看起来像这样的稀疏数据表:计算上的多个列名在data.table

data = data.table(
    var1 = c("a","",""), 
    var2 = c("","","c"), 
    var3 = c("a","b",""), 
    var4 = c("","b","") 
) 
     var1 var2 var3 var4 
    1: a   a  
    2:    b b 
    3:   c  

我想补充一点,包含零和一的指示哪些变量是一弦一柱目前在任一行,就像这样:

var1 var2 var3 var4 concat 
1: a   a  1|0|1|0 
2:    b b 0|0|1|1 
3:   c   0|1|0|0 

我能得到这个使用下面的命令:

data[, concat := paste(
      as.integer(var1 != ""), 
      as.integer(var2 != ""), 
      as.integer(var3 != ""), 
      as.integer(var4 != ""), 
      sep = "|")] 

但是,如果我有数百个变量,我宁愿使用某种计算来获得所需的表达式。可能是基于paste0("var",1:4)的东西,或者至少是一个列名称向量。有什么建议么?

回答

4

相同的基本如上述的方法:

data[ , concat := apply(.SD, 1, function(x) paste(+(x == ""), collapse = "|"))][] 
# var1 var2 var3 var4 concat 
# 1: a   a  0|1|0|1 
# 2:    b b 1|1|0|0 
# 3:   c   1|0|1|1 
+0

我真的很惊讶,循环播放每一行的速度都快于将它们粘贴为列。但无论我认为应该发生什么,似乎都是这种情况! :-P – thelatemail

2
data$concat <- apply(apply(data, 2, function(x) ifelse(x == "", 0, 1)), 1, function(x) paste(x, collapse="|")) 

击穿:

1)对于data每一列,检查是否元素是空的,如果是的话返回0,否则1

apply(data, 2, function(x) ifelse(x == "", 0, 1)) 

我们称之为从返回(1)变量concat。对于每行concat,将所有内容粘贴在一起并用管道(|)将它们分开。将新列data设置为等于此值。

apply(concat, 1, function(x) paste(x, collapse="|")) 
+0

不错,但建议:没有理由不要只是把整个事情按行进行;如果按照列方式调用_were_,则方法是使用'lapply(.SD,“==”,“”)'; ['ifelse'很慢](http://stackoverflow.com/questions/16275149/does-ifelse-really-calculate-both-of-its-vectors-every-time-is-it-slow),所以避免它;并且这个具有'[data.table]'标签,你应该[通过引用分配':='](https://rawgit.com/wiki/Rdatatable/data.table/vignettes/datatable-reference- semantics.html) – MichaelChirico

+0

会问你关于'。SD',之前从未见过,我更喜欢你的答案,但我只是发布了我自己的工作。 – TomNash

1

另一种选择是对数据进行分组由行和每行粘贴在一起:

data[,concat := paste0(as.integer(.SD != ""), collapse = "|"), by = 1:nrow(data)] 
data 
# var1 var2 var3 var4 concat 
#1: a   a  1|0|1|0 
#2:    b b 0|0|1|1 
#3:   c   0|1|0|0 
4

变化不需要由每一行任何分组或每行上的apply

data[, concat := do.call(paste, c(lapply(.SD, function(x) (x!="")+0), sep="|")) ] 

# var1 var2 var3 var4 concat 
#1: a   a  1|0|1|0 
#2:    b b 0|0|1|1 
#3:   c   0|1|0|0 
+1

而不是所有的平等测试,然后是强制(在每个答案中),我可以使用'nchar'。 – Frank

+1

@Frank - true,尽管假设真实数据中的有效值都只是一个字符。如果不是的话,我想你可以用'pmin'或其他东西来加以限制,但这只是增加了复杂性。 – thelatemail

2

感谢您提供了多种多样的解决方案。我很佩服!

我在我的大数据集上做了一些基准比较,以比较几种不同方法的运行时间。以下是我发现:

data[ , concat := apply(.SD, 1, function(x) paste(+(x == ""), collapse = "|"))] 

时间:6分钟,41号

data[, concat := do.call(paste, c(lapply(.SD, function(x) (x!="")+0), sep="|")) ] 

时间:10分钟,26号

data[,concat := paste0(as.integer(.SD != ""), collapse = "|"), by = 1:nrow(data)] 

时间:> 40分钟(手动杀死)