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

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

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

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

843閲覧

NumPy配列の要素を、別の配列を参照して移動させたい

lawa

総合スコア3

NumPy

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

2クリップ

投稿2020/09/16 06:05

編集2020/09/16 06:08

前提・実現したいこと

PythonとGISを使用して地形発達シミュレーションを行おうとしています。
そこで、河川での侵食・堆積を表現したいです。

現在の状況

元となるデータは5mDEMを使用しています。形式はGeotiffのラスターファイルです。
まず、SAGA GISのChannel network and drainage basinsというものによって、流れる先を示すラスターデータを作成してあります。
下の表のように数字と方角が対応しています(ピクセルに0とあった場合には北へ流れる)。
8の場合は移動しません。

 |7|0|1|
|6| |2|
|5|4|3|

また、侵食量は式があり、求めることが出来ます。

考えたこと

このようにやればよいのではないかという予測
0. DEM及び流下先ラスターデータをnumpy配列に変換する

  1. DEM配列の各要素ごとに侵食量を計算し、新たな配列(土砂配列)とする
  2. 土砂配列を流下先配列に従って移動させる
  3. 移動後の要素

わからないこと

やりたいことを画像で示すと、以下のようになります。
イメージ説明
2×2の配列があった場合、移動後の土砂の配列が分かれば侵食・堆積後の標高は簡単な計算で求まります。


しかし、赤線で囲った部分の表現の仕方が見当もつきません。

調べた結果numpyの場合、cumsum関数を使えば隣の要素との計算が、スライシング機能によって要素の抽出ができると
分かりました。
また、roll関数によって位置をずらすことができると分かりました。
ただ、今回のように要素によってバラバラな動きをする方法は調べてもわかりませんでした。

教えていただけると幸いです。

補足情報(FW/ツールのバージョンなど)

ひとまず、移動距離は1マスとしたいです。

conda version : 4.8.4 conda-build version : 3.20.0 python version : 3.8.5.final.0

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

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

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

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

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

guest

回答2

0

ベストアンサー

移動後の土砂を求めるのに、
「下に移動する土砂」「上に移動する土砂」等、方向別に個別に求めるようにすると、numpy と相性が良くなりますよ。

python

1t = np.zeros_lize(s) # 堆積する予定の行列・・・今は全て0 2m = np.array(((4,4),(2,8))) #動き行列 3s = np.array(((1,1),(1,1))) #浸食量行列 4 5#以下を8方向分処理する・・下記は下向きの例 6m_down = (m==4) #下に移動する場所は True でそれ以外はFalse の行列 7s_down = s * m_down #浸食されて下に移動する量の行列 8t[1:,:] += s_down[:-1,:] #下に移動した浸食量を堆積に追加 9

これを8方向について行えば赤枠の中の移動後の土砂が t に求まります。

投稿2020/09/17 04:41

hiro-k

総合スコア902

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

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

lawa

2020/09/17 08:46

回答ありがとうございます! m==5のときも試してみたところ、無事上手くいきました。 スライシング機能によって移動を実現しているんですね。 スライシング機能をそのように使うとは思いつきもしませんでした。
guest

0

流下先配列の特定の座標に着目したとき、その座標の値が「4」ならば、一つ下の座標に侵食量の値がプラスされると、いうことかと思います。
逆に言えば、ある特定座標の上の座標の値が「4」ならば、その座標に上の座標の侵食量の値がプラスされるということになります。

したがって配列を畳み込み演算のように3*3のブロックごとに処理していけば良いです。

python

1from skimage.util import view_as_windows 2 3# 移動マップ 4d = np.array([[7, 0, 1], 5 [6, 9, 2], 6 [5, 4, 3]])[::-1, ::-1] 7 8m = np.array([[4, 4], [2, 8]]) # 流下先配列 9s = np.array([[1, 1], [1, 1]]) # 侵食量配列 10 11# 移動後の土砂配列の計算 12m_block = view_as_windows(np.pad(m, 1, constant_values=8), (3, 3)) 13# [[8 8 8 8] 14# [8 4 4 8] [[888] [[888] [[844] [[448] 15# [8 2 8 8] [ [844] [448] [828] [288] ] 16# [8 8 8 8]] -> [828]], [288]], [888]], [888]] 17s_block = view_as_windows(np.pad(s, 1, constant_values=0), (3, 3)) 18c = np.sum(((m_block == d) * s_block), (2, 3)) 19 20c 21# array([[0, 0], 22# [1, 2]])

python

1np.random.seed(0) 2m = np.random.randint(0, 9, (5, 5)) # 流下先配列 3# [[5 0 3 3 7] 4# [3 5 2 4 7] 5# [6 8 8 1 6] 6# [7 7 8 1 5] 7# [8 4 3 0 3]] 8s = np.random.randint(1, 3, (5, 5)) # 侵食量配列 9# [[2 1 2 2 1] 10# [1 2 1 2 2] 11# [2 2 2 1 2] 12# [1 2 2 2 2] 13# [1 2 1 1 2]] 14 15# 移動後の土砂配列の計算 16m_block = view_as_windows(np.pad(m, 1, constant_values=8), (3, 3)) 17s_block = view_as_windows(np.pad(s, 1, constant_values=0), (3, 3)) 18c = np.sum(((m_block == d) * s_block), (2, 3)) 19# [[0 0 0 2 0] 20# [0 0 0 3 3] 21# [4 1 0 4 2] 22# [0 0 0 1 0] 23# [0 0 0 2 0]]

(以下は以前の解答)

全体的な処理フローは専門外のためよくわかってないですが(すみません)、
とりあえず「赤枠内でやりたいこと」というのはこういうことでしょうか……?

python

1from skimage.util import view_as_windows 2 3d = np.array([[7, 0, 1], 4 [6, 9, 2], 5 [5, 4, 3]]) 6m = view_as_windows(d, (2, 2)) 7 8v = np.array([[4, 4], 9 [2, 8]]) 10 11np.sum(m == v[::-1, ::-1], (2, 3)) 12# array([[0, 0], 13# [1, 2]])

投稿2020/09/16 08:11

編集2020/09/18 03:57
kirara0048

総合スコア1399

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

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

lawa

2020/09/16 09:42

素早い回答ありがとうございます! あまりよくわかっていないので、確認しつつ質問させていただきたいのですが、 ・view_as_windowsで区切ったのは、元の2×2の配列の大きさに合わせるためですか ・私が画像の例で出した侵食量の配列はどこに反映されているのですか ・v[::-1, ::-1]は反転のような方法を取っているということですか ・本番では何千×何千の配列になるのですが、そのときも2×2に区切って処理をした方がよいのでしょうか 質問ばかりで申し訳ありませんが、よろしくお願いいたします。
lawa

2020/09/21 02:12

返信が遅くなってしまい、申し訳ありません。 「どこへ移動させるか」ではなく、「どこから移動してくるか」という逆の発想なんですね。 詳しく教えていただき、ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問