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

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

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

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

Python 3.x

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

Q&A

解決済

1回答

288閲覧

python np.dstackの使い方について

astromelt0416

総合スコア15

NumPy

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

Python 3.x

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

0グッド

0クリップ

投稿2018/10/17 03:51

編集2018/10/17 04:33

先日、以下のような質問をしました
https://teratail.com/questions/152409

この質問に対して寄せていただいた回答をもとに、8*8の行列で各成分が0~2πとなるものは以下のようにあらわすことができました。

python

1import numpy as np 2S = np.random.uniform(0, 2 * np.pi, (Nx, Ny)) 3print(S)

output

1[[4.41650775 2.71406146 4.41416128 3.14201439 2.69117847 4.27302197 2 2.13271308 3.04400582] 3 [1.12690231 3.42268815 4.46682612 4.73870683 5.92194469 2.70762728 4 5.3183137 3.73280308] 5 [2.39379053 4.57429553 2.89689483 1.63613895 2.62612769 2.82020993 6 1.662676 2.52406824] 7 [2.0699564 4.10302686 3.45921419 5.79703282 3.02967725 5.82700575 8 2.46686931 0.37984799] 9 [3.08676912 5.76371844 3.64893616 0.86066251 2.55529371 2.63367659 10 3.29609631 1.03792125] 11 [4.88785811 6.02503479 3.8441244 5.05772728 1.00185371 3.58283383 12 1.9105011 4.4521828 ] 13 [2.28177066 5.43348847 3.7151592 0.27352182 5.39425746 5.95659263 14 2.02327713 4.24771053] 15 [2.62177829 5.79892895 3.47362596 5.06351588 3.27111045 3.12798965 16 0.02599374 3.94512495]]

これを用いて次は周期的境界条件を課して、先日の質問の中でもあった以下の値を計算したいと考えています。
S(i,j)とすると
E =-cos(S(i,j)-S(i+1,j))-cos(S(i,j)-S(i-1,j))-cos(S(i,j)-S(i,j+1))-cos(S(i,j)-S(i,j-1)))

ただし、ここで周期的境界条件というものを課して列1,8及び行1,8で反対側に折り返すという操作を行うこととします。

以上を組み込んで以下のようなコードを考えました。

python

1import matplotlib.pyplot as plt 2import numpy as np 3 4 5def Ecalc(Nx,Ny): 6 for i in range (-1,Nx): 7 for j in range(0,Ny): 8 l=i 9 m=j 10 if l==-1: 11 l=Nx 12 if l==Nx: 13 l=0 14 if m==-1: 15 m=Ny 16 if m==Ny: 17 m=0 18 19 for i in range(0,Nx): 20 for j in range(-1,Ny): 21 l=i 22 m=j 23 if l==-1: 24 l=Nx 25 if l==Nx: 26 l=0 27 if m==-1: 28 m=Ny 29 if m==Ny: 30 m=0 31 32 S = np.random.uniform(0, 2 * np.pi, (Nx, Ny)) 33 print(S) 34 35 36 E = np.empty_like(S) 37 for i, j in np.dstack(Nx,Ny): 38 E[i - 1, j - 1] = -np.cos(S[i, j] - S[i - 1, j]) \ 39 - np.cos(S[i, j] - S[i + 1, j]) \ 40 - np.cos(S[i, j] - S[i, j + 1]) \ 41 - np.cos(S[i, j] - S[i, j - 1]) 42 print(E) 43 Esum=np.sum(E) 44 print(Esum) 45 46if __name__ == '__main__': 47 Ecalc(8,8)

output

1Traceback (most recent call last): 2 File "C:\Users\user2\Desktop\testtesttesttest2.py", line 46, in <module> 3 Ecalc(8,8) 4 File "C:\Users\user2\Desktop\testtesttesttest2.py", line 37, in Ecalc 5 for i, j in np.dstack(Nx,Ny): 6TypeError: dstack() takes 1 positional argument but 2 were given

このエラーを解消し、周期的境界条件を満たした値Eを出力することが目標です。よろしくお願い致します。

追記

やりたいことについて詳しく書きます。
1.NxNyの行列を生成し、各成分を(i,j)であらわす。
2.行列の各要素は0~2
np.piの乱数を取るものとする。この値をS[i,j]とする。
3.E[i,j]を以下のように定義し、すべてのS[i,j]に対して計算を行う。
E[i,j] =-cos(S(i,j)-S(i+1,j))-cos(S(i,j)-S(i-1,j))-cos(S(i,j)-S(i,j+1))-cos(S(i,j)-S(i,j-1)))
しかし、このままでは行列の端では計算ができなくなる(例えばE[1.1]を計算するとき、S[0,1]やS[1,0]が定義されていないので計算ができない)ので、以下のような周期的境界条件を課します。
~~周期的境界条件~~
例えばNx=8,Ny=8の場合、S[0,1]=S[8,1]、S[1,0]=S[1,8]といった具合です。

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

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

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

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

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

hayataka2049

2018/10/17 03:59 編集

なぜdstackを使おうと思ったのでしょうか? コードを読む限りあまり適切とも思えませんし、どういう動作をさせたいのかという意図がわからないと回答がつきづらいと思います
astromelt0416

2018/10/17 04:19

前回の質問の中で、回答してくださった方の中にdstackを使っていらっしゃる方がいて、それに従ってやってみたらうまくいったので使っていた次第です。実際、dstack自体は3次元配列の結合の際に用いられるものとのことで、正直私も理解せず使ってしまっていました。私がやりたいことは質問文中にあります、Eを計算することです。その過程で行列要素のナンバリングと各要素i:1~Nx,j:1~Nyに対する繰り返し処理が必要となりました。質問文にも追記しておきます。
guest

回答1

0

ベストアンサー

エラーメッセージで「位置引数が1つのはずが、2つ渡された」となっており、実際、リファレンス numpy.dstack() を確認すると、

np.dstack(Nx,Ny)

ではなく、

np.dstack([Nx,Ny])

とするよう書いてあります。

追記

前回の回答で dstack() を使用したのは、「各要素をナンバリングした行列を作りたい」と書いてあったので、np.mgrid で各要素の x 座標と y 座標の一覧を作成し、それを結合するために使いました。

indices = np.dstack(np.mgrid[1:9, 1:9]).reshape(-1, 2) print(indices)
[[1 1] [1 2] [1 3] [1 4] [1 5] [1 6] [1 7] ...

ただ、各要素を iteratate するのが目的だったのであれば、np.ndenumerate() を使ったほうがシンプルです。

python

1a = np.random.randn(5, 5) 2print(a) 3 4for index, value in np.ndenumerate(a): 5 print(index, value)
[[1 1] [1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [2 1] ...

追記

境界条件って端の場合は反対側の値を使うということですよね。
であれば、padding='wrap' で np.pad() しておけばいいです。

どういうことかは以下を見ていただければわかるかと思います。

a = np.random.randint(0, 5, (5, 5)) print(a) # [[3 3 2 2 0] # [0 4 1 2 1] # [1 4 4 1 4] # [4 4 2 4 0] # [4 1 4 3 3]] b = np.pad(a, (1, 1), 'wrap') print(b) # [[3 4 1 4 3 3 4] # [0 3 3 2 2 0 3] # [1 0 4 1 2 1 0] # [4 1 4 4 1 4 1] # [0 4 4 2 4 0 4] # [3 4 1 4 3 3 4] # [0 3 3 2 2 0 3]]

python

1np.set_printoptions(linewidth=120) 2 3Nx, Ny = 5, 5 4S = np.random.uniform(0, 2 * np.pi, (5, 5)) 5print(S) 6 7E = np.empty_like(S) 8S_pad = np.pad(S, (1, 1), 'wrap') 9print(S_pad) 10 11for i, j in np.dstack(np.mgrid[1:Nx+1, 1:Ny+1]).reshape(-1, 2): 12 E[i - 1, j - 1] = -np.cos(S_pad[i, j] - S_pad[i - 1, j]) \ 13 - np.cos(S_pad[i, j] - S_pad[i + 1, j]) \ 14 - np.cos(S_pad[i, j] - S_pad[i, j + 1]) \ 15 - np.cos(S_pad[i, j] - S_pad[i, j - 1]) 16print(E)

追記

話を簡単にするため (3, 3) 行列で考えます。

python

1Nx, Ny = 3, 3 2S = np.random.randint(0, 5, (Nx, Ny)) 3print(S) 4# [[0 2 4] 5# [0 0 3] 6# [2 0 2]]

S_pad は (Nx, Ny) の配列の周囲に1ずつパディングを入れたものです。
パディングの値は padding='wrap' を指定することで、例えば、S[0, 0] であれば、S[2, 2] の値になるようにしています。
これにより、E[0, 0] = -cos(S[0, 0] - S[-1, 0]) を計算する場合、条件分岐が不要になります。

python

1S_pad = np.pad(a, (1, 1), 'wrap') 2print(S_pad) 3# [[2 2 0 2 2] 4# [4 0 2 4 0] 5# [3 0 0 3 0] 6# [2 2 0 2 2] 7# [4 0 2 4 0]]

S_pad の各要素のインデックスは以下のようになっています。

python

1(0, 4) (1, 4) (2, 4) (3, 4) (4, 4) (5, 4) (6, 4) 2(0, 4) (1, 4) (2, 4) (3, 4) (4, 4) (5, 4) (6, 4) 3(0, 4) (1, 4) (2, 4) (3, 4) (4, 4) (5, 4) (6, 4) 4(0, 4) (1, 4) (2, 4) (3, 4) (4, 4) (5, 4) (6, 4) 5(0, 4) (1, 4) (2, 4) (3, 4) (4, 4) (5, 4) (6, 4) 6(0, 4) (1, 4) (2, 4) (3, 4) (4, 4) (5, 4) (6, 4) 7(0, 4) (1, 4) (2, 4) (3, 4) (4, 4) (5, 4) (6, 4)

このうち、元の行列 S の値がある以下のインデックスだけ iterate したいわけです。

python

1(1, 4) (2, 4) (3, 4) (4, 4) (5, 4) 2(1, 4) (2, 4) (3, 4) (4, 4) (5, 4) 3(1, 4) (2, 4) (3, 4) (4, 4) (5, 4) 4(1, 4) (2, 4) (3, 4) (4, 4) (5, 4) 5(1, 4) (2, 4) (3, 4) (4, 4) (5, 4)

なので、目標は以下の配列を作ることです。

[(1, 1), (1, 2), (1, 3), (1, 4), ...]

np.mgrid は返り値として次の2つの値を返します。

python

1X, Y = np.mgrid[1:Nx + 1, 1:Ny + 1] 2print(X) 3# 各要素の行 4# [[1 1 1] 5# [2 2 2] 6# [3 3 3]] 7 8# 各要素の列 9print(Y) 10# [[1 2 3] 11# [1 2 3] 12# [1 2 3]]

よって、これを np.dstack() で結合すると、各要素のインデックスの一覧が作れます。

python

1XY = np.dstack([X, Y]) 2print(XY) 3# [[[1 1] [1 2] [1 3]] 4# [[2 1] [2 2] [2 3]] 5# [[3 1] [3 2] [3 3]]]

これは (3, 3, 2) の numpy 配列なので、(9, 2) として、reshape() します。
(3, 3, 2) を (9, 2) に reshape() する際に、(?, 2) と2が決まっていれば、? の部分は9と確定するので、この場合、-1 と指定しておくことができます。

python

1print(XY.reshape(-1, 2)) # XY.reshape(9, 2) と一緒 2# [[1 1] 3# [1 2] 4# [1 3] 5# [2 1] 6# [2 2] 7# [2 3] 8# [3 1] 9# [3 2] 10# [3 3]]

投稿2018/10/17 03:57

編集2018/10/17 05:58
tiitoi

総合スコア21956

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

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

astromelt0416

2018/10/17 04:13

回答ありがとうございます。ご指摘の通り、np.dstack([Nx,Ny])としたのですが、次は以下のようなValueErrorが出てしまっています。 ValueError: not enough values to unpack (expected 2, got 1) この場合、np.dstackを使っていること自体が間違いなのでしょうか・・・
tiitoi

2018/10/17 04:37

前回の回答では、np.dstack(np.mgrid[1:9, 1:9]).reshape(-1, 2) となっていたはずです。 1つずつ要素を走査していくのが目的であれば np.ndenumerate() を使ったほうがシンプルかと思います。
tiitoi

2018/10/17 05:06 編集

境界条件の判定は padding='wrap' で np.pad() しておけば不要です。サンプルコードを追記しました。
astromelt0416

2018/10/17 05:11

意図を汲んでいただきありがとうございます。追記の方、参考にさせていただきました。想像通りの結果が得られたので、一度先に進んでみたいと思います。ありがとうございました。
tiitoi

2018/10/17 05:16

想定どおり動いたようでよかったです。 ただ、コードでわからない部分があれば、よくわからないけど動くという状態で使うのではなく、理解しておいたほうがよいですよ。 コードで不明な点があれば補足します。
astromelt0416

2018/10/17 05:22

おっしゃる通りです。お言葉に甘えて少し追質問させていただきます。 for i, j in np.dstack(np.mgrid[1:Nx, 1:Ny]).reshape(-1, 2): の部分で.reshape(-1, 2)を除くと、ValueError: too many values to unpack (expected 2)が出るのを確認しました。先ほどもこのエラーで躓いていた記憶なのですが、この.reshape(-1, 2)はいったいどのような意味なのでしょうか。
tiitoi

2018/10/17 06:01

先程のコードに一部誤りがあったので、訂正しました。 × np.mgrid[1:Nx, 1:Ny] ○ np.mgrid[1:Nx+1, 1:Ny+1] np.dstack(np.mgrid[1:Nx, 1:Ny]).reshape(-1, 2) はループしたい添字の一覧を作っています。回答に追記しました。 meshgrid は最初とっつきにくいと思いますので、以下のページなども合わせて参照されるといいかと思います。 https://deepage.net/features/numpy-meshgrid.html
astromelt0416

2018/10/17 06:22

回答ありがとうございました。meshgridの雰囲気はつかめたと思います。参考ページと合わせて、いろいろと試してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問