2016-04-04 7 views
1

10^5要素のリストを作成する必要があります。多数の要素を持つリストを作成する

gamma1 <- 2.2 
C1 <- zeta(x = gamma1) 
C1inverse <- 1/C1 

listN <- c((10^3), (10^4), (10^5)) 

for(N in listN) { 
    listKseq <- vector(mode = "list", length = 0) 

    for(k in 1:N) { 
    ki <- N * C1inverse * k^(-gamma1) 
    listKseq <- c(listKseq, ki) 
    } 

    print(paste("I created list with N = ", length(listKseq), " nodes.", sep = "")) 
} 

このコードは、Nのために働く= 10^3、N = 10^4ではなくNのために= 10^5: は、これは私のコードです。 は、実際にはprintの結果は次のとおりです。

[1] "I created list with N = 1000 nodes." 
[1] "I created list with N = 10000 nodes." 

本当にエラーは生成されませんが、実行には時間がかかりすぎると、しばらくして、私は(15分は十分ではありません)を停止します。

このようなリストを生成する方法はありますか?

おかげ

+1

例では、関数呼び出しzeta()を使用しました。これはベースRパッケージにはありません。重要である場合(例えばスカラー以外の結果を返すなど)、どこから来るのかを指定する必要があります。単純な番号を返すだけであれば、それを編集する必要があります。 –

+0

ええ、私のgoogleベースの推測はライブラリ(VGAM)です – Frank

答えて

8

あなたは長さゼロのリストを割り当て、その後、代わりに各反復

listKseq <- vector(mode = "list", length = 0) 
... 
    listKseq <- c(listKseq, ki) 

でそれを育てる「コピー・アンド・APPENDの戦略、「事前に割り当てと塗りつぶしを持っています'

listKseq <- vector(mode = "list", length = N) 
... 
    listKseq[[k]] = ki 

『コピー・アンド・APPEND』戦略は、既に計算されたすべてのデータのコピーを作成し、ループを通るたびに、それは、として多項式の複雑さ(スケールを有しています、約N^2)。事前割り振りと塗りつぶしはコピーを生成せず、Nで直線的に拡大します。ここ

は、元の変性実装

f0 <- function(N) { 
    gamma1 <- 2.2 
    C1 <- zeta(x = gamma1) 
    C1inverse <- 1/C1 
    listKseq <- vector(mode = "list", length = 0) 
    for(k in 1:N) { 
     ki <- N * C1inverse * k^(-gamma1) 
     listKseq <- c(listKseq, ki) 
    } 
    listKseq 
} 

f1 <- function(N) { 
    gamma1 <- 2.2 
    C1 <- zeta(x = gamma1) 
    C1inverse <- 1/C1 
    listKseq <- vector(mode = "list", length = N) 
    for(k in 1:N) { 
     ki <- N * C1inverse * k^(-gamma1) 
     listKseq[[k]] <- ki 
    } 
    listKseq 
} 

それらは

> identical(f0(1000), f1(1000)) 
[1] TRUE 

f1()において

> library(microbenchmark) 
> microbenchmark(f0(1000), f0(10000), f1(1000), f1(10000), times=10) 
Unit: milliseconds 
     expr  min   lq  mean  median   uq   max 
    f0(1000) 9.017734 9.128453 9.779840 9.242001 9.275092 14.975256 
f0(10000) 954.733153 965.318717 1002.789735 969.329023 1002.291013 1125.090369 
    f1(1000) 2.332049 2.417364 2.462379 2.461930 2.488568 2.583112 
f1(10000) 22.220757 22.393636 22.725043 22.503726 22.797767 24.376800 
neval cld 
    10 a 
    10 b 
    10 a 
    10 a 

に記載されているように、それらが拡張するのと同じ結果を返すデモンストレーション、負担ですコードを書く人にあらかじめ割り当てて記入してください。 、あなたの計算が...「ベクトル化」の代わりのループ

f2 <- function(N) { 
    gamma1 <- 2.2 
    C1 <- zeta(x = gamma1) 
    C1inverse <- 1/C1 
    as.list(N * C1inverse * seq_len(N)^(-gamma1)) 
} 

のように書くことができ

f1a <- function(N) { 
    gamma1 <- 2.2 
    C1 <- zeta(x = gamma1) 
    C1inverse <- 1/C1 
    lapply(seq_len(N), function(k) N * C1inverse * k^(gamma1)) 
} 

さらに、より表現と自由なコンパクト、かつ堅牢なコードのために、この動作を取得するにはlapply()を使用し、シンプルなベクトルが

f3 <- function(N) { 
    gamma1 <- 2.2 
    C1 <- zeta(x = gamma1) 
    C1inverse <- 1/C1 
    N * C1inverse * seq_len(N)^(-gamma1) 
} 

アイデンティティと時間が

ているんだろうというときには、リストの長-1の要素を戻すことは意味がありません
> identical(unlist(f1(1000)), f3(1000)) 
[1] TRUE 
> microbenchmark(f1(10000), f2(10000), f3(10000), times=10) 
Unit: microseconds 
     expr  min  lq  mean median  uq  max neval 
f1(10000) 22330.886 22482.578 24223.9281 22939.443 24100.424 30414.666 10 
f2(10000) 1196.715 1217.937 1256.7939 1242.236 1256.622 1401.922 10 
f3(10000) 887.824 909.951 981.8528 979.900 996.471 1201.596 10 
cld 
    b 
    a 
    a 

これらの改良がどのように役立つかを知るにはきれいです。アルゴリズムのスケーリングは、大規模なデータ、ベクトル化の使用、そして最終的には適切な表現にとって最も重要です。ある時点では、コードが「十分に良い」ものであるため、考えを止めるだろう。

コピーアンドアペンドは非常に悪い戦略なので、長さが不明確でサイズがres = vector("list", 1e7); ...; length(res) = actual_lengthになるように過剰に割り当ててトリミングしたり、大きなチャンクで割り当ててコピー&何回か。

+0

とても速くて正確な返答をありがとう。そして、私は先験的に最終的な長さを知らないのですか?明らかに、この例(これは簡略化)のケースではありません。 – marielle