Remrinのpython攻略日記

python3に入門しました。python3についてあれこれとサンプルコードとか。

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 行方向に次元削減
f:id:rare_Remrin:20170512120642p:plain

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

 
参考:
pythonドキュメント 条件に付いてもう少し

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)

Archived Problems - Project Euler

テストデータ(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 パラダイス・クローズド THANATO 汀こるもの
38 掘割で笑う女 浪人左門あやかし指南 輪渡颯介
39 マネーロード 二郎遊真
40 無貌伝 双児の子ら 望月守宮
41 虫とりのうた 赤星香一郎
42 プールの底に眠る 白河三兎
43 キョウカンカク 天祢涼
44 琅邪の鬼 丸山天寿
45 図書館の魔女 高田大介
46 恋都の狐さん 北夏輝
47 眼球堂の殺人 The Book 周木律
48 愛の徴 天国の方角 近本洋一
49 渦巻く回廊の鎮魂曲 冷媒探偵アーネスト 風森章羽
50 ○○○○○○○○殺人事件 早坂吝
51 恋と禁忌の述語論理 井上真偽
52 誰かが見ている 宮西真冬