※本記事はData Science from ScratchのChapter2に出てきたTipsの自分用メモです。
参考になりそうなリンクと簡単な使い方だけ書いてます。(Python3です)
yield
yield
についてのイメージは、こちらのブログがわかりやすく、その後こちらのブログを参考にすると理解が深まります。
簡単に言うと、「return
を使うとその行で処理が終わって値をすべて戻してしまうので、膨大なデータを用いた繰り返し作業を行う場合、繰り返しごとにメモリを無駄に消費して大変だよね。そういうときにはyield
っていう便利な物があるんだよ」ということだと思います。
def func():
a = 10
b = 20
c = a + b
yield c # ここで一旦停止
a = 100
b = 200
c = a + b
yield c # ここで一旦停止
a = 1000
b = 2000
c = a + b
yield c # ここで一旦停止
for x in func():
print (x)
#---- 結果 -----
# 30
# 300
# 3000
#---------------
partial
When passing functions around, sometimes we’ll want to partially apply (or curry) functions to create new functions.
「関数回してると時々関数の一部を使って新しい関数を作りたい時あるよね〜」な人に役立つのがpartial
だそうです。
使用時にはfunctools
からimport
する必要があります。
# 例えば base を power乗 する関数を作る
def exp(base, power):
return base ** power
これを使って2のx乗を計算する関数を作る場合こんな風に書きますよね。
def two_to_the(power):
return exp(2, power)
でもpartial
を使うとこんな風に書けます。
from functools import partial
two_to_the = partial(exp, 2) # 最初の引数で使用する関数、2つ目の引数でbaseを指定
print two_to_the(3) # 8
参照する関数の別の引数を指定したい場合は、その引数の名前を含めて指定します。
square_of = partial(exp, power=2) # 今回はpowerを指定
print square_of(3) # 9
このpartial
すごく便利らしいので以下の説明でもpartial
を使って慣れようと思います。
#Pythonの基本的な高階関数(higher-order functions)
map
, filter
, reduce
は高階関数と呼ばれるものだそうです。
高階関数とは、英語の「 higher-order function 」の訳で、「他の関数を引数として受け取る関数」のことです。たとえば、リストの各要素に共通の処理を加えたリストを作成したい場合なんかに、処理をわかりやすく簡潔に記述することができます。
by LIFE WITH PYTHON
map
map(x, y)
はx(i) for i in y
です。
def double(x):
return 2 * x
xs = [1, 2, 3, 4]
twice_xs = [double(x) for x in xs] # [2, 4, 6, 8]
twice_xs = map(double, xs) # same as above
list_doubler = partial(map, double) # *function* that doubles a list
twice_xs = list_doubler(xs) # [2, 4, 6, 8]
複数の引数を持つリストが与えられていれば、複数の引数を持つ関数にも使用することができるそうです。
def multiply(x, y):
return x * y
products = map(multiply, [1, 2], [4, 5]) # [1 * 4, 2 * 5] = [4, 10]
filter
filter(x, y)
はi for i in y if x(i)
です。
def is_even(x): # True if x is even, False if x is odd
return x % 2 == 0
x_evens = [x for x in xs if is_even(x)] # [2, 4]
x_evens = filter(is_even, xs) # same as above
list_evener = partial(filter, is_even) # *function* that filters a list
x_evens = list_evener(xs) # [2, 4]
reduce
複数の要素を1つにまとめたいときに使う。
具体的には配列の先頭から2つの要素を取り出して処理を行い、次はその結果とその次の要素に処理を行う…ということを繰り返すそうです。
python3からはfunctools
からimport
しないとダメになったそうです。
from functools import reduce
def multiply(x, y): return x * y
x_product = reduce(multiply, xs) # = 1 * 2 * 3 * 4 = 24
list_product = partial(reduce, multiply) # *function* that reduces a list
x_product = list_product(xs) # 24
enumerate
ループ処理を行うときにenumerate
を使うと、要素のインデックスと要素の両方を同時に取得できます。
例えばdocuments
というリストの要素とインデックス両方にdo_something
という処理を繰り返し行う場合
# not Pythonic
for i in range(len(documents)):
document = documents[i]
do_something(i, document)
とすれば良いのですが、Pythonicじゃないそうです。
なので、enumerate
を使い(index, element)
のタプルを作ります以下のようにします。
for i, document in enumerate(documents):
do_something(i, document)
仮にインデックスのみを取得したい場合は以下のようにします。(2行目が好ましい)
for i in range(len(documents)): do_something(i) # not Pythonic
for i, _ in enumerate(documents): do_something(i) # Pythonic
enumerateとzipの違い
a = [a1, a2, a3]
b = [b1, b2, b3]
# enumerate
for i, a_i in enumerate(a):
print(i, a_i)
#---- 結果 -----
# 0 a1
# 1 a2
# 2 a3
#---------------
# zip
for a_i, b_i in zip(a,b):
print(a_i, b_i)
#---- 結果 -----
# a1 b1
# a2 b2
# a3 b3
#---------------
#参照