2016-05-04 11 views
2

Ich habe eine logische Datenrahmen wie:Merge gleiche Spaltennamen eines logischen/Binär-Datenrahmen

> 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 

Mein Ziel ist es, die Säule mit dem gleichen Spaltennamen zu kombinieren. Das heißt, die Ausgabe sollte ein Datenrahmen mit 4 Spalten sein (Apfel, Kiwi, Banane, Orange).

Ich habe versucht:

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

Aber der Ausgang ist nicht das, was ich sehe. Für jede Zeile mit demselben Spaltennamen sollte die Ausgabe True sein, solange mindestens 1 TRUE vorhanden ist. Für jede Zeile mit demselben Spaltennamen sollte die Ausgabe False sein, wenn 0 TRUE ist.

Für die erste Zeile in der ersten Spalte sollte TRUE anstelle von FALSE sein.

Unerwünschte testmerge Ausgabe:

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

gewünschte Ausgabe:

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

Replizieren Datenrahmen:

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") 

Antwort

3

Mit sapply und 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 

Wir datafame basierend auf Obst Namen subsetting, dann Berechnung rowSums. TRUE ist 1 und FALSE ist 0, so dass rowSums von mehr als Null mindestens einen TRUE-Wert haben. Ich habe drop = FALSE, so wird die Teilmenge als ein Datenrahmen in Fällen wie orange bleiben, wo es nur eine Spalte gibt.

Hinweis: Wenn die Daten lang ist dann Reduce() Lösung von @akrun funktioniert besser, aber wenn Daten breit ist dann rowSums() ist effizienter. basierend auf dem numerischen Index verwenden Reduce zu überprüfen, ob es irgendwelche TRUE in jeder Reihe

2

Es gibt vielleicht effizientere Wege, dies zu erreichen, aber hier ein versuchen

Ich würde vorschlagen, die Spaltennamen in Unique mit make.unique zu konvertieren, dann in langes Format konvertieren, überprüfen Sie Ihren Zustand durch eine Zeilen-ID und die Spaltennamen (wieder einzigartig gemacht) und dann wieder in ein breites Format, etwas wie

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

vielen dank für diese lösung – S12000

2

wäre eine weitere Möglichkeit, durch die names davon in eine list, Schleife durch die list, Teilmenge der Sequenz von Spalten des Datensatzes zu split sein .

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

Das ist schön 'Reduce (' | ', test [i])'! – zx8754

+1

Vielen Dank für diese Lösung – S12000

Verwandte Themen