taku_1213
@taku_1213

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

数値計算の高速化

解決したいこと

数値計算の高速化

例)
現在、2次元配列の数値計算のプログラムを作成しています。
以前作成した2重ループの数値計算のプログラムでは問題なく
前ステップの値(i-194)が-1より小さかったら処理1
前ステップの値(i-194)が-1より大きかったら処理2
となるような計算はされていますが配列が巨大なためものすごく時間がかかってしまいます(下に載せてあります)。

ということもありスライス機能を使って高速化させようと思ったのですが、一度にすべて計算してしまうスライス機能で処理の条件分岐ができるのか知りたいです。
またほかの良い方法がありましたら是非ご教授宜しくお願い致します...

発生している問題・エラー

なし

例)

なし

または、問題・エラーが起きている画像をここにドラッグアンドドロップ

該当するソースコード

#以前作成した2重ループの数値計算
c1=1190000
c2=113000000
c3=1.66
h1=0.003
kf1=0.00034
kl1=0.0004
x=1.2
for i in range(194, prd.shape[0]):
    for j in range(prd.shape[1]):
            if prd[i-194,j]<=-1:
                    prd[i,j]=prd[i-194,j]+2/(x*np.log(c1+c2/(0-prd[i-194,j])**c3))*(h1*(24-prd[i-194,j])+(kf1+(kl1-kf1)*(0+1)/(0-prd[i-194,j]))*(prd[i-194,j-1]-2*prd[i-194,j]+prd[i-194,j+1])/x)
                        
            else:
                    prd[i,j]=prd[i-194,j]+2/(x*np.log(c1))*(h1*(24-prd[i-194,j])+kl1*(prd[i-194,j-1]-2*prd[i-194,j]+prd[i-194,j+1])/x)



#現在
c1=1190000
c2=113000000
c3=1.66
h1=0.003
kf1=0.0034
kl1=0.004
x=1.2

for i in range(194, prd.shape[0]):
    if prd[i-194, 1:]<=-1:    ???????ここが不明
        prd[i, 1:]=prd[i-194, 1:]+2/(x*np.log(c1+c2/(0-prd[i-194, 1:j])**c3))*(h1*(24-prd[i-194, 1:])+(kf1+(kl1-kf1)*(0+1)/(0-prd[i-194, 1:]))*(prd[i-194, 0:-1]-2*prd[i-194, 1:]+prd[i-194, 2:])/x)
    if prd[i-194, 1:]>-1:      ????????ここが不明
        prd[i, 1:]=prd[i-194, 1:]+2/(x*np.log(c1))*(h1*(24-prd[i-194, 1:])+kl1*(prd[i-194, 0:-1]-2*prd[i-194, 1:]+prd[i-194, 2:])/x)

例)


自分で試したこと

ここに問題・エラーに対して試したことを記載してください。

0

3Answer

元々なにを数値解析しようとしているのかはわかりませんが、、、
通常のリストでは無理です。
しかしnumpyのwhereなどを使うことで、一気に条件分岐的なことは可能です。

0Like

Comments

  1. prdのサイズがわからないので、これが一つの例です。
    また質問文はprdの定義がない為、具体的なアドバイスが難しいです。次からはとりあえず動くものを提示してください。

    prd = np.zeros((194, 2))
    
    logC1 = np.log(c1)
    
    for i in range(194, prd.shape[0]):
        j = i - 194
        less = prd[j, 1:] + 2 / ( x * np.log(c1 + c2 / (0 - prd[j, 1:])**c3) ) * (h1 * ( 24 - prd[j, 1:] ) + (
            kf1 + ( kl1 - kf1 ) * ( 0 + 1 ) / ( 0 - prd[j, 1:] ) ) * ( prd[j, 0:-1] - 2 * prd[j, 1:] + prd[j, 2:] ) / x)
    
        more = prd[j, 1:] + 2 / ( x * logC1 ) * ( h1 * ( 24 - prd[j, 1:] ) + kl1 * (
            prd[j, 0:-1] - 2 * prd[j, 1:] + prd[j, 2:] ) / x)
    
        prd[i, 1:] = np.where(prd[j, 1:] <= -1, less, more)
    
for i in range(194, prd.shape[0]):
    for j in range(prd.shape[1]):
       if prd[i-194,j]<=-1:
          pass

で時間測定し、単に遅い(ものすごく時間がかかって)ではなく、何処のコードが何分かかるか?事実確認してはどうでしょうか?

また、prd.shape[0]=193、4以内?と prd.shape[1]
のサイズはどの位でしょうか?

尚、prd_2[i,j] = prd[i-194,j]
のように別のリスト変数に転送するとどうでしょうか?

蛇足ですけど、
(kf1+(kl1-kf1)*(0+1)
は改善できそうです。
単に kl1 なのでは? 

訂正:(kf1+(kl1-kf1)*(0+1)/...
     (kf1+0.00006/...

だけでした。

0Like

Comments

  1. (Pythonはあまり詳しくないけど、スライスは記述を簡潔にするだけで高速化は期待できないのでは…?)

    np.log(c1)は常に同じ値を返すのにループ内で何度も実行されているため
    ループの前の変数設定部分にlogC1=np.log(c1)を追加し、ループ内のnp.log(c1)logC1に置き換えると多少は速くなると思います。


    式を見てみると参照しているのはprd[i-194, ...]だけなので、たとえば「偶数行を処理するスレッド」「奇数行を処理するスレッド」に分けて並列実行すればけっこうな高速化が期待できそうなんですが、Pythonではメモリ保護機構のためにそういうのは不向きみたいですね…

式の計算はpred[i-194, j], pred[i-194, j-1], pred[i-194, j+1]を参照しているようなので、対応する2次元ベクトルを作ることによってベクトル計算をすることができ、ループを回さずにすみます。

条件式に関しては、
pred[i-194, j]の値の条件でのマスクを作成して、そのマスクと計算値を掛け合わせることによって
条件式がtrueのときだけにその計算式が反映されるようにできます。

#%%
import numpy as np
c1 = 1
c2 = 2
c3 = 3
c4 = 4
pred = np.random.normal(size=(198 * 2, 11))
pred_0 = pred[0:198, 1:10]  # predicted data pred[i-194, j]に対応
pred_1 = pred[0:198, 0:9]   # predicted data  j-1に対応
pred_2 = pred[0:198, 2:11]  # predicted data for j+1に対応
pred_mask1 = pred_0 >= -1  # pred>=-1 に対応するマスク(true/false)
pred_mask2 = pred_0 < -1  # pred< -1 に対応するマスク(true/false)

pred_new = (
    pred_mask1 * (pred_0 * c1 + pred_1 ** c2 + np.exp(pred_2))  # pred >=-1での式
    + pred_mask2 * (pred_0 * c3 + pred_1 ** c4 + pred_2)  # pred < -1での式
    )
0Like

Your answer might help someone💌