アプリケーションの実行中に複数回呼び出されるこのコードはあります。 値を表す数値の配列をとります(value_array)。 これらは、zone_arrayで定義されたゾーンで合計される必要があります。 zone_idsは、zone_array内のすべてのゾーンのリストを表します。値がループインデックスに等しい別の配列でインデックスされた配列から値を合計するnumpyループを最適化する方法
基本的には次のようなものです:私は母集団ラスタマップを取得しました。ゾーンマップの各ゾーンにいくつの人が住んでいるか知りたいと思います。
コード:
values = np.zeros(len(zone_ids))
for i in zone_ids:
values[i] = round(np.nansum(value_array[zone_array == i]), 2)
return values
犯人は、forループのようですが、私はそれを排除し、同じ結果を持ってする方法を発見していません。
私はbincountで試しましたが、私は成功しませんでした。 numba jitを使用しても効果はありません。
このコードはCythonのサポートがないQgisプラグインで使用されるので、私はcythonから遠ざかりたいと思います。
テストコード:ループあたり17.5ミリ秒±
import numpy as np
def fill_values(zone_array, value_array, zone_ids):
values = np.zeros(len(zone_ids))
for i in zone_ids:
values[i] = round(np.nansum(value_array[zone_array == i]), 2)
return values
def run():
# 300 different zones
zone_ids = range(300)
# zone map with 300 zones
zone_array = (np.random.rand(2000, 2000) * 300).astype(int)
# value map from which we want the sum of values per zone (real map can have NaN values)
value_array = (np.random.rand(2000, 2000) * 10.)
value_array[5, 5] = np.NAN
fill_values(zone_array, value_array, zone_ids)
if __name__ == '__main__':
run()
1.92 sが(STD DEV平均±7つのラン、1つのループ毎の)bincountの実装で
Divakarによって示唆されるように:
203ミリ秒(STD平均±。DEV。7つの実行、1つのループごとの)ループあたり15.2ミリ秒±
犯人は、forループではない -
従って、実装があろう。代わりに、問題は比較 'zone_array == i'内です。すべての2000x2000 = 4e6値は、各zone_id「i」に対して「i」と等しいかどうかチェックされなければならない。 – Chickenmarkus
もし私がゾーンIDの量を減らすなら、私は速度が上がるので、forループはパフォーマンスの問題に関わっています。そして、私は 'zone_array == i'をやっていないために知っている選択肢がないので、ループに焦点を当てます。最高ののは、私が何とか 'zone_array == zone_ids'を使用してループをスキップできることです。 –
'zone_array [、、、None] == zone_ids'で比較をブロードキャストすることはできますが、それでもforループにインデックスが残っており、パフォーマンスの改善はほとんどありません。 – user2699