4

foreach各ループ内にリストを生成するループと、次.combineのようにそれらを結合する関数があります。

mergelists = function(x,xn) {
  padlen = length(x[[1]])
  for (n in names(x)[!names(x) %in% names(xn)])  xn[[n]] = 0
  for (n in names(xn)[!names(xn) %in% names(x)]) xn[[n]] = c(rep(0,padlen), xn[[n]])
  for (idx in names(xn)) { x[[idx]] = c( x[[idx]], xn[[idx]] ) }
  x
}

最初の 2 つの for ループは、新しいリスト ( xn) を変更して、結果を収集するリスト ( ) と互換性を持たせxます。最後の 1 つは と に結合xxnますx

私のコードは途方もなく非効率的だと思います。なぜなら、再割り当てが多く、for ループを使用しているからです。しかし、私はより良い解決策について考えることができません。何か案は?

いくつかの詳細な説明: リスト名は事前にわかりません (それらは foreach 部分で行われるブートストラップ演習のパターンです)。

例:

> x
$foo
[1] 3 2

$bar
[1] 3 2

> xn
$foo
[1] 1

$baz
[1] 1

に参加する必要があります

> x
$foo
[1] 3 2 1

$bar
[1] 3 2 0

$baz
[1] 0 0 1

それでおしまい。

4

2 に答える 2

3

foo と bar がすべてのリストに存在し、順番に並んでいる場合、mapply は機能します。@BenBarnesが示唆したように、0を作成するための前処理ステップがあると、たとえそれらがどこにも存在しない場合でも、これが実行可能なオプションになります。並べ替えは簡単です。より適切と思われるため、0 を NA に変更しました。

# Make data
x <- list(foo=c(3,2),bar=c(6,7))
xn <- list(foo=c(1),bar=c(1),aught=c(5,2))
lol <- list(x=x,xn=xn)

# Pre-process
allnames <- sort(unique(unlist(lapply(lol, names))))
cleanlist <- function(l,allnames) {
  ret <- l[allnames]
  names(ret) <- allnames
  ret[sapply(ret,is.null)] <- NA
  ret
}
lol <- lapply(lol,cleanlist,allnames=allnames)

# Combine
do.call("mapply", c(c,lol) )

生成するもの:

    aught bar foo
x      NA   6   3
xn1     5   7   2
xn2     2   1   1

ベンチマーク

とはいえ、速度の向上を期待しているのであれば、元のバージョンが依然として最速です。しかし、ループのないアプローチは非常に洗練されており、任意の数の x にスケーリングします。

library(microbenchmark)
microbenchmark( mergelists(lol$x,lol$xn), mergeList2(lol$x,lol$xn), do.call("mapply", c(c,lol) ) )

Unit: microseconds
                          expr       min         lq     median         uq       max
1 do.call("mapply", c(c, lol))   155.048   159.5175   192.0635   195.5555   245.841
2    mergeList2(lol$x, lol$xn) 19938.288 20095.9905 20225.4750 20719.6730 27143.674
3    mergelists(lol$x, lol$xn)    63.416    68.1650    78.0825    84.3680    95.265

ここに画像の説明を入力

于 2012-04-19T14:15:46.223 に答える
3

私のベンチマークでは、このアプローチはあなたのアプローチよりも時間がかかりますが、すでに解決しているので、とにかく投稿すると思いました. これで倍の努力が必要です。.combine名前が完全に不明で、関数にゼロを埋め込む必要がある場合は、次のことを試すことができます。(おそらく、最初に反復のサブセットで試して、機能するかどうかを確認してください):

library(reshape2)

mergeList2 <- function(x, xn) {
  xDF <- data.frame(ID = seq_along(x[[1]]), x)
  xnDF <- data.frame(ID = seq_along(xn[[1]]) + nrow(xDF), xn)
  meltedX <- melt(xDF, id = "ID")
  meltedXN <- melt(xnDF, id = "ID")
  res <- as.list(dcast(rbind(meltedX, meltedXN), ID ~ variable, 
    fill = 0))[-1]
  return(res)
}

あなたの例:

mergeList2(list(foo = c(3, 2), bar = c(3, 2)),
  list(foo = 1, baz= 1))

# $foo
# [1] 3 2 1

# $bar
# [1] 3 2 0

# $baz
# [1] 0 0 1

foreach例を使ってテストしてください

set.seed(1)

foreach(dd = 1:10, .combine = mergeList2) %do% {
  theNames <- sample(c("foo", "bar", "baz"), 2)
  ans <- as.list(rpois(2, 4))
  names(ans) <- theNames
  ans
}

# $foo
#  [1] 4 7 2 4 0 2 0 4 5 3

# $baz
#  [1] 7 0 0 5 3 5 3 4 0 5

# $bar
#  [1] 0 5 2 0 5 0 0 0 6 0
于 2012-04-19T15:44:57.703 に答える