51

バックグラウンド

いくつかの SQL 言語 (主に postgreSQL を使用) には、各行の最初の非 null 列要素を返す、coalesce という関数があります。これは、テーブルに多くのNULL要素が含まれている場合に非常に効率的に使用できます。

多くのNAが含まれているあまり構造化されていないデータを扱う場合にも、Rの多くのシナリオでこれに遭遇します。

私は単純な実装を自分で作成しましたが、途方もなく遅いです。

coalesce <- function(...) {
  apply(cbind(...), 1, function(x) {
          x[which(!is.na(x))[1]]
        })
}

a <- c(1,  2,  NA, 4, NA)
b <- c(NA, NA, NA, 5, 6)
c <- c(7,  8,  NA, 9, 10)
coalesce(a,b,c)
# [1]  1  2 NA  4  6

質問

coalesceRで実装する効率的な方法はありますか?

4

8 に答える 8

19

dplyrパッケージの使用:

library(dplyr)
coalesce(a, b, c)
# [1]  1  2 NA  4  6

ベンチマーク、承認されたソリューションほど高速ではありません:

coalesce2 <- function(...) {
  Reduce(function(x, y) {
    i <- which(is.na(x))
    x[i] <- y[i]
    x},
    list(...))
}

microbenchmark::microbenchmark(
  coalesce(a, b, c),
  coalesce2(a, b, c)
)

# Unit: microseconds
#                expr    min     lq     mean median      uq     max neval cld
#   coalesce(a, b, c) 21.951 24.518 27.28264 25.515 26.9405 126.293   100   b
#  coalesce2(a, b, c)  7.127  8.553  9.68731  9.123  9.6930  27.368   100  a 

しかし、より大きなデータセットでは、比較できます:

aa <- sample(a, 100000, TRUE)
bb <- sample(b, 100000, TRUE)
cc <- sample(c, 100000, TRUE)

microbenchmark::microbenchmark(
  coalesce(aa, bb, cc),
  coalesce2(aa, bb, cc))

# Unit: milliseconds
#                   expr      min       lq     mean   median       uq      max neval cld
#   coalesce(aa, bb, cc) 1.708511 1.837368 5.468123 3.268492 3.511241 96.99766   100   a
#  coalesce2(aa, bb, cc) 1.474171 1.516506 3.312153 1.957104 3.253240 91.05223   100   a
于 2017-01-24T08:19:57.580 に答える
4

非常に簡単な解決策は、パッケージの関数を使用することですifelsebase

coalesce3 <- function(x, y) {

    ifelse(is.na(x), y, x)
}

上記より遅いように見えますがcoalesce2

test <- function(a, b, func) {

    for (i in 1:10000) {

        func(a, b)
    }
}

system.time(test(a, b, coalesce2))
user  system elapsed 
0.11    0.00    0.10 

system.time(test(a, b, coalesce3))
user  system elapsed 
0.16    0.00    0.15 

を使用Reduceして、任意の数のベクトルに対して機能させることができます。

coalesce4 <- function(...) {

    Reduce(coalesce3, list(...))
}
于 2015-08-25T12:22:49.560 に答える
1

これが私の解決策です:

coalesce <- function(x){ y <- head( x[is.na(x) == F] , 1) return(y) } NA ではない最初の値を返しますdata.table。たとえば、いくつかの列で合体を使用したい場合、これらの列名は文字列のベクトルです。

column_names <- c("col1", "col2", "col3")

使い方:

ranking[, coalesce_column := coalesce( mget(column_names) ), by = 1:nrow(ranking)]

于 2015-11-02T14:43:44.203 に答える