1.10. if文

 どの言語でも条件を分岐するにはif文が使われる。pythonではforループと同じように、if文の最後に:をつけ、改行してインデントを入れて条件を書く。実行文にインデントを入れないとforループと同様、文法エラーになる。

In [1]:
a = 10 
if a < 0:
    print("Minus")
else: #そうでないなら、
    print("Plus")
 
Plus
 

条件文としては、>=<=なども使える。イコールの場合は、==のように等号を二つ書く。条件が複数あるときは、andorが使える。

In [2]:
a = 2
if a >= 0:
    print("a >= 0 ")
if a == 0:
    print("a is 0")
if a < 0 or a > 0: #aが0より小さいか、0より大きい(つまり0でない)
    print("a is not 0")
 
a >= 0 
a is not 0
 

abでない」、のような否定の条件を表すには、ほかにも書き方がある。

In [3]:
a = 1
if a != 0:
    print("a is not 0")
if not a == 0:
    print("a is not 0")
 
a is not 0
a is not 0
 

 変数aがbool型なら、aと書くだけで条件文にできる。

In [4]:
a = True
if a:
    print("a is True")
 
a is True
 

 条件の分岐(そうでないなら)には、else:を使う。

In [5]:
a = 2
if a >= 0:
    print("a is greater than or equal to 0 ")
else:
    print("a is negative")
 
a is greater than or equal to 0 
 

 さらに条件を分岐したいときには elif(else ifの略)が使える。詳細は省略する。

 

 forループとif文が分かったところで、以下のような例題を考えてみよう。

 

 

(例題) 宇宙線(高エネルギーの粒子)を電流に変換できる検出器を用いて、電流値(単位はnA)を1秒ごとに測定したら下図のようなデータが得られた。

In [6]:
import numpy as np
import matplotlib.pyplot as plt
datas = np.array([0,  2, 0, 5, 1, 30, 1, 2, 1, 0.5, 
         5, 55, 1, 0, 12, 2, 1, 0.5, 3, 4]) # 観測結果のデータ
plt.plot(datas)
plt.xlabel('Time (s)')
plt.ylabel('Current (nA)');
 
 

 検出器を流れた電流が10 nAを超えたときだけ、粒子が検出器に到達したと判断し、それ以外の場合はノイズだと判断することにする。また、10 nAを超えれば電流値の大小のかかわらず1個粒子が検出されたとする。測定中に何個の宇宙線が検出されたか?

 

 

(解答例1) このdatasの配列数だけforループを回し、判定基準より上なら一つカウントするようにすればいい。

In [7]:
threshold = 10 
count = 0 
for data in datas:
    if data > threshold: 
        count += 1
print(count)
 
3
 

というように答えが出る。5行目のcount += 1は、count = count + 1の略である。他にもa -= ba *= bなどのように略すことができる。それぞれa = a - ba = a * bを略したものである。

 

 

条件を満たす要素の直接抽出

 配列がndarrayの場合、条件を満たす要素を抽出するのに、forループやif文を使わない方法がある。 例えば、

In [8]:
a = np.array([1,2,3])
print(a[a>1])
 
[2 3]
 

のように、a[aに関する条件]とすることで、その条件を満たす要素を持つ配列が新たに作られる。
 それでは次のようなコードは何を表しているだろうか?

In [9]:
a > 1
Out[9]:
array([False,  True,  True])
 

 条件文のようだが、結果は要素がTrue/Flaseの配列になっていることが分かる。aが配列ならば、a > 1も配列なのだ。

 

 forループとif文を使って回すやり方はjava, C/C++などで頻繁に使われる方法であるが、pythonの場合は、この条件を配列から直接抽出する方法の方が、コードが非常に簡潔でかつ計算時間も少ないというメリットがあるので、ぜひ使いこなせるようになってほしい。

 

 条件を満たす要素の直接抽出を使って先の例題をやってみる。
(解答例2)

In [10]:
count = (datas[datas > threshold]).size
print(count)
 
3
 

 一次元配列datasの要素のうち、thresholdより大きいものを取り出した新たな配列の大きさがカウント数になっているはずなので、.sizeを使えばforループとif文を使わずに、一行で3と答えが出る。

 

 さらに下記のようなコードもあり得る。

(解答例3) datasの要素がthresholdより比較して大きいならTrue、そうでないならFalseを要素に持つTrue/Falsのみを要素に持つ配列datas>theresholdを作り、その和を取るとすれば、$1$行で書くことができる。Bool型の要素を持つ配列の和を取るとNumPyのint型になるように作られているので、このようなやり方が可能となるわけである。

In [11]:
np.sum(datas > threshold)
Out[11]:
3
 

 一見すると条件式のように見えるdatas > thresoldは、実は条件式ではなく、配列を表しているということが重要で、これが「ああ配列のことね」とすぐに理解できるようになればpython/NumPyに慣れてきたといえるだろう。

 

(解答例4) 解答例3の場合はTrur/Falseのみを要素に持つ配列が作られたが、np.where(条件, x, y)という関数を使うと、ndarrayの要素の中で、条件を満たしていれば要素をxに、そうでなければyにすることができる。np.whereを使うと任意の要素を持つ配列を作ることができるという点が異なっている。

In [12]:
c = np.where(datas>threshold, 1, 0) 
count = np.sum(c)
print(count)
 
3
 

cは、実際には以下のような配列になっているので、その和を取ればカウント数になるわけである。

In [13]:
print(c)
 
[0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0]
 

 

練習問題

(1.10.1.) forループとif文を使って、$1$から$100$までの整数のうち、$7$で割り切れるものをすべて挙げよ。また条件を満たす要素の抽出を使った方法と比較せよ。剰余はa % bnp.mod(a, b)を使うとよい。

 

 

解答例

(1.10.1.) (解答例1) forループとif文を使うなら、剰余の%を使って、

In [14]:
import numpy as np
n = 100
m = np.arange(1, 101)
for i in m:
    if i % 7 == 0:
        print(i)
 
7
14
21
28
35
42
49
56
63
70
77
84
91
98
 

 

(解答例2) np.modは配列を扱えるので、forループとif文を使わずに$3$行目のように$1$行で書くことができる。

In [15]:
n = 100
m = np.arange(1, 101)
print(m[np.mod(m,7)==0])
 
[ 7 14 21 28 35 42 49 56 63 70 77 84 91 98]
 

 まあ7で割り切れる数字を求めたいだけなら、np.arangeを使って、下のように書くのが一番いい方法だと思うが、今回はif文の練習ということで取り上げた。

In [16]:
print(np.arange(7,101,7))
 
[ 7 14 21 28 35 42 49 56 63 70 77 84 91 98]
 


当サイトのテキスト・画像の無断転載・複製を固く禁じます。
Unauthorized copying and replication of the contents of this site, text and images are strictly prohibited.
© 2019 Go Yusa