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

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

新規登録して質問してみよう
ただいま回答率
85.35%
機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

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

Q&A

解決済

3回答

1659閲覧

二重for文の振る舞いが分からない

esklia

総合スコア81

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

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

0グッド

0クリップ

投稿2020/03/07 13:31

編集2020/03/08 09:33

経緯

pythonではじめる機械学習p97をやっているのですが、svmパラメータを調整する時のコードに出てくる二重のfor文の挙動が分からず困っています。

for とifの組み合わせによるネストについてに出てくるコードのように、
「iの一番目、二番目、三番目の要素についてjの要素全てを順にループしていく」という構造のfor文は理解できるのですが、

今回のようなfor文ではその考えだと、「ax,Cに対してa,gammaをループする」という意味が通らない解釈しかできず、また、最初のfor文の引数にgammaを入れてあげたほうがシンプルになるという考えもできてしまい(=最初のfor文の引数を三つにする)、非常に混乱しています。
簡単な質問かと思われますが、プログラムがどのように動作しているのかをご教授いただけないでしょうか?

-----------------追記---------------------
Cの各要素についてgammaの要素を順にループしていくというところは理解できますが、axは3行3列のaxesデータ(座標軸のデータ)aは9つの座標軸データを持っており、axの各要素に対してaがループされたのでは9*9でグラフが81個プロットされる計算になってしまい(ここが誤解の元だと思います。)どのようにループされるのかわかりかねております。

-----------------追記2---------------------
このような理解で間違いないでしょうか。
イメージ説明

-----------------追記3---------------------
再度ループの階層(?)を意識してループのイメージを書き直しました。もともと混乱した原因は「外側、内側」という言葉が何を表しているのかよくわからなかったからだと思うのですが、これでだいたいあっていると思います。ただ、ループの描写もあまりうまくありませんが…

イメージ説明

fig, axes = plt.subplots(3,3,figsize=(15,10)) for ax, C in zip(axes, [-1, 0, 3]): for a, gamma in zip(ax, range(-1, 2)): mglearn.plots.plot_svm(log_C=C, log_gamma=gamma, ax=a) axes[0,0].legend(['class 0','class 1','sv class 0','sv class 1',], ncol=4, loc=(.9,1.2))

出力]8011e49755dafc975155486debd85356.jpeg)

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

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

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

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

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

guest

回答3

0

ソースコードから見るに、
axesはいま、要素数3のリスト構造になっています。
以下のようなイメージを持つとよいかと思います。

Python

1axes : 2[ 3 [<subplot0>,<subplot1>,<subplot2>], #1つ目 4 [<subplot3>,<subplot4>,<subplot5>], #2つ目 5 [<subplot6>,<subplot7>,<subplot8>], #3つ目 6]

※[]の区切り位置に注目してください。
9つの要素が並べられているわけではなく、あくまで3つ([[ ],[ ],[ ]])です。
その3つのうち、1つに注目するとその内部にまた3つの要素がある状態です。

したがって、外側のループ(1回目)でaxesからaxに取り出される要素は、

Python

1#for ax, C in zip(axes, [-1, 0, 3]): に対して 2ax : [<subplot0>,<subplot1>,<subplot2>]

となります。

次に内側のループを見ると、上記のaxからaに要素を取り出すループになっているので、
1回目のループでは、

Python

1#for a, gamma in zip(ax, range(-1, 2)):に対して 2a : <subplot0>

となり、あとは実際の処理

Python

1mglearn.plots.plot_svm(log_C=C, log_gamma=gamma, ax=a) 2axes[0,0].legend(['class 0','class 1','sv class 0','sv class 1',], ncol=4, loc=(.9,1.2))

が実行されます。

ここまでの流れが追えていれば、あとは大丈夫だと思いますが、
念のため記載しておくと、内側のループ処理は、
axの要素数分繰り返すので、各回で取り出される要素は
それぞれ、

Python

1#for a, gamma in zip(ax, range(-1, 2)):に対して 2a : <subplot0>#1回目 3a : <subplot1>#2回目 4a : <subplot2>#3回目

となり、それぞれ処理が実行されます。

内側のループを抜けると、外側のループ(2回目)に突入して行きます。
このまま、処理を追いかけていくと
9回の処理によって、9つのグラフが描画されそうです。

投稿2020/03/07 15:55

webdev-koara

総合スコア75

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

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

esklia

2020/03/07 16:07 編集

皆さんに教えていただくことで、そのように直感的に理解するに至りましたが、理屈で理解できていないように思えます(「取り出して処理を行う」という私の理解と、「ループをさらにループする」という皆さんの理解に乖離があるように感じます。)。
webdev-koara

2020/03/07 16:10

すみません、今2枚目の手書きの画像を見ました。 イメージは合っていると思いますよ! もし、より具体的に2重ループ理解したいのであれば、一旦今回のソースコードから離れ 掛け算九九の表を出力するような2重ループプログラムを書いてみると よいと思います。 また2重ループの理解度とは別に、今回扱っているaxesというリストが、 「リストの中にリストを含む構造」になっていることも理解の妨げ になっているように思いました。 ただ、1つずつ理解していけば、必ず理解できると思います。
esklia

2020/03/08 04:56 編集

イメージがあっていてよかったです。質問文記載のURLのリンク先に書いてあるようなiとjを使用したソースコードは書いたことがあり、それは九九と同じような構造をしているのですが、、未だ正確には理解できていないと感じました。
guest

0

axは3行3列のaxesデータ(座標軸のデータ)

という理解でよいです。

aは9つの座標軸データを持っており、axの各要素に対してaがループされたのでは9*9でグラフが81個プロットされる計算になってしまい(ここが誤解の元だと思います。)

ここがおかしいです。
外側のループでは1行x3列のグラフの集まりをとりだし、内側のループではそこから1行x1列=1つのグラフを取り出していると考えるとよいかと思います。

Python

1import matplotlib.pyplot as plt 2 3fig, axes = plt.subplots(3,3) 4# axesは3行x3列のグラフ(Axes)の集まり 5 6for ax_row, C in zip(axes, [-1, 0, 3]): 7 # ax_rowは1行x3列のグラフの集まり 8 for ax, gamma in zip(ax_row, range(-1, 2)): 9 # axは1行x1列=1つのグラフ 10 ax.set_xlim(-2, 2) 11 ax.set_ylim(-2, 4) 12 ax.set_title('gamma={},C={}'.format(gamma, C)) 13 ax.plot(gamma, C, marker='.') 14 15plt.show()

イメージ説明

投稿2020/03/07 14:41

can110

総合スコア38341

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

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

esklia

2020/03/07 14:53 編集

ご回答ありがとうございます。 >>> 外側のループでは1行x3列のグラフの集まりをとりだし、内側のループではそこから1行x1列=1つのグラフを取り出していると考えるとよいかと思います。 「ループする」という表現が二重になるとよくイメージできず、「取り出す」というのはわかるのですが、 ループするという理解だと質問文の画像に記載してあるように「一つ目の引数の各要素に二つ目のfor文の各要素をすべて参照しループする」という考えになり、 「 ax[1] → a[1], ax[1] → a[2], ax[1] → a[3], ax[1] → a[4], ax[1] → a[5], ax[1] → a[6], ax[1] → a[7], ax[1] → a[8], ax[1] → a[9], ax[2] → a[1], ax[2] → a[2], ax[2] → a[3], ax[2] → a[4], ax[2] → a[5], ax[2] → a[6], ax[2] → a[7], ax[2] → a[8], ax[2] → a[9], ax[3] → a[1], ax[3] → a[2], ax[3] → a[3], ax[3] → a[4], ax[3] → a[5], ax[3] → a[6], ax[3] → a[7], ax[3] → a[8], ax[3] → a[9], 」 のようにループすると考えてしまいます。
can110

2020/03/07 15:00

「一つ目の引数の各要素に二つ目のfor文の各要素をすべて参照しループする」という内容と、その後の例で 「ax[1]→~」が3回ではなく9回繰り返される理由が分かりません。 いずれにせよ、実際にループを追っていってその動きから理解するしかないのではないでしょうか?
esklia

2020/03/07 15:28

for a in ax を考えたとき、「ただax[0 1 2]を0 1 2のイテラブルな値として取り出し、それぞれの値について何らかの処理を行う」という理解で語弊はないでしょうか。
can110

2020/03/07 15:45

その説明の結果の例が示されないと判断が難しいですが 「0 1 2のイテラブルな値として取り出し」というところに語弊というか誤解がありそうに思えます。
esklia

2020/03/07 16:05 編集

0、 1、 2という数値は反復可能である(0,1,2…と順に処理できる)という理解ですが、語弊ありますでしょうか?
can110

2020/03/07 16:09

はい。数値(この場合はintでしょうか?)は反復可能ではありません。
esklia

2020/03/08 05:05 編集

そうでしたか、 夜分遅くまでお付き合いいただき大変感謝申し上げます。「反復可能」とは何を指すのかご教示いただけますでしょうか。
esklia

2020/03/08 05:07

「(反復可能オブジェクト) 要素を一度に 1 つずつ返せるオブジェクトです。 反復可能オブジェクトの例には、(list, str, tuple といった) 全てのシーケンス型や…」 今回の例でいうとax[0 1 2][3 4 5]…の[0 1 2]、[3 4 5]のそれぞれがオブジェクトであり、イテラブルである(反復処理の対象とできる型・オブジェクト)と解釈しました。
guest

0

ベストアンサー

for文はループです。二重forはループをループするだけです。繰り返しの繰り返しといった方が伝わりやすいかもしれません。

たとえばこの二重forは普通にわかりますか? わかれば大丈夫です。質問文のも理解できます。

python

1for i in [1, 2, 3]: 2 for j in [4, 5, 6]: 3 print(i, j, i * j) 4 5""" => 61 4 4 71 5 5 81 6 6 92 4 8 102 5 10 112 6 12 123 4 12 133 5 15 143 6 18 15"""

「iの一番目の要素についてjの要素全てを順に適用していく」

この解釈は個人的には意味不明です。

追記

python

1import numpy as np 2 3axes = np.arange(9).reshape(3, 3) 4for ax, C in zip(axes, [-1, 0, 3]): 5 print("C:", C, "ax:", ax) 6 for a, gamma in zip(ax, range(-1, 2)): 7 print(C, gamma, a) 8 9""" => 10C: -1 ax: [0 1 2] 11-1 -1 0 12-1 0 1 13-1 1 2 14C: 0 ax: [3 4 5] 150 -1 3 160 0 4 170 1 5 18C: 3 ax: [6 7 8] 193 -1 6 203 0 7 213 1 8 22"""

追記2

これをどう動くと認識しているのでしょうか。

python

1A = [[1, 2], 2 [3, 4]] 3 4for line in A: 5 for x in line: 6 print(x) 7""" => 81 92 103 114 12"""

投稿2020/03/07 13:58

編集2020/03/07 15:19
hayataka2049

総合スコア30935

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

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

esklia

2020/03/07 14:20

いつもお世話になっております。上記コードは理解できるのですが、今回は引数が二つあることも相まってまだ理解できておりません。僭越ながら私のイメージを質問文に追記しますので、そちらをご覧いただけると幸いです。
hayataka2049

2020/03/07 14:32 編集

axesが(3, 3)の配列で、numpy配列をiterableとして取り扱うとaxis=0で要素を取り出す感じの挙動になります。あとは追記を見てください。 zipのやることとターゲットがアンパックされることはわかっていますか?
hayataka2049

2020/03/07 14:44

「Cの各要素についてgammaの要素を順にループしていく」などの表現は意味をなしません。[-1, 0, 3]の要素がCに代入されます。gammaに代入されるのもrange(-1, 2)の「要素」(コンテナではないので厳密には要素とは言えません)です。
esklia

2020/03/07 15:11 編集

>>> zipのやることとターゲットがアンパックされることはわかっていますか? アンパックされるとどうなるかということをあいまいに理解していました。 「zipはリストなどではなく、タプルやリストにすることができるイテラブルな値だ」(入門python3 p102) 追記してくださったコードを踏まえると、「参照する」という表現は全く間違っており、 axの各要素は[0 1 2][3 4 5][6 7 8]はアンパックされた時点でただの9つの数値の集まりになり、 ただ単に順にプロットされるということでしょうか(言葉でうまく表現できておりませんが…)
hayataka2049

2020/03/07 15:12

まずその「各要素」という言葉は私は意味をなしていないと認識していますし、それをどういう意味で使われているのかも想像できません。こうなると、要素という言葉を使わないで会話しないとコミュニケーションが成立しないと思います。 そして、アンパックされるのはそこではありません。
hayataka2049

2020/03/07 15:17

zip(axes, [-1, 0, 3])が(axesから取り出したもの, [-1, 0, 3]から取り出したもの)というタプルのイテレータを返し、for文のターゲットリストでax, Cと書いておけばこのタプルをaxとCに振り分けることができます。これを認識しているか、ということが私の聞いたことです。
esklia

2020/03/07 15:20 編集

失礼しました。各要素というのはax[0 1 2]なら0と1と2をそれぞれ各要素と解釈しておりました。 >>> アンパックされるのはそこではありません。
hayataka2049

2020/03/07 15:20

アンパックは後回しでいいので、ちょっと追記2を見てみてください。
esklia

2020/03/07 15:23

追記2は A = [[1, 2], [3, 4]] 一つ目のforで[1 2]と[3 4]に分けられ、 二つ目のforで1 2 3 4に分けられ、それぞれの数字がprintされると解釈しました。
hayataka2049

2020/03/07 15:26

そのコメントだけだと理解されているかどうかこちらとしては判断できないのですが、ループを使わないで書くと line = A[0] # 外側のforの1回目 x = line[0] # 外側のforの1回目の内側のforの1回目 print(x) x = line[1] # 外側のforの1回目の内側のforの2回目 print(x) line = A[1] # 外側のforの2回目 x = line[0] # 外側のforの2回目の内側のforの1回目 print(x) x = line[1] # 外側のforの2回目の内側のforの2回目 print(x) と概ね等価、ということはわかっていますか?
esklia

2020/03/07 15:38 編集

すみません、語弊があったので書き直します。
hayataka2049

2020/03/07 15:42

コメントの編集ではなく新しいコメントとして投稿してください。
esklia

2020/03/07 15:48

申し訳ございません。今後はしないようにいたします。 A,line,xの例とaxes,ax,aの例について 理解はできたようなのですが、言葉にできないため「追記2」として質問文に画像を掲載させていただきます。
hayataka2049

2020/03/07 17:20

なぜ[1]などが出てくるのかがわかりません。xに代入されるのは1などですが。
esklia

2020/03/08 04:58

すみません、誤って[]をつけてしまいました。おっしゃる通り1 2…を参照しております。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問