2016-08-11 3 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

Хорошо, но предложения: нет причин не просто делать всю вещь по-разному; если обращение по столбцам будет вызвано, то подход будет состоять в использовании '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 - правда, хотя это предполагает, что действительные значения в реальных данных - всего один символ. Если нет, я полагаю, вы могли бы сделать «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 мин (вручную убит)

Смежные вопросы