2016-05-04 3 views
2

У меня есть логический dataframe как:Объединить же имена столбцов логической/бинарного dataframe

> test 
    apple apple apple kiwi kiwi banana banana banana apple orange 
1 FALSE TRUE FALSE FALSE TRUE FALSE TRUE TRUE TRUE FALSE 
2 TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE FALSE 
3 FALSE FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE FALSE 

Моя цель состоит в том, чтобы объединить столбец с таким же именем столбца. То есть вывод должен быть файловой рамкой с 4 колонками (яблоко, киви, банан, оранжевый).

Я пробовал:

testmerge <- df[, !duplicated(colnames(df))] 

Но выход не то, что я ищу. Для каждой строки с таким же именем столбца вывод должен быть истинным, так как длится по крайней мере 1 TRUE. Для каждой строки с одинаковым именем столбца вывод должен быть False, если существует 0 ИСТИНА.

Для первого первого столбца первой строки должно быть TRUE вместо FALSE.

Нежелательная testmerge выход:

apple kiwi banana orange 
1 FALSE FALSE FALSE FALSE 
2 TRUE TRUE TRUE FALSE 
3 FALSE TRUE FALSE FALSE 

Желаемый результат:

apple kiwi banana orange 
1 TRUE TRUE TRUE FALSE 
2 TRUE TRUE TRUE FALSE 
3 FALSE TRUE FALSE FALSE 

Replicate dataframe:

test <- structure(list(apple = c(FALSE, TRUE, FALSE), apple = c(TRUE, TRUE, 
FALSE), apple = c(FALSE, TRUE, FALSE), kiwi = c(FALSE, TRUE, TRUE 
), kiwi = c(TRUE, TRUE, TRUE), banana = c(FALSE, TRUE, FALSE), banana = c(TRUE, 
FALSE, FALSE), banana = c(TRUE, TRUE, FALSE), apple = c(TRUE, TRUE, 
FALSE), orange = c(FALSE, FALSE, FALSE)), .Names = c("apple", "apple", 
"apple", "kiwi", "kiwi", "banana", "banana", "banana", "apple", "orange"), row.names = c(NA, 
-3L), class = "data.frame") 

ответ

3

Использование sapply и rowSums:

as.data.frame(
    sapply(unique(colnames(test)), 
     function(i){ 
      rowSums(test[, grepl(i, colnames(test)), drop = FALSE]) > 0}) 
) 

#output 
# apple kiwi banana orange 
# 1 TRUE TRUE TRUE FALSE 
# 2 TRUE TRUE TRUE FALSE 
# 3 FALSE TRUE FALSE FALSE 

Мы Подменю datafame на основе фруктовых имен, то вычислительные rowSums. TRUE равно 1, а FALSE равно 0, поэтому rowSums больше нуля будут иметь хотя бы одно значение TRUE. У меня есть drop = FALSE, поэтому подмножество останется в виде кадра данных в таких случаях, как orange, где есть только один столбец.

Примечание: Если данные долго затем уменьшить() решение по @akrun работает лучше, но если данные широка затем rowSums() является более эффективным.

2

Там, может быть, более эффективные способы для достижения этой цели, но вот попробовать

Я бы предложил преобразовать имена столбцов в уникальные, используя make.unique, а затем преобразовать в длинный формат, проверить ваше состояние на идентификатор строки и имена столбцов (сделанный уникальный снова), а затем преобразовать обратно в широкий формат, что-то вроде

library(data.table) 
setnames(setDT(test), make.unique(names(test))) # Make column names unique 
res <- melt(test[, id := .I], id = "id" # Add a row index and melt by it 
      )[, sum(value) > 0, # Check condition >> 
       by = .(id, Names = sub("\\..*", "", variable))] # by row id and unique names 
dcast(res, id ~ Names, value.var = "V1") # Convert back to wide format 
# id apple banana kiwi orange 
# 1: 1 TRUE TRUE TRUE FALSE 
# 2: 2 TRUE TRUE TRUE FALSE 
# 3: 3 FALSE FALSE TRUE FALSE 
+0

спасибо большое за это решение – S12000

2

Другим вариантом было бы, чтобы split последовательность столбцов набора данных по names его в list, петля через list, подмножество основано на числовой индекс, использовать Reduce, чтобы проверить, есть ли какие-либо TRUE, в каждой строке ,

sapply(split(seq_along(test), names(test)), function(i) Reduce(`|`, test[i])) 
#  apple banana kiwi orange 
#[1,] TRUE TRUE TRUE FALSE 
#[2,] TRUE TRUE TRUE FALSE 
#[3,] FALSE FALSE TRUE FALSE 
+1

Это красиво 'Сократить (' | ', test [i])'! – zx8754

+1

благодарит за это решение – S12000