2016-12-27 4 views
3

Скажем, у меня есть data.table такие, как: (или с цифрами и НСБУ)R data.table применить функцию для всех пар столбцов

temp <- data.table(M=c(NA,T,T,F,F,F,NA,NA,F), 
        P=c(T,T,T,F,F,F,NA,NA,NA), S=c(T,F,NA,T,F,NA,NA,NA,NA)) 

    M  P  S 
    NA TRUE TRUE 
TRUE TRUE FALSE 
TRUE TRUE NA 
FALSE FALSE TRUE 
FALSE FALSE FALSE 
FALSE FALSE NA 
    NA NA NA 
    NA NA NA 
FALSE NA NA 

И я хочу, чтобы проверить, когда переменная NA означает что значения второй переменной - все NA. Проверить, связаны ли некоторые переменные с другими.

Например, когда P = NA, мы также имеем S = NA.

Этот код работает правильно для двух отдельных колонок:

temp[is.na(P),all(is.na(S))] 

дает TRUE,

и

temp[is.na(S),all(is.na(P))] 

дает FALSE, потому что шестой строка S = NA, но P = NA!.

Теперь мой вопрос. Я хотел бы обобщить его, проверив все пары в моей таблице data.table и напечатаю, какие пары «связаны».
Я бы предпочел напечатать только те результаты, которые являются ИСТИНАМИ, игнорируя FALSE, потому что большинство пар в моей реальной таблице данных не будут связаны, и у меня есть 550 переменных.

Я попробовал этот код:

temp[, lapply(.SD, function(x) temp[is.na(x), 
       lapply(.SD, function(y) all(is.na(y)))]] 

Я получаю эту ошибку

Error: unexpected ']' in: "temp[, lapply(.SD, function(x) temp[is.na(x), lapply(.SD, function(y) all(is.na(y)))]]"

Я мог бы попробовать с цикл, но я бы предпочел типичный data.table синтаксис. Любые предложения приветствуются.

Я также хотел бы знать, как обращаться к двум различным .SD, когда вы вставляете вызовы data.table.

ответ

5

Для комбинаций пар, crossprod кажется еще полезным.

Мы заботимся только для того, является ли NA или нет значение:

NAtemp = is.na(temp) 

Сравните сосуществование NA с:

crossprod(NAtemp) 
# M P S 
#M 3 2 2 
#P 2 3 3 
#S 2 3 5 

с числом NA в колонке:

colSums(NAtemp) 
#M P S 
#3 3 5 

подобный:

ans = crossprod(NAtemp) == colSums(NAtemp) 
ans 
#  M  P  S 
#M TRUE FALSE FALSE 
#P FALSE TRUE TRUE 
#S FALSE FALSE TRUE 

И использовать удобный as.data.frame.table для форматирования:

subset(as.data.frame(as.table(ans)), Var1 != Var2) 
# Var1 Var2 Freq 
#2 P M FALSE 
#3 S M FALSE 
#4 M P FALSE 
#6 S P FALSE 
#7 M S FALSE 
#8 P S TRUE 
+0

Невозможно ли это сделать с помощью data.table? (по причинам скорости) – skan

+0

@skan: Я считаю, что единственная вещь, которую можно использовать (относительно эффективности) - последняя строка - например, что-то вроде 'ij = which (col (ans)! = row (ans), TRUE); data.frame (v1 = rownames (ans) [ij [, "row"]], v2 = colnames (ans) [ij [, "col"]], val = ans [ij]) 'может избежать некоторых накладных расходов. «crossprod» предлагает очень удобный алгоритм для эффективного вычисления всех парных комбинаций на матрицах, а также итоговая матрица 550 * 550 не вызывает проблем с памятью. Вы нашли какое-то узкое место на бенчмарке? –

+0

ОК, завтра я применим ваш ответ и akrun один к моему большому набору данных и сделаю тест и определю, кто победитель. – skan

3

Мы можем попытаться с combn

unlist(combn(names(temp), 2, FUN = function(nm) 
    list(setNames(temp[is.na(get(nm[1])), all(is.na(get(nm[2])))], paste(nm, collapse="-"))))) 
# M-P M-S P-S 
# FALSE FALSE TRUE 

Или, если мы нужны все комбинации

d1 <- CJ(names(temp), names(temp))[V1!=V2] 
d1[, .(index=temp[is.na(get(V1)), all(is.na(get(V2)))]) , .(V1, V2)] 
# V1 V2 index 
#1: M P FALSE 
#2: M S FALSE 
#3: P M FALSE 
#4: P S TRUE 
#5: S M FALSE 
#6: S P FALSE 
+0

Ваше решение очень компактна и использует data.table, но я не знаю, почему, когда данные имеют много столбцов (у меня есть 500, но вы можете см. его даже с 50). Решение @alexis_laz на несколько порядков. – skan

+0

И я думаю, что ваш первый гребень кода (имена (temp)) должен быть повторен с измененным порядком изменения. – skan

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