質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

1301閲覧

二次元配列の特定のセルに隣接する周囲8方向のセルから条件に合うセルの数を取得する

gantakun

総合スコア16

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

2クリップ

投稿2022/08/12 08:02

前提

二次元配列の特定のセルに隣接する周囲8方向のセルに,ある数値が格納されているとき,
その数を高速で取得したいと考えています.ここで,隣接する特定の数値のカウントはできる一方で,
計算の高速化が実現できていません.実務で,1000×1000程度の配列で10万回以上同じ処理を繰り返すため,
現時点でのコードではどうしても時間がかかってしまいます.

実現したいこと

以下の二次元配列で1の部分に注目します.1に隣接する周囲8方向に0が入っている場合,
0が上下左右方向であればカウンターとして1を,
斜め方向であれば1/√2を追加する処理を高速で実現したいと考えています.
例として赤枠で囲まれた1には,1+1+(1/√2)+(1/√2)のカウントが貯まっていきます.
現在はscipyの畳み込みを使用していますが,より良いコードと高速化手法をご教授いただきたく投稿しました.

イメージ説明

現在のコード

Python

1#モジュールのインポート 2import pandas as p 3import numpy as np 4import math 5from scipy.signal import convolve2d 6 7#配列準備 8land_sea_boundary = np.array([[2, 2, 2, 2, 2, 2], 9 [2, 2, 2, 2, 2, 2], 10 [2, 2, 1, 1, 1, 1], 11 [1, 1, 1, 0, 0, 0], 12 [0, 0, 0, 0, 0, 0], 13 [0, 0, 0, 0, 0, 0]]) 14 15#カウンター格納用の配列準備 16retreat_increment = np.zeros([6, 6]) 17 18#mainの処理 19up = np.array([[0, 1, 0], [0, 0, 0], [0, 0, 0]]) 20down = np.array([[0, 0, 0], [0, 0, 0], [0, 1, 0]]) 21left = np.array([[0, 0, 0], [1, 0, 0], [0, 0, 0]]) 22right = np.array([[0, 0, 0], [0, 0, 1], [0, 0, 0]]) 23 24up_right = np.array([[0, 0, 1], [0, 0, 0], [0, 0, 0]]) 25up_left = np.array([[1, 0, 0], [0, 0, 0], [0, 0, 0]]) 26down_right = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 1]]) 27down_left = np.array([[0, 0, 0], [0, 0, 0], [1, 0, 0]]) 28 29retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, up, mode='same', boundary='fill', fillvalue=0) == 0), 1, 0) 30retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, down, mode='same', boundary='fill', fillvalue=0) == 0), 1, 0) 31retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, left, mode='same', boundary='fill', fillvalue=0) == 0), 1, 0) 32retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, right, mode='same', boundary='fill', fillvalue=0) == 0), 1, 0) 33retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, up_right, mode='same', boundary='fill', fillvalue=0) == 0), 1/math.sqrt(2), 0) 34retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, up_left, mode='same', boundary='fill', fillvalue=0) == 0), 1/math.sqrt(2), 0) 35retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, down_right, mode='same', boundary='fill', fillvalue=0) == 0), 1/math.sqrt(2), 0) 36retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, down_left, mode='same', boundary='fill', fillvalue=0) == 0), 1/math.sqrt(2), 0) 37 38#配列の四辺は内側の値をコピー 39retreat_increment = np.pad(retreat_increment[1:-1,1:-1], 1, 'edge') 40 41 42print(retreat_increment) 43 44#[[0. 0. 0. 0. 0. 0. ] 45 #[0. 0. 0. 0. 0. 0. ] 46 #[0. 0. 0.70710678 1.70710678 2.41421356 2.41421356] 47 #[2.41421356 2.41421356 3.41421356 0. 0. 0. ] 48 #[0. 0. 0. 0. 0. 0. ] 49 #[0. 0. 0. 0. 0. 0. ]] 50

試したこと

以前,for文を使用して周囲8方向を検索するプログラムを書いたのですが,
その手法では計算速度が出なかったため,scipyの畳み込みを使用しました.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

シンプルに

python

1 np.array([ 2 [1/np.sqrt(2), 1, 1/np.sqrt(2)], 3 [1, 0, 1], 4 [1/np.sqrt(2), 1, 1/np.sqrt(2)], 5])

で畳み込みをすれば、1回の畳み込みだけでできるのではないでしょうか。

python

1#モジュールのインポート 2import numpy as np 3from scipy.signal import convolve2d 4 5#配列準備 6land_sea_boundary = np.array([[2, 2, 2, 2, 2, 2], 7 [2, 2, 2, 2, 2, 2], 8 [2, 2, 1, 1, 1, 1], 9 [1, 1, 1, 0, 0, 0], 10 [0, 0, 0, 0, 0, 0], 11 [0, 0, 0, 0, 0, 0]]) 12 13# 0 と等しい部分の畳み込み 14mask = np.array([ 15 [1/np.sqrt(2), 1, 1/np.sqrt(2)], 16 [1, 0, 1], 17 [1/np.sqrt(2), 1, 1/np.sqrt(2)], 18]) 19retreat_increment = convolve2d(land_sea_boundary == 0, mask, mode='same', boundary='fill') 20 21# 1 と等しい部分だけ残す 22retreat_increment = np.where(land_sea_boundary == 1, retreat_increment, 0) 23 24#配列の四辺は内側の値をコピー 25retreat_increment = np.pad(retreat_increment[1:-1,1:-1], 1, 'edge') 26 27print(retreat_increment)

投稿2022/08/12 10:41

bsdfan

総合スコア4567

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gantakun

2022/08/13 06:22

ありがとうございます.実際のプログラムに組み込んだ際に計算時間が半分以下になったので,非常に助かりました.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問