2016-05-17 5 views
3

私はゼロの値を持つ複数の変数を持つdata.frameを持っています。私は、観測ごとにゼロでない変数の組み合わせを返す余分な変数を構築する必要があります。例えば。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)) 

今、私は新しい変数を生成したいと思います:

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

私は明らかに動作しませんでした、このような何かを考えた:

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

答えて

6

これはおそらくSOLV可能性EDは簡単apply(df, 1, fun)を使用しますが、ここでは代わりに、パフォーマンスのために賢明な行の賢明なこのコラムを解決するための試みである(私は一度@alexis_lazによって行わ同様のものを見ましたが、今はそれを見つけることができません)

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

大きなデータの

いくつかのベンチマークは、あなたが正しい考えを持っていたが、あなたのループ内の論理比較が正しくありませんでした

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

を適用する使用:

# 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

を設定します。

私はあなたの前に持っていたものとかなり類似したコードを維持しようとしましたが、これは動作するはずです:

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

感謝を!これまで提案されているすべてのソリューションは美しく機能します。だから、あなたのバージョンを最善のものとして選ぶのは私の好みの問題です。それはNAの交換が欠けているが、それは障害物ではなかった。 – Antti

+1

@Anttiそれだけでは味の問題ではありません。行方式の操作は、Rがvecotirzed言語であり、すべてが直感的である。最も遅いソリューションを選択しました。私の答えでいくつかのベンチマークを参照してください。ですから、あなたはその間に "* neatest *"を定義してください。 –

+0

@DavidArenburgは、私は絶対にそれが行方向Rにループ高速なソリューションではありません同意するものとします。私の防衛では、私はループが何が起こっているかを少しはっきりさせると思うし、元のコードに近づけようとしていたので、ロジックが質問者にとってより簡単になるだろう。 –

関連する問題