NumPyの使い方(8) 真偽値
NumPyの真偽値について。
・TrueとFalse
python標準のTrue, Falseでは
False | 数値のゼロ、空文字列、空配列、False |
True | 他すべて |
TrueがFalse以外ということは、
負の値、NaN、infもTrueとなる。
・条件がTrueとなる要素の確認
import numpy as np a1 = np.arange(8).reshape(2, 4) print(a1) # [[0 1 2 3] # [4 5 6 7]] # 2の倍数かどうか(1) print(a1 % 2 == 0) # [[ True False True False] # [ True False True False]] # 2の倍数かどうか(2) print(np.mod(a1, 2) == 0) # [[ True False True False] # [ True False True False]] # 2の倍数の個数 print((a1 % 2 == 0).sum()) #4 a1 = np.arange(20) print(a1 > 10) # [False False False ..., True True True] # 条件がTrueとなる要素の個数 print((a1 > 10).sum()) # 9 # 条件がTrueとなる値の和 print(a1[a1 >10].sum()) # 135 a2 = np.array([1, 2, 3, 4]) a3 = np.array([1, 1, 4, 4]) print(a2 == a3) # [ True False False True]
anyとall
any 1つでもTrueだとTrueを返す。
all すべてがTrueのときのみTrueを返す。
a1 = np.array([[0, 0, 0], [1, 1, 1], [1, 1, 1]]) print(a1) # [[0 0 0] # [1 1 1] # [1 1 1]] print(a1.any()) # True print(a1.all()) # False
any(), all()で軸を指定できる。次元削減になる。
axis=0 列方向に次元削減
axis=1 行方向に次元削減
print(a1.all(axis=0)) # [False False False] print(a1.all(axis=1)) # [False True True] print(a1.any(axis=0)) # [ True True True] print(a1.any(axis=1)) # [False True True]
boolと条件
真偽値boolや条件などについて。
真偽値bool
・True, Falseの2つの値のみ。
・True,=1, False=0で変更できない。(python2では変更できた)
True = 0 # SyntaxError: can't assign to keyword
False | 数値のゼロ、空文字列、空配列、False |
True | 他すべて |
・必要になったら、True=1, False=0の数値として扱われる。
print(True) # True print(True + True + 1) # 3
・条件分岐や繰り返しに使える。
x = 5 if x > 0: print(x > 0) # True if True: print(True) # True if 1: print(x) # 5 if 2: print(x) # 5 if -1: print(x) # 5
# and, orは短絡 (short-circuit)演算子 # 左から右へ評価し、結果が確定した時点で評価を止める。 # 戻り値は最後に評価された引数 # 最後の引数3を評価するまで確定しない。 print(1 and 2 and 3) # 3 # (1 and 0 and) の時点で評価がFalse(=0)と確定するので3は評価されない。 print(1 and 0 and 3) # 0 # (0 and)の時点で評価がFalseと確定 print(0 and 1 and 3) # 0 # 最後の(3/0)は評価されない print(1 and 0 and (3/0)) # 0 print(0 or 1 or 2 or 3) # 1 print(0 or 0 or 10 or 20) # 10 string1, string2, string3 = '', 'Trondheim', 'Hammer Dance' non_null = string1 or string2 or string3 print(non_null) # 'Trondheim'
・3項演算子のような書き方ができる。
print(1==1 and "T" or "F") # T print(1==0 and "T" or "F") # F
NumPyの使い方(7) 統計関数、最大・最小
NumPyの統計関数の使い方
ndarray配列全体、あるいは特定の軸についての統計処理をする。
sumやmeanなどの集計処理は次元削減になる。
axis=0 縦方向にreduce
axis=1 横方向にredece
sum | 和。 長さ0の配列では0を返す。 |
mean | 平均。長さ0の配列ではNaNを返す。 |
var | 分散 |
std | 標準偏差 |
min | 最小値, aminも同じ |
max | 最大値, amaxも同じ |
nanmin | NaNを無視した最小値 |
nanmax | NaNを無視した最大値 |
minimun | 2つの配列を比較して小さい要素、NaNを優先 |
maximun | 2つの配列を比較して大きい要素、NaNを優先 |
fmin | 2つの配列を比較して小さい要素、NaNを無視 |
fmax | 2つの配列を比較して小さい要素、NaNを無視 |
argmin | 最小値のインデックス |
argmax | 最大値のインデックス |
cumsum | 累積和 |
cumprod | 累積積 |
maximumやfmaxでは予めNaNを処理したほうがよさそう。
import numpy as np a1 = np.array([[1, 2], [3, 4]]) a2 = np.array([[0, 5], [2, 6]]) a3 = np.array([[0, 5], [2, np.nan]]) print(a1.max(axis=0)) # [3 4] print(a1.max(axis=1)) # [2 4] print(a1.max()) # 4 print(a1.argmax()) # 3 : 1次元配列にし、3番要素が最大値 print(a3.max()) # nan print(np.nanmax(a3)) # 5.0 print(np.maximum(a1, a2)) # [[1 5] # [3 6]] print(np.maximum(a1, a3)) # [[1 5] # [3 nan]] RuntimeWarning: invalid value encountered in maximum print(np.fmax(a1, a3)) # [[ 1. 5.] # [ 3. 4.]] RuntimeWarning: invalid value encountered in fmax
mean(), sum()
a1 = np.arange(12).reshape(3, 4) print(a1) # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] # mean print(a1.mean()) # 4.0 メソッド print(np.mean(a1)) # 4.0 関数 # axisを指定すると1次元低い配列を取得 print(np.mean(a1, 0)) # [ 4. 5. 6. 7.] print(np.mean(a1, axis=0)) # [ 4. 5. 6. 7.] print(np.mean(a1, 1)) # [ 1.5 5.5 9.5] print(np.mean(a1, axis=1)) # [ 1.5 5.5 9.5] #print(np.mean(a1, 2)) IndexError: tuple index out of range print(a1.sum()) # 66 print(np.sum(a1)) # 66 print(a1.sum(0)) # [12 15 18 21] print(a1.sum(1)) # [ 6 22 38]
累積和cumsum(), 累積積cumprod()
a2 = np.ones((3, 4), dtype=int) a2*= 2 print(a2) # [[2 2 2 2] # [2 2 2 2] # [2 2 2 2]] print(np.cumsum(a2, 0)) # [[2 2 2 2] # [4 4 4 4] # [6 6 6 6]] print(np.cumsum(a2, 1)) # [[2 4 6 8] # [2 4 6 8] # [2 4 6 8]] print(np.cumprod(a2, 0)) # [[2 2 2 2] # [4 4 4 4] # [8 8 8 8]] print(np.cumprod(a2, 1)) # [[ 2 4 8 16] # [ 2 4 8 16] # [ 2 4 8 16]] print(np.cumsum(a2)) # [ 2 4 6 ..., 20 22 24]
NumPyの使い方(6) 条件制御
NumPyの条件制御について。
if~elseで条件分岐をするとき
a = 5 if a >= 0: b = 1 else: b = -1
と書けますが、これを3項演算子を使い以下のようにも書けます。
b = 1 if a >= 0 else -1
似たような動作を組み込みのリスト型で行うとき、
例えば、Trueならlist1から、そうでなければlist2から要素を選ぶとき、
list1 = [1, 2, 3, 4, 5] list2 = [11, 12, 13, 14, 15] condi = [True, False, True, False, True] list3 = [x if c else y for (c, x, y) in zip(condi, list1, list2)] print(list3) # [1, 12, 3, 14, 5]
NumPyではnp.where()を使って
np.where(条件, x, y)のように書きます。
x,yは配列または数値。数値ならブロードキャストされる。
a3 = np.where(condi, list1, list2) print(a3) # [ 1 12 3 14 5]
他の例も
a1 = np.arange(9).reshape(3, 3) print(a1) # [[0 1 2] # [3 4 5] # [6 7 8]] # 3未満の要素を0で置き換える(1) print(np.where(a1 < 3, 0, a1)) # [[0 0 0] # [3 4 5] # [6 7 8]] # 3未満の要素を0で置き換える(2) print(np.where(a1 >= 3, a1, 0)) # [[0 0 0] # [3 4 5] # [6 7 8]] # 正なら1、正でないなら-1にする print(np.where(a1 > 0, 1, -1)) # [[-1 1 1] # [ 1 1 1] # [ 1 1 1]]
np.where()の引数を条件の配列だけにすると、
Trueとなる要素のインデックスを取得。
a1 = np.arange(9).reshape(3, 3) print(a1) # [[0 1 2] # [3 4 5] # [6 7 8]] # Trueとなる要素のインデックスを取得 print(np.where(a1 > 5)) # (array([2, 2, 2], dtype=int32), array([0, 1, 2], dtype=int32)) # そのインデックスを利用して、要素を取り出せる。 print(a1[np.where(a1 > 5)]) # [6 7 8] # Trueとなる要素のインデックスを取得 print(np.where(a1 > 2)) # (array([1, 1, 1, 2, 2, 2], dtype=int32), array([0, 1, 2, 0, 1, 2], dtype=int32)) # そのインデックスを利用して、要素を取り出せる。 print(a1[np.where(a1 > 2)]) # [3 4 5 6 7 8] # 値の検索 target = [3, 4, 7] ix = np.in1d(a1.ravel(), target).reshape(a1.shape) print(ix) # [[False False False] # [ True True False] # [False True False]] # そのインデックスを表示 print(np.where(ix)) # (array([1, 1, 2], dtype=int32), array([0, 1, 1], dtype=int32))
2つの条件を同時に判断
cond1がTrueでcond2もTrue | 3 |
cond1がTrueでcond2はFalse | 2 |
cond1がFalseでcond2はTrue | 1 |
cond1がFalseでcond2もFalse | 0 |
としたい場合は、python標準だとif, elifなどを組み合わせて書けるが、
np.whereを3回ネストしても書ける
cond1 = np.array([True, True, False, False]) cond2 = np.array([True, False, True, False]) result = np.where(cond1 & cond2, 3, np.where(cond1, 2, np.where(cond2, 1, 0))) print(result) # [3 2 1 0]
True=1, False=0であることを使い次のようにも書ける。
result = cond1 * 2 + cond2 print(result) # [3 2 1 0]
NumPyの使い方(5) ベクトル演算とユニバーサル関数
ベクトル演算とユニバーサル関数について。
ベクトル演算
ndarrayと数値(スカラー)の計算は全要素対象で、forループを使わない。
ndarrayどうしの演算は対応する位置の要素どうしで計算。
[注意]ndarray * ndarrayは内積や外積にはならない。
import numpy as np a1 = np.arange(6).reshape(2, 3) print(a1) # [[0 1 2] # [3 4 5] print(a1 + 1) # [[1 2 3] # [4 5 6] print(a1 - 1) # [[-1 0 1] # [ 2 3 4] print(a1 * 2) # [[ 0 2 4] # [ 6 8 10] print(a1 / 10) # [[ 0. 0.1 0.2] # [ 0.3 0.4 0.5] print(a1 ** 2) # [[ 0 1 4] # [ 9 16 25] print(a1 +a1) # [[ 0 2 4] # [ 6 8 10]] print(a1 * a1) # [[ 0 1 4] # [ 9 16 25]]
ユニバーサル関数(ufunc, universal function)
ベクトル演算と同様に、要素ごとに計算される。
引数となる配列が1つのとき「単項ufunc」、2つのとき「2項ufunc」
例:
a1 = np.arange(6) a2 = np.arange(0, 60, 10) # 単項ユニバーサル関数の例 print(np.square(a1)) # [ 0 1 4 9 16 25] # 2項ユニバーサル関数の例 print(np.add(a1, a2)) # [ 0 11 22 33 44 55]
単項ufunc
abs | 整数、小数、複素数の絶対値 |
fabs | 整数、小数の絶対値。高速 |
sqrt | 平方根。 array**0.5と同等 |
square | 2乗。 array**2と同等 |
exp | eを底としたべき乗 |
log | 自然対数。底がe |
log10 | 常用対数。底が10 |
log2 | 底が2の対数 |
log1p | 1を加えてからの自然対数 |
sign | 要素の符号を返す。正:+1, 負:-1, ゼロ:0 |
ceil | 切り上げ |
floor | 切り捨て |
rint | dtypeそのままで、四捨五入 |
modf | 整数部分と小数部分の2つの配列を返す |
isnan | NaNかどうかの真偽値 |
isfinite | True:Nanでもinfでもない。False:NaNかinf |
isinf | infかどうか。 |
sin | 三角関数 |
cos | |
tan | |
sinh | 双曲線関数 |
cosh | |
tanh | |
arcsin | 逆三角関数 |
arcsos | |
arctan | |
arcsinh | 逆双曲線関数 |
arccosh | |
arctanh | |
logical_not | 論理否定。-arrayと同等 |
2項unfnc
add | 和 |
subtract | 差 |
multiply | 積 |
divide | 商 |
floor_divide | 商を左方向へ丸める。// |
power | 累乗 |
maximum | 最大値。NaNがあるときはNaNを選ぶ |
minimum | 最小値。NaNがあるときはNaNを選ぶ |
fmax | 最大値。NaNがあるときはNaNではない方 |
fmin | 最小値。NaNがあるときはNaNではない方 |
mod | 剰余 |
copysign | 1つめの配列の絶対値を2つめの配列の符号に。 |
greater | > |
greater_equal | >= |
less | < |
less_equal | <= |
equal | == |
not_equal | != |
logical_and | & 論理和 |
logical_or | |論理積 |
logical_xor | ^ 排他 |
・np.vectorize()を使って自作の関数をufuncにできる。
def myfunc(x, y): return x + y vfunc = np.vectorize(myfunc) print(vfunc(np.arange(5), 10)) # [10 11 12 13 14]
Project Euler
Project Euler problem #001 Multiples of 3 and 5
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
問題1:1000未満の3または5の倍数の和を求めよ。
forループを使っていくのが自然かな。
# forループとif limit = 1000 result = 0 for i in range(limit): if i%3 == 0 or i%5 ==0: result += i print(result)
ifの部分は3項演算子でも。
# forループと3項演算子 limit = 1000 result = 0 for i in range(limit): result += i if i%5 == 0 or i%3 ==0 else 0 print(result)
リスト内包表記を使うとシンプルに。
# リスト内包表記 limit = 1000 result = sum([x for x in range(limit) if x%3 == 0 or x%5 ==0 ]) print(result)
3つの等差数列に分けても。
# 等差数列のsum() limit = 1000 result = sum(range(0, limit, 3)) + sum(range(0, limit, 5)) - sum(range(0, limit, 15)) print(result)
等差数列の和の公式を使うと、コードは複雑になるけど処理時間は大幅短縮。
# 等差数列の和の公式 limit = 1000 def sum_multi(x): first = x last = (limit - 1) - (limit - 1) % x return int((first + last) * (last / x) / 2) result = sum_multi(3) + sum_multi(5) - sum_multi(15) print(result)
Project Euler problem #002 Even Fibonacci numbers
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
問題2:フィボナッチ数列で400万以下の偶数の項の和を求めよ。
def fib4(): a, b = 0, 1 result = 0 while b < 4*10**6: result += b if b % 2 ==0 else 0 a, b = b, a + b return result print(fib4()) # 4613732
フィボナッチ数列の偶数項は3項ごとに登場。
それと、フィボナッチ数列の生成をlambda式で1行にまとめてみると、
f = lambda x:int(((1 + 5**0.5) / 2)**i / 5**0.5 + 0.5) i, result = 3, 0 while f(i) < 4*10**6: result += f(i) i += 3 print(result)
Project Euler problem #003 Largest prime factor
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
問題3:600851475143の素因数のうち最大のものを求めよ。
# 素数のジェネレータ def gen2(start=2, stop=1000000): pr = max(1, start - 1) while True: while pr < stop: pr += 1 if all(pr%x != 0 for x in range(2, int(pr**0.5) + 1)): break yield pr # 素因数分解 def factorial(n): if n in [0, 1]: return [n] result = [] stop = int(n**0.5) + 1 g = gen2() pr = next(g) while pr < stop: if n % pr == 0: result.append(pr) n //= pr continue pr = next(g) if n > 1: result.append(n) return result print(max(factorial(600851475143))) # 6857
Project Euler problem #004 Largest palindrome product
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers.
問題:3桁の2つの数の積で作った回文のうち最大のものを求めよ。
forループを2重にして回文判定するとよさそう。
result = 0 for i in range(100, 1000): for j in range(i, 1000): if str(i * j) == str(i * j)[::-1]: result = max(result, i * j) print(result) # 906609
端が9と仮定すると、奇数×奇数なので、forループは奇数で。
result = 0 for i in range(901, 1000, 2): for j in range(i, 1000, 2): if str(i * j) == str(i * j)[::-1]: result = max(result, i * j) print(result)
積の1の位が9になるのは1×9、3×3、7×7、9×1なので、さらにループを減らせそう。
result = 0 pair9 = {1:8, 3:0, 7:0, 9:2} for i in range(901, 1000, 2): if i%10 in pair9: # 1の位が1,3, 7, 9なら incre = pair9[i%10] # 相手の1の位が決まる else: continue for j in range(i+incre, 1000, 10): # 1の位は固定なのでstep=10 if str(i * j) == str(i * j)[::-1]: result = max(result, i * j) print(result)
テストデータ(6) メフィスト賞
import pandas as pd url = 'http://python-remrin.hatenadiary.jp/entry/2017/05/10/222443' ## DataFrameのリストを得る。header=0のオプション指定で、最初の行をheader扱い。 fetched = pd.io.html.read_html(url) print(len(fetched)) # listの要素であるDataFrameの個数 df = fetched[0] # 2次元リスト化 data = [] for i in range(len(df)): x = [] for j in range(len(df.iloc[0])): x.append(df.iloc[i, j]) data.append(x) print(data) # hatena表組み化 for i in range(len(df)): s = "|" for j in range(len(df.iloc[0])): s += str(df.iloc[i, j]) + "|" print(s)
回数 | 作品名 | 著者名 |
1 | すべてがFになる | 森博嗣 |
2 | コズミック | 清涼院流水 |
3 | 六枚のとんかつ | 蘇部健一 |
4 | Jの神話 | 乾くるみ |
5 | 記憶の果て | 浦賀和宏 |
6 | 歪んだ創世記 | 積木鏡介 |
7 | 血塗られた神話 | 新堂冬樹 |
8 | ダブ(エ)ストン街道 | 浅暮三文 |
9 | QED 百人一首の呪 | 高田崇史 |
10 | Kの流儀 | 中島望 |
11 | 銀の檻を溶かして | 高里椎奈 |
12 | ドッペルゲンガー宮 | 霧舎巧 |
13 | ハサミ男 | 殊能将之 |
14 | UNKNOWN | 古処誠二 |
15 | 真っ暗な夜明け | 氷川透 |
16 | ウェディング・ドレス | 黒田研二 |
17 | 火蛾 | 古泉迦十 |
18 | 日曜日の沈黙 | 石崎幸二 |
19 | 煙か土か食い物 | 舞城王太郎 |
20 | 月長石の魔犬 | 秋月涼介 |
21 | フリッカー式 鏡公彦にうってつけの殺人 | 佐藤友哉 |
22 | DOOMSDAY 審判の夜 | 津村巧 |
23 | クビキリサイクル 青色サヴァンと戯れ言遣い | 西尾維新 |
24 | 『クロック』城殺人事件 | 北山猛邦 |
25 | それでも警官は微笑う | 日明恩 |
26 | 死都日本 | 石黒耀 |
27 | フレームアウト | 生垣真太郎 |
28 | 蜜の森の凍える女神 | 関田涙 |
29 | 空を見上げる古い歌を口ずさむ | 小路幸也 |
30 | 極限推理コロシアム | 矢野龍王 |
31 | 冷たい校舎の時は止まる | 辻村深月 |
32 | 孤虫症 | 真梨幸子 |
33 | 黙過の代償 | 森山赳志 |
34 | 少女は踊る暗い腹の中踊る | 岡崎隼人 |
35 | 天帝のはしたなき果実 | 古野まほろ |
36 | ウルチモ・トルッコ 犯人はあなただ! | 深水黎一郎 |
37 | パラダイス・クローズド THANATOS | 汀こるもの |
38 | 掘割で笑う女 浪人左門あやかし指南 | 輪渡颯介 |
39 | マネーロード | 二郎遊真 |
40 | 無貌伝 双児の子ら | 望月守宮 |
41 | 虫とりのうた | 赤星香一郎 |
42 | プールの底に眠る | 白河三兎 |
43 | キョウカンカク | 天祢涼 |
44 | 琅邪の鬼 | 丸山天寿 |
45 | 図書館の魔女 | 高田大介 |
46 | 恋都の狐さん | 北夏輝 |
47 | 眼球堂の殺人 The Book | 周木律 |
48 | 愛の徴 天国の方角 | 近本洋一 |
49 | 渦巻く回廊の鎮魂曲 冷媒探偵アーネスト | 風森章羽 |
50 | ○○○○○○○○殺人事件 | 早坂吝 |
51 | 恋と禁忌の述語論理 | 井上真偽 |
52 | 誰かが見ている | 宮西真冬 |