2016-09-10 7 views
2

VectorVectorであり、長さはそれぞれWです。これらの最後のベクトルには、0〜150,000の整数が5のステップで含まれますが、空にすることもできます。私はこれらのベクトルのそれぞれについて経験的なcdfを計算しようとしています。 CDFはj >= maximum(v)ために1に等しくなり、時にはこのmaximum(v) 150,000よりもはるかに低くなるので、私はしかし、これジュリアのループが途切れる

cdfdict = Dict{Tuple{Int,Int},Float64}() 
for i in 1:length(W) 
    v = W[i] 
    len = length(v) 
    if len == 0 
     pcdf = 1.0 
    else 
     for j in 0:5:150_000 
      pcdf = length(v[v .<= j])/len 
      cdfdict[i, j] = pcdf 
     end 
    end 
end 

ようなすべてのベクターおよびすべての整数を超える反復これらのCDFを計算することができ、このアプローチは非効率的です。

私の質問は:どのように私はj > maximum(v)ためjループの勃発が、それでもj秒の残りのためpcdf = 1.0を割り当て条件を含めることができますか?

j > maximum(v)のときにはbreakを含めるようにしましたが、これはもちろん、残りの部分がループするのを停止します。jまた、私はループを壊して、後でcdfdictに見つからないキーのために1.0にアクセスするためにget!を使用することができますが、それは私が探しているものではありません。

+3

時期尚早の最適化は諸悪(クヌース??)のルートですあなたはそれを壊すことは関係ありません。 –

+0

これはループの後に 'get!'を使うのとほぼ同じです... – amrods

+1

私は@ TasosPapastylianouの解決策が最高だと思います。しかし、あなたはジュリアにどのくらいの速いループがあるかを過小評価しているかもしれません。 0から150,000を5秒でループし、あらかじめ設定された値1.0を入力すると、時間がかかります。 –

答えて

2

私のコメントで詳しく述べると、この回答はDictの代わりにArrayを満たす実装の詳細です。

ランダムなテストケースを作成するにはまず:のCDFの始まりを埋めるために今

cdfmat = ones(Float64,length(W),length(0:5:150_000)); 

::次は、1.0秒で満たされ、適切なサイズの配列を作成

W = [rand(0:mv,rand(0:10)) for mv in floor(Int,exp(log(150_000)*rand(10)))] 

for i=1:length(W) 
    v = sort(W[i]) 
    k = 1 
    thresh = 0 
    for j=1:length(v) 
     if (j>1 && v[j]==v[j-1]) 
      continue 
     end 
     pcdf = (j-1)/length(v) 
     while thresh<v[j] 
      cdfmat[i,k]=pcdf 
      k += 1 
      thresh += 5 
     end 
    end 
end 

この実装では、遅くなることがあるsortが使用されますが、他のimp基本的にベクトルをさまざまな値と比較します。この値は、ほとんどの場合、さらに遅くなります。

+0

この回答は質問から少し横向きであり、詳細には説明されていませんので、必要に応じてコメントの必要と質問で詳細に編集します。 –

+0

「v」に繰り返し値が含まれるケースはどうですか? – amrods

+0

私はそれが動作すると思う、ありがとう。 – amrods

2

breakは1レベルのみです。 forループ関数をラップして、return(breakを置いた場所の代わりに)を使用するか、または@gotoを使用して、必要な処理を行うことができます。

どこかでブール値をbreakd=trueに変更してからブレークし、大きなループの最後にはif breakd break endとすることができます。

+2

'@goto'は' if breakd'よりはるかに明確で、強く推奨されるべきです。 –

2

forループを使用して、残りの要素をすべて1.0に設定することができます。内側のループは

m = maximum(v) 
for j in 0:5:150_000 
    if j > m 
     for k in j:5:150_000 
      cdfdict[i, k] = 1.0 
     end 
     break 
    end 
    pcdf = count(x -> x <= j, v)/len 
    cdfdict[i, j] = pcdf 
end 

になります。しかし、これは理解しにくいです。ブランチを使用する方が簡単です。実際には、ブランチが非常に予測可能であるため、これは同じくらい速く行う必要があります。

m = maximum(v) 
for j in 0:5:150_000 
    if j > m 
     cdfdict[i, j] = 1.0 
    else 
     pcdf = count(x -> x <= j, v)/len 
     cdfdict[i, j] = pcdf 
    end 
end 
1

もう1つの答えは、サンプルをソートし、CDFビンを分位値で埋めることによってCDFを計算したArrayを使用して実装しました。このように配列全体が塗りつぶされているので、配列上で別のパスを実行しても過度にコストがかかることはありません(すでに単一パスを許容しています)。並べ替えビットとそれに伴う割り当ては、配列内のヒストグラムを計算し、cumsumを使用してCDFを生成することで回避できます。(

cdfmat = zeros(Float64,n,hl); # empty histograms 
for i=1:n      # drop samples into histogram bins 
    for j=1:length(W[i]) 
    cdfmat[i,1+(W[i][j]+w-1)÷5]+=one(Float64) 
    end 
end 
cumsum!(cdfmat,cdfmat,2)  # calculate pre-CDF by cumsum 
for i=1:n      # normalize each CDF by total 
    if cdfmat[i,hl]==zero(Float64) # check if histogram empty? 
    for j=1:hl     # CDF of 1.0 as default (might be changed) 
     cdfmat[i,j] = one(Float64) 
    end 
    else       # the normalization factor calc-ed once 
    f = one(Float64)/cdfmat[i,hl] 
    for j=1:hl 
     cdfmat[i,j] *= f 
    end 
    end 
end 

初期サイズ、長さおよび幅:

W = [rand(0:mv,rand(0:10)) for mv in floor(Int,exp(log(rmax)*rand(n)))]; 

はのCDFを計算する:

n = 10; w = 5; rmax = 150_000; hl = length(0:w:rmax) 

サンプル例を生成おそらくコードは、このよりよいについて説明しますa)one,zeroの使用に注意してください。本当のタイプの変更 - これは良い習慣です。 (b)また、さまざまな@inbounds@simdを追加すると、さらに最適化する必要があります。 (c)このコードを関数に入れることをお勧めします(これはこの答えではありません)。 (d)空のサンプルに対してCDFがゼロであれば(つまり、サンプルが意味的に巨大サンプルを意味しないことを意味する)、第2のforを簡略化することができる。

より多くのオプションのための他の回答を参照してください、とリマインダー:たとえように、デフォルト値として '1'を使用してcdfdictを初期化することができ

関連する問題