2016-05-17 4 views
3

Ich habe ein data.frame, das mehrere Variablen mit Nullwerten hat. Ich muss eine zusätzliche Variable konstruieren, die die Kombination von Variablen zurückgibt, die für jede Beobachtung nicht Null sind. Z.B.Wie erstellt man eine Kombinationsvariable in R data.frame?

df <- data.frame(firm = c("firm1", "firm2", "firm3", "firm4", "firm5"), 
       A = c(0, 0, 0, 1, 2), 
       B = c(0, 1, 0, 42, 0), 
       C = c(1, 1, 0, 0, 0)) 

Nun möchte Ich mag die neue Variable generieren:

df$varCombination <- c("C", "B-C", NA, "A-B", "A") 

ich so etwas wie dies erdacht, was natürlich nicht funktioniert:

for (i in 1:nrow(df)){ 
    df$varCombination[i] <- paste(names(df[i,2:ncol(df) & > 0]), collapse = "-") 
} 

Antwort

6

Dies könnte wahrscheinlich solv sein ed apply(df, 1, fun) mit leicht, aber hier ist ein Versuch, diese spaltenweise statt zeilenweise Performancegründen (ich sah ähnlich von @alexis_laz etwas getan einmal, sondern kann es jetzt nicht finden) zu lösen

## Create a logical matrix 
tmp <- df[-1] != 0 
## or tmp <- sapply(df[-1], `!=`, 0) 

## Prealocate result 
res <- rep(NA, nrow(tmp)) 

## Run per column instead of per row 
for(j in colnames(tmp)){ 
    res[tmp[, j]] <- paste(res[tmp[, j]], j, sep = "-") 
} 

## Remove the pre-allocated `NA` values from non-NA entries 
gsub("NA-", "", res, fixed = TRUE) 
# [1] "C" "B-C" NA "A-B" "A" 

Einige Benchmarks auf einen größeren Datensatz

set.seed(123) 
BigDF <- as.data.frame(matrix(sample(0:1, 1e4, replace = TRUE), ncol = 10)) 

library(microbenchmark) 

MM <- function(df) { 
    var_names <- names(df)[-1] 
    res <- character(nrow(df)) 
    for (i in 1:nrow(df)){ 
    non_zero_names <- var_names[df[i, -1] > 0] 
    res[i] <- paste(non_zero_names, collapse = '-') 
    } 
    res 
} 

ZX <- function(df) { 
    res <- 
    apply(df[,2:ncol(df)]>0, 1, 
      function(i)paste(colnames(df[, 2:ncol(df)])[i], collapse = "-")) 
    res[res == ""] <- NA 
    res 
} 

DA <- function(df) { 
    tmp <- df[-1] != 0 
    res <- rep(NA, nrow(tmp)) 

    for(j in colnames(tmp)){ 
    res[tmp[, j]] <- paste(res[tmp[, j]], j, sep = "-") 
    } 
    gsub("NA-", "", res, fixed = TRUE) 
} 


microbenchmark(MM(BigDF), ZX(BigDF), DA(BigDF)) 
# Unit: milliseconds 
#  expr  min   lq  mean  median   uq  max neval cld 
# MM(BigDF) 239.36704 248.737408 253.159460 252.177439 255.144048 289.340528 100 c 
# ZX(BigDF) 35.83482 37.617473 38.295425 38.022897 38.357285 76.619853 100 b 
# DA(BigDF) 1.62682 1.662979 1.734723 1.735296 1.761695 2.725659 100 a 
5

Verwendung gelten:

# paste column names 
df$varCombination <- 
    apply(df[,2:ncol(df)]>0, 1, 
     function(i)paste(colnames(df[, 2:ncol(df)])[i], collapse = "-")) 

# convert blank to NA 
df$varCombination[df$varCombination == ""] <- NA 

# result 
df 
# firm A B C varCombination 
# 1 firm1 0 0 1    C 
# 2 firm2 0 1 1   B-C 
# 3 firm3 0 0 0   <NA> 
# 4 firm4 1 42 0   A-B 
# 5 firm5 2 0 0    A 
1

Sie hatte die richtige Idee, aber die logische Vergleich in der Schleife war nicht korrekt.

ich versucht habe den Code ziemlich ähnlich zu halten, was vor dir hatte, sollte diese Arbeit:

var_names <- names(df)[-1] 

df$varCombination <- character(nrow(df)) 

for (i in 1:nrow(df)){ 

    non_zero_names <- var_names[df[i, -1] > 0] 

    df$varCombination[i] <- paste(non_zero_names, collapse = '-') 

} 

> df 
    firm A B C varCombination 
1 firm1 0 0 1    C 
2 firm2 0 1 1   B-C 
3 firm3 0 0 0    
4 firm4 1 42 0   A-B 
5 firm5 2 0 0    A 
+0

Dank! Alle bisher vorgeschlagenen Lösungen funktionieren wunderbar. Es ist also nur Sache meines Geschmacks, deine Version als die sauberste zu wählen. Es fehlt der NA-Ersatz, aber das war nicht der Stolperstein. – Antti

+1

@Antti es ist nicht nur eine Frage des Geschmacks. Row-wise Operationen sind contr-intuitiv in R eine vecotirzed Sprache und alle. Sie haben die langsamste Lösung mit Abstand gewählt. Sehen Sie einige Benchmarks in meiner Antwort. Also definiere "* neatest *" während du dabei bist. –

+0

@DavidArenburg Ich stimme absolut zu, dass reihenweise Schleife in R keine schnelle Lösung ist. Zu meiner Verteidigung glaube ich, dass die Schleife es ein wenig klarer macht, was passiert und ich versuchte, es nahe am ursprünglichen Code zu halten, so dass die Logik dem Fragesteller leichter folgen würde. –

Verwandte Themen