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

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

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

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

Python 3.x

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

解決済

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

gantakun
gantakun

総合スコア11

NumPy

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

Python 3.x

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

1回答

0リアクション

2クリップ

149閲覧

投稿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

#モジュールのインポート import pandas as p import numpy as np import math from scipy.signal import convolve2d #配列準備 land_sea_boundary = np.array([[2, 2, 2, 2, 2, 2], [2, 2, 2, 2, 2, 2], [2, 2, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]) #カウンター格納用の配列準備 retreat_increment = np.zeros([6, 6]) #mainの処理 up = np.array([[0, 1, 0], [0, 0, 0], [0, 0, 0]]) down = np.array([[0, 0, 0], [0, 0, 0], [0, 1, 0]]) left = np.array([[0, 0, 0], [1, 0, 0], [0, 0, 0]]) right = np.array([[0, 0, 0], [0, 0, 1], [0, 0, 0]]) up_right = np.array([[0, 0, 1], [0, 0, 0], [0, 0, 0]]) up_left = np.array([[1, 0, 0], [0, 0, 0], [0, 0, 0]]) down_right = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 1]]) down_left = np.array([[0, 0, 0], [0, 0, 0], [1, 0, 0]]) retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, up, mode='same', boundary='fill', fillvalue=0) == 0), 1, 0) retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, down, mode='same', boundary='fill', fillvalue=0) == 0), 1, 0) retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, left, mode='same', boundary='fill', fillvalue=0) == 0), 1, 0) retreat_increment = retreat_increment + np.where((land_sea_boundary == 1) & (convolve2d(land_sea_boundary, right, mode='same', boundary='fill', fillvalue=0) == 0), 1, 0) retreat_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) retreat_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) retreat_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) retreat_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) #配列の四辺は内側の値をコピー retreat_increment = np.pad(retreat_increment[1:-1,1:-1], 1, 'edge') print(retreat_increment) #[[0. 0. 0. 0. 0. 0. ] #[0. 0. 0. 0. 0. 0. ] #[0. 0. 0.70710678 1.70710678 2.41421356 2.41421356] #[2.41421356 2.41421356 3.41421356 0. 0. 0. ] #[0. 0. 0. 0. 0. 0. ] #[0. 0. 0. 0. 0. 0. ]]

試したこと

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

以下のような質問にはリアクションをつけましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

NumPy

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

Python 3.x

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