1

次の 2 つの配列があるとします。

R <- 101
v <- array(0, dim <- c(R,2))
v[,1] <-runif(101)
t <- array(runif(5), dim <- c(5,2))

私がやりたいことは、次の関数の結果を v の 2 列目の各セルに割り当てることです。

which.min(abs(v[r,1] - t[,1]))

したがって、v の 2 列目のセルごとに、1、2、3、4、または 5 になります。v のすべての行 r に対して for ループを使用してこれを実行できることはわかっていますが、誰かがベクトル化する方法を知っていますか? (かなり遅い)forループに頼る必要がないように、この操作は?

4

3 に答える 3

2

Vectorize呼び出しのように、名前にもかかわらず、実際にはベクトル化されていませんlapply。しかし、これにより結果が得られます。

> Vectorize(function(r) which.min(abs(v[r,1] - t[,1])))(seq(nrow(v)))
##   [1] 4 3 3 2 5 5 2 5 2 5 3 3 2 5 1 4 5 5 4 3 3 5 5 2 4 2 2 4 4 3 2 4 5 2
##  [35] 2 3 2 4 4 1 5 5 2 3 2 4 5 5 3 5 2 4 4 2 4 5 5 5 5 5 4 3 3 5 5 3 2 3
##  [69] 5 3 5 3 3 5 4 5 5 3 1 2 5 5 2 3 3 4 3 3 4 5 4 2 2 3 4 2 5 5 5 5 2

この値はv[,2] に割り当てることができます。

于 2013-01-26T03:29:49.670 に答える
2

展開vしてt次のことができます。

V <- matrix(rep.int(v[,1],dim(t)[[1]]),ncol=dim(t)[[1]])
TT <- matrix(rep.int(t[,1],dim(v)[[1]]),ncol=dim(t)[[1]],byrow=T)

次に、各列の最大値を減算して取得します。

max.col(-abs(V-TT))
于 2013-01-26T02:03:44.310 に答える
1

私は、ベクトル化されたものすべてを使用およびstepfun組み合わせて、ベクトル化されたソリューションを提供できると思います。少しねじれた/複雑なロジックですが、すべての努力に値するものです。pminpmax

stepfun+ pmin+を使用する利点pmax:

  • 非常に高速です(以下のベンチマークを参照)
  • 行列のサイズに制限されません (Jonathan のコードを実行中に巨大なベクトルのエラーを参照してください)

まず、このアイデアはJonathan Chang's投稿から着想を得ています。ここでの小さな違いは、違いではなくインデックスが必要なことです。また、すべての値が正であると仮定します(入力から)。これを負の入力を持つベクトルに拡張することもできますが、必要に応じてその作業を任せます。コードとベンチマークに進む前に、背後にある考え方について説明させてください。runifstepfun

2 つのベクトルx( に相当v[,1]) とy( に相当) があるとしt[,1]ます。次に、この方法でを並べ替えyて作成しstepfunます。sorted y

y_sort <- sort(y)
step <- stepfun(y_sort, 0:length(y))

これはどのように私たちを助けますか?クエリstep(a)を実行すると、 の最大値のインデックスが得られy_sortます < a。これが浸透するまでに時間がかかる場合があります。つまり、値はとのa間の位置にあります。ここで、最初に把握しなければならないことは、これら 2 つの値のどちらが に最も近いかということです。これは、これらのインデックスに対応する のインデックスとおよび の値を抽出し、かどうかを尋ねることによって実現されます。false の場合はインデックスであり、逆の場合も同様です。次に、 fromから元のインデックスを取得します。これは、オプションinを使用して、対応する並べ替えられたインデックスを取得することで実現できます。step(a)step(a) + 1sorted y (y_sort)astep(a)step(a)+1y_sortabs(a-y_sort[step(a)]) > abs(a - y_sort[step(a)+1])step(a)yy_sortindex.return = TRUEsort

この方法に従うのは非常に複雑かもしれないことに同意します。ただし、コードを確認して段階的に実行し、上記のテキストを使用してそれに従ってください (必要な場合)。最良の部分はa、ベクトルにすることができるため、非常に高速です! それではコードに進みます。

# vectorised solution using stepfun
vectorise_fun1 <- function(x, y) {
    y_sort <- sort(abs(y), index.return = TRUE)
    y_sval <- y_sort$x
    y_sidx <- y_sort$ix

    # stepfun
    step_fun <- stepfun(y_sval, 0:length(y))
    ix1      <- pmax(1, step_fun(x))
    ix2      <- pmin(length(y), 1 + ix1)
    iy       <- abs(x - y_sval[ix1]) > abs(x - y_sval[ix2])

    # construct output  
    res      <- rep(0, length(x))
    res[iy]  <- y_sidx[ix2[iy]]
    res[!iy] <- y_sidx[ix1[!iy]]
    res
}

# obtaining result
out_arun <- vectorise_fun1(v[,1], t[,1])
# (or) v[,2] <- vectorise_fun1(v[,1], t[,1])

# Are the results identical?
# Matthew's solution
vectorise_fun2 <- function(x, y) {
    res <- Vectorize(function(r) which.min(abs(x[r] - y)))(seq(length(x)))
}
out_matthew <- vectorise_fun2(v[,1], t[,1])

# Jonathan's solution
vectorise_fun3 <- function(x, y) {
    V  <- matrix(rep.int(x, length(y)), ncol = length(y))
    TT <- matrix(rep.int(y, length(x)), ncol = length(y), byrow = T)
    max.col(-abs(V-TT))
}
out_jonathan <- vectorise_fun3(v[,1], t[,1])

# Are the results identical?
> all(out_arun == out_matthew)
[1] TRUE
> all(out_arun == out_jonathan)
[1] TRUE

それで、ポイントは何ですか?すべての結果は同一であり、 の関数stepfunは巨大で追跡が困難です。大きなベクトルを考えてみましょう。

x <- runif(1e4)
y <- runif(1e3)

それでは、ベンチマークを行って利点を見てみましょう。

require(rbenchmark)
> benchmark( out_arun <- vectorise_fun1(x,y), 
             out_matthew <- vectorise_fun2(x,y), 
             out_jonathan <- vectorise_fun3(x,y), 
             replications=1, order = "elapsed")

#                                   test replications elapsed relative user.self
# 1     out_arun <- vectorise_fun1(x, y)            1   0.004     1.00     0.005
# 2  out_matthew <- vectorise_fun2(x, y)            1   0.221    55.25     0.169
# 3 out_jonathan <- vectorise_fun3(x, y)            1   1.381   345.25     0.873

# Are the results identical?
> all(out_arun == out_matthew)
[1] TRUE
> all(out_arun == out_jonathan)
[1] TRUE

したがって、使用step_funすると、最小で 55 回、最大で 345 回高速になります。では、さらに大きなベクトルを見てみましょう。

x <- runif(1e5)
y <- runif(1e4)

require(rbenchmark)
> benchmark( out_arun <- vectorise_fun1(x,y), 
             out_matthew <- vectorise_fun2(x,y), 
             replications=1, order = "elapsed")

#                                  test replications elapsed relative user.self
# 1    out_arun <- vectorise_fun1(x, y)            1   0.052    1.000     0.043
# 2 out_matthew <- vectorise_fun2(x, y)            1  16.668  320.538    11.849

ジョナサンの関数は割り当てエラーを引き起こしました:

Error in rep.int(x, length(y)) : 
     cannot allocate vector of length 1000000000

そしてスピードアップはこちらで320倍。

于 2013-01-26T13:58:52.953 に答える