4

すべての要素が列に残り、各列が昇順になるように行列を並べ替える必要があります。Rの行列またはデータフレームのベクトル化された列単位の並べ替えはありますか?(私の行列はすべて正であり、で囲まれているため、列の各セルにB追加して、通常の1次元ソートを実行できます。j*Bj

> set.seed(100523); m <- matrix(round(runif(30),2), nrow=6); m
     [,1] [,2] [,3] [,4] [,5]
[1,] 0.47 0.32 0.29 0.54 0.38
[2,] 0.38 0.91 0.76 0.43 0.92
[3,] 0.71 0.32 0.48 0.16 0.85
[4,] 0.88 0.83 0.61 0.95 0.72
[5,] 0.16 0.57 0.70 0.82 0.05
[6,] 0.77 0.03 0.75 0.26 0.05
> offset <- rep(seq_len(5), rep(6, 5)); offset
 [1] 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5
> m <- matrix(sort(m + offset), nrow=nrow(m)) - offset; m
     [,1] [,2] [,3] [,4] [,5]
[1,] 0.16 0.03 0.29 0.16 0.05
[2,] 0.38 0.32 0.48 0.26 0.05
[3,] 0.47 0.32 0.61 0.43 0.38
[4,] 0.71 0.57 0.70 0.54 0.72
[5,] 0.77 0.83 0.75 0.82 0.85
[6,] 0.88 0.91 0.76 0.95 0.92

しかし、もっと美しいものがすでに含まれていますか?)そうでなければ、私のマトリックスに約1M(10M、100M)のエントリ(ほぼ正方行列)がある場合、最も速い方法は何でしょうか?applyと友達のパフォーマンスペナルティが心配です。

実際、私は「ソート」を必要とせず、「トップn」だけを必要とします。たとえば、nは約30または100です。applypartialパラメータを使用することを考えていますがsort、これは単にベクトル化された並べ替えを行うよりも安いのではないかと思います。ですから、自分でベンチマークを行う前に、経験豊富なユーザーにアドバイスをお願いしたいと思います。

4

5 に答える 5

4

sortを使用する場合は、デフォルトの方法の2倍の速度で100万要素のオーダーになる可能性があること?sortを示します。method = "quick"

まず始めてapply(m, 2, sort, method = "quick")、それが十分な速度を提供するかどうかを確認します。

ただし、これに関するコメントに注意してください?sort。ネクタイは不安定な方法でソートされます。

于 2012-06-07T07:19:07.420 に答える
4

これまでに提案されたソリューションのクイックテストフレームワークを作成しました。

library(rbenchmark)

sort.q <- function(m) {
  sort(m, method='quick')
}
sort.p <- function(m) {
  mm <- sort(m, partial=TOP)[1:TOP]
  sort(mm)
}

sort.all.g <- function(f) {
  function(m) {
    o <- matrix(rep(seq_len(SIZE), rep(SIZE, SIZE)), nrow=SIZE)
    matrix(f(m+o), nrow=SIZE)[1:TOP,]-o[1:TOP,]
  }
}
sort.all <- sort.all.g(sort)
sort.all.q <- sort.all.g(sort.q)

apply.sort.g <- function(f) {
  function(m) {
    apply(m, 2, f)[1:TOP,]
  }
}
apply.sort <- apply.sort.g(sort)
apply.sort.p <- apply.sort.g(sort.p)
apply.sort.q <- apply.sort.g(sort.q)

bb <- NULL

SIZE_LIMITS <- 3:9
TOP_LIMITS <- 2:5

for (SIZE in floor(sqrt(10)^SIZE_LIMITS)) {
  for (TOP in floor(sqrt(10)^TOP_LIMITS)) {
    print(c(SIZE, TOP))
    TOP <- min(TOP, SIZE)
    m <- matrix(runif(SIZE*SIZE), floor(SIZE))
    if (SIZE < 1000) {
      mr <- apply.sort(m)
      stopifnot(apply.sort.q(m) == mr)
      stopifnot(apply.sort.p(m) == mr)
      stopifnot(sort.all(m) == mr)
      stopifnot(sort.all.q(m) == mr)
    }

    b <- benchmark(apply.sort(m),
                   apply.sort.q(m),
                   apply.sort.p(m),
                   sort.all(m),
                   sort.all.q(m),
                   columns= c("test", "elapsed", "relative",
                              "user.self", "sys.self"),
                   replications=1,
                   order=NULL)
    b$SIZE <- SIZE
    b$TOP <- TOP
    b$test <- factor(x=b$test, levels=b$test)

    bb <- rbind(bb, b)
  }
}

ftable(xtabs(user.self ~ SIZE+test+TOP, bb))

これまでの結果は、最大のマトリックスを除くすべてのマトリックスでapply、「トップn」を実行しない限り、パフォーマンスが実際に低下することを示しています。1e6未満の「小さな」行列の場合、すべてをソートせずにソートするだけでapplyは競争力があります。「巨大な」行列の場合、配列全体の並べ替えは。より遅くなりますapply。使用partialは「巨大な」行列に最適であり、「小さな」行列ではわずかな損失にすぎません。

独自の並べ替えルーチンを自由に追加してください:-)

                      TOP      10      31     100     316
SIZE  test                                               
31    apply.sort(m)         0.004   0.012   0.000   0.000
      apply.sort.q(m)       0.008   0.016   0.000   0.000
      apply.sort.p(m)       0.008   0.020   0.000   0.000
      sort.all(m)           0.000   0.008   0.000   0.000
      sort.all.q(m)         0.000   0.004   0.000   0.000
100   apply.sort(m)         0.012   0.016   0.028   0.000
      apply.sort.q(m)       0.016   0.016   0.036   0.000
      apply.sort.p(m)       0.020   0.020   0.040   0.000
      sort.all(m)           0.000   0.004   0.008   0.000
      sort.all.q(m)         0.004   0.004   0.004   0.000
316   apply.sort(m)         0.060   0.060   0.056   0.060
      apply.sort.q(m)       0.064   0.060   0.060   0.072
      apply.sort.p(m)       0.064   0.068   0.108   0.076
      sort.all(m)           0.016   0.016   0.020   0.024
      sort.all.q(m)         0.020   0.016   0.024   0.024
1000  apply.sort(m)         0.356   0.276   0.276   0.292
      apply.sort.q(m)       0.348   0.316   0.288   0.296
      apply.sort.p(m)       0.256   0.264   0.276   0.320
      sort.all(m)           0.268   0.244   0.213   0.244
      sort.all.q(m)         0.260   0.232   0.200   0.208
3162  apply.sort(m)         1.997   1.948   2.012   2.108
      apply.sort.q(m)       1.916   1.880   1.892   1.901
      apply.sort.p(m)       1.300   1.316   1.376   1.544
      sort.all(m)           2.424   2.452   2.432   2.480
      sort.all.q(m)         2.188   2.184   2.265   2.244
10000 apply.sort(m)        18.193  18.466  18.781  18.965
      apply.sort.q(m)      15.837  15.861  15.977  16.313
      apply.sort.p(m)       9.005   9.108   9.304   9.925
      sort.all(m)          26.030  25.710  25.722  26.686
      sort.all.q(m)        23.341  23.645  24.010  24.073
31622 apply.sort(m)       201.265 197.568 196.181 196.104
      apply.sort.q(m)     163.190 160.810 158.757 160.050
      apply.sort.p(m)      82.337  81.305  80.641  82.490
      sort.all(m)         296.239 288.810 289.303 288.954
      sort.all.q(m)       260.872 249.984 254.867 252.087
于 2012-06-07T08:00:39.897 に答える
3

しますか

apply(m, 2, sort)

仕事をしますか?:)

または、トップ10の場合、たとえば、次を使用します。

apply(m, 2 ,function(x) {sort(x,dec=TRUE)[1:10]})

パフォーマンスは強力です。1e7行と5列(合計5e7の数値)の場合、私のコンピューターは約9秒または10秒かかりました。

于 2012-06-07T07:12:51.713 に答える
3

Rは行列計算で非常に高速です。1e4列に1e7要素があるマトリックスは、私のマシンでは3秒以内に並べ替えられます

set.seed(1)
m <- matrix(runif(1e7), ncol=1e4)

system.time(sm <- apply(m, 2, sort))
   user  system elapsed 
   2.62    0.14    2.79 

最初の5列:

sm[1:15, 1:5]
              [,1]         [,2]         [,3]         [,4]         [,5]
 [1,] 2.607703e-05 0.0002085913 9.364448e-05 0.0001937598 1.157424e-05
 [2,] 9.228056e-05 0.0003156713 4.948019e-04 0.0002542199 2.126186e-04
 [3,] 1.607228e-04 0.0003988042 5.015987e-04 0.0004544661 5.855639e-04
 [4,] 5.756689e-04 0.0004399747 5.762535e-04 0.0004621083 5.877446e-04
 [5,] 6.932740e-04 0.0004676797 5.784736e-04 0.0004749235 6.470268e-04
 [6,] 7.856274e-04 0.0005927107 8.244428e-04 0.0005443178 6.498618e-04
 [7,] 8.489799e-04 0.0006210336 9.249109e-04 0.0005917936 6.548134e-04
 [8,] 1.001975e-03 0.0006522120 9.424880e-04 0.0007702231 6.569310e-04
 [9,] 1.042956e-03 0.0007237203 1.101990e-03 0.0009826915 6.810103e-04
[10,] 1.246256e-03 0.0007968422 1.117999e-03 0.0009873926 6.888523e-04
[11,] 1.337960e-03 0.0009294956 1.229132e-03 0.0009997757 8.671272e-04
[12,] 1.372295e-03 0.0012221676 1.329478e-03 0.0010375632 8.806398e-04
[13,] 1.583430e-03 0.0012781983 1.433513e-03 0.0010662393 8.886999e-04
[14,] 1.603961e-03 0.0013518191 1.458616e-03 0.0012068383 8.903167e-04
[15,] 1.673268e-03 0.0013697683 1.590524e-03 0.0013617468 1.024081e-03
于 2012-06-07T07:18:39.630 に答える
1

彼らは、天才と狂気の間に微妙な境界線があると言います...これを見て、あなたがその考えについてどう思うかを見てください。質問のように、目標は、vec長い可能性のあるベクトルの上位30個の要素(1e7、1e8、またはそれ以上の要素)を見つけることです。

topn = 30
sdmult = max(1,qnorm(1-(topn/length(vec))))
sdmin = 1e-5
acceptmult = 10
calcsd = max(sd(vec),sdmin)
calcmn = mean(vec)
thresh = calcmn + sdmult*calcsd
subs = which(vec > thresh)
while (length(subs) > topn * acceptmult) {
    thresh = thresh + calcsd
    subs = which(vec > thresh)
}
while (length(subs) < topn) {
    thresh = thresh - calcsd
    subs = which(vec > thresh)
}
topvals = sort(vec[subs],dec=TRUE)[1:topn]

基本的な考え方は、の分布についてあまり知らなくても、の最大値は平均よりもいくつかの標準偏差vecであると確かに予想するということです。正規分布のvec場合、 2行目の式は、最大値を見つけるために調べる必要がある平均よりもsdがいくつ多いかを大まかに示します(たとえば、vecに1e8値が含まれている場合、上位30の値は次の場所にある可能性があります。平均より5sd上で始まる領域。)正規ではない場合でも、この仮定が真実から大きく離れている可能性は低いです。vecqnormtopnvec

さて、の平均とsdを計算し、vecこれらを使用して、上を見るしきい値を提案します。これは、平均より上にある特定の数のsdです。このアッパーテールで、値よりわずかに多いサブセットを見つけたいと思っていtopnます。そうすれば、それを並べ替えて、最も高い値を簡単に特定できます。これは、全体topnとして最も高いtopn値になります。vec

ここでの正確なルールはおそらく少し調整できますが、何らかの理由で元のしきい値が「アウト」になるのを防ぐ必要があるという考えです。したがって、特定のしきい値を超えている要素の数をすばやく確認できるという事実を利用します。したがって、最初に、しきい値を超える要素calcsdが少なくなるまで、しきい値を少しずつ上げます。10 * topn次に、必要に応じて。少なくともしきい値を超える要素が確実に得られるまでthresh、(再びのステップで)削減します。この双方向検索は、常にサイズがかなり近い(できれば10または100倍以内の)「しきい値セット」につながるはずです。としてcalcsdtopntopntopnが比較的小さい場合(通常の値は30)、このしきい値セットの並べ替えは非常に高速です。もちろんtopn、元のベクトルの最高の要素がすぐに得られvecます。

私の主張では、適切なしきい値セットの生成に関連する計算はすべてRで高速であるため、非常に大きなベクトルの上位30個程度の要素のみが必要な場合、この間接的なアプローチは、ベクトル全体の並べ替えを伴うアプローチよりも優れています。

どう思いますか?!面白いアイデアだと思われる場合は、いいね/投票してください:)適切なタイミングで行うことを検討しますが、ランダムに生成されたデータに対する最初のテストは非常に有望でした。「実際の」データでテストするのは素晴らしいことです。けれど...!

乾杯 :)

于 2012-06-07T10:18:44.767 に答える