2016-08-11 76 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分鐘(手動殺死)