Python Tips
pythonを利用する上で、便利な表記などの個人的なメモです。基本的な部分は触れていません。対象も自分が便利だなと思ったものに限定されます。
github
- githubのjupyter notebook形式のファイルはこちら
google colaboratory
- google colaboratory で実行する場合はこちら
筆者の環境
!sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.6
BuildVersion: 18G95
!python -V
Python 3.5.5 :: Anaconda, Inc.
timeit
関数の実行時間を計測するためのモジュールです。
https://docs.python.org/2/library/timeit.html
import timeit
timeit.timeit('[ i for i in range(10)]')
1.7865126989781857
平均を取るための繰り返し回数number
を指定することが出来ます。デフォルトは1000000(100万回)です。
number = 1000000
timeit.timeit('[ i for i in range(10)]', number=number)
1.9443903490027878
timeit.repeat()関数を用いて、repeatオプションを用いることにより、timeitiを多数回繰り返すことが出来ます。
repeat = 5
number = 1000000
timeit.repeat('[ i for i in range(10)]', number=number,repeat=repeat)
[1.810243125015404,
1.9543377529771533,
1.7649507180030923,
1.962000719999196,
1.8034991680178791]
%timeit, %%timeit
jupyter notebook形式で処理の時間を計るためのマジックコマンドです。%timeitは引数となるコマンドが対象、%%timeitはセル全体が対応します。
また、-r
と-n
オプションによりtimeitのrepeatとnumberに対応させることが出来ます。
%timeit [i ** 2 for i in range(10000)]
3.56 ms ± 183 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit -r 5 -n 1000 [i ** 2 for i in range(10000)]
3.51 ms ± 41 µs per loop (mean ± std. dev. of 5 runs, 1000 loops each)
%%timeit
a = [i for i in range(10000)]
b = list(map(lambda x: x **2, a))
4.42 ms ± 260 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
内包表記
forなどを利用せずに、リストを作成します。リストを作成するアルゴリズムは高速化されており、推奨されているようです。
リスト型
[i for i in range(5)]
[0, 1, 2, 3, 4]
[i * 2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
ifがある場合
[i * 2 for i in range(10) if i % 2 == 0]
[0, 4, 8, 12, 16]
[i * 2 if i % 2 == 0 else 1 for i in range(10)]
[0, 1, 4, 1, 8, 1, 12, 1, 16, 1]
文字列もOK
[ord(i) for i in "TensorFlow"]
[84, 101, 110, 115, 111, 114, 70, 108, 111, 119]
2次配列もOK
[[i for i in range(10)] for j in range(10)]
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]
[[j for i in range(10)] for j in range(10)]
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
[6, 6, 6, 6, 6, 6, 6, 6, 6, 6],
[7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
[8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]]
時間測定
内包表記と通常のやや冗長なfor文を用いたリスト作成方法の比較を行ってみます。
%timeit [i for i in range(1000000)]
133 ms ± 5.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
a = []
for i in range(1000000):
a.append(i)
202 ms ± 22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
内包表記を利用すると、6割程度短縮できます。リスト型はすべて内包表記で作成した方が良さそうです。
辞書型
辞書型にも内包表記は使えます。とても便利です。
a = {'a':1, 'b':2, 'c':3}
print('a : ',a)
print('reverse a : ',{j:i for i,j in a.items()})
a : {'c': 3, 'b': 2, 'a': 1}
reverse a : {1: 'a', 2: 'b', 3: 'c'}
lambda
基本
無名関数といわれるものです。わざわざ関数に名前を与えるまでもない関数に対して利用されます。単独で用いられることは少なく、次に説明するmapやfilterなどの高階関数、sortなどと共に利用する場合が多いです。
# defという関数定義を利用していない
a = lambda x: x ** 2
print(a(10))
print((lambda x: x ** 2)(10))
100
100
引数を二つ持つ場合
# スカラーの足し算
(lambda a,b: a + b)(1,2)
3
# listの足し算
(lambda a,b: a + b)([1,2,3],[4,5,6])
[1, 2, 3, 4, 5, 6]
if ~ else ~
lambdaの中でもif~else~が利用できます。
print((lambda a: a if a == 0 else -100)(-1))
print((lambda a: a if a == 0 else -100)(0))
print((lambda a: a if a == 0 else -100)(1))
-100
0
-100
高階関数
関数自体を引数や返り値に含む関数の事です。引数にlambdaを利用する場面が多いと思います。
map
利用例は以下の通りです。リストのそれぞれの要素に対して、一律に引数である関数の処理を実行させます。
a = [i for i in range(10)]
print('a : ',a)
print('map : ',list(map(lambda x: x ** 2, a)))
a : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
map : [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
lambdaの中にif~else~を入れた例です。
a = [i for i in range(10)]
print('a : ',a)
print('map : ',list(map(lambda x: x ** 2 if x % 3 == 0 else 100, a)))
a : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
map : [0, 100, 100, 9, 100, 100, 36, 100, 100, 81]
a = [i for i in range(10)]
b = [i for i in range(10,0,-1)]
print('a : ',a)
print('b : ',b)
print('lambda : ',list(map(lambda a,b: a + b, a,b)))
a : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b : [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
lambda : [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
filter
利用例は以下の通りです。リストのそれぞれの要素に対して、一律に引数である関数の処理を実行させます。結果がfalseの要素は削除されます。
a = [i for i in range(10)]
print('a : ',a)
print('filter1 : ',list(filter(lambda x: x > 5,a)))
print('filter2 : ',list(filter(lambda x: x % 2 == 0,a)))
a : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
filter1 : [6, 7, 8, 9]
filter2 : [0, 2, 4, 6, 8]
reduce
resuce(f,x,[op])
で第一引数に引数を二つ持つ関数、第二引数に配列を取るように定義されています。配列の要素それぞれが逐次的に第一引数の関数の対象となります。
import functools
x = [i for i in range(5)]
print('x : ',x)
print('reduce : ',functools.reduce(lambda a,b:a+b, x))
x : [0, 1, 2, 3, 4]
reduce : 10
計算の順序として以下の様なイメージです。
[0,1,2,3,4]
=>[0 + 1,2,3,4]
=[1,2,3,4]
[1,2,3,4]
=>[1 + 2,3,4]
=[3,3,4]
[3,3,4]
=>[3 + 3,4]
=[6,4]
[6,4]
=>[6 + 4]
=[10]
最終的に10が得られます。
shutil
使い方はたくさんあり、気まぐれで更新していきます。
ディレクトリ中のファイルをすべて削除する場合
一度ディレクトリを削除し、もう一度からのディレクトリを作成するのが良さそうです。
import os
import shutil
_dir = './test/'
if os.path.exists(_dir):
shutil.rmtree('./test')
os.mkdir('./test')
# shutil.rmtree('./test')
random
乱数関係のモジュールです。
choice
与えられたリストの中から一つの要素をランダムに抽出します。
import random
random.choice(range(10))
6
shuffle
リストをランダムにシャッフルします。破壊的なメソッドで、オブジェクトそのものを更新します。
import random
a = [i for i in range(10)]
random.shuffle(a)
print('a : ',a)
a : [0, 9, 3, 7, 4, 1, 5, 2, 8, 6]
sample
リストをランダムにシャッフルした配列を返します。非破壊的なメソッドで新たなオブジェクト作成します。
import random
a = [i for i in range(10)]
b = random.sample(a, len(a))
print('a : ',a)
print('b : ',b)
a : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b : [8, 9, 4, 1, 3, 7, 2, 0, 5, 6]
sort
sortメソッド
破壊的なメソッドです。元のオブジェクトを更新します。
import numpy as np
a = list(np.random.randint(10, size=10))
print('before a : ',a)
a.sort()
print('sorted a : ',a)
before a : [7, 1, 0, 5, 8, 3, 3, 2, 7, 3]
sorted a : [0, 1, 2, 3, 3, 3, 5, 7, 7, 8]
sorted関数
非破壊的なメソッドです。ソート済みのオブジェクトを返します。
import numpy as np
a = list(np.random.randint(10, size=10))
print('before a : ',a)
b = sorted(a)
print('sorted a : ',b)
before a : [1, 8, 4, 6, 3, 5, 6, 4, 7, 2]
sorted a : [1, 2, 3, 4, 4, 5, 6, 6, 7, 8]
リストやオブジェクトのソート
keyオプションを利用して、ソートする要素を指定します。
a = [
['a',1],
['b',6],
['c',3],
['d',2],
]
print('original : ',a)
b = sorted(a,key=lambda x:x[1])
print('sort by ascending order : ', b)
c = sorted(a,key=lambda x:x[1], reverse=True)
print('sort by descending order : ', c)
original : [['a', 1], ['b', 6], ['c', 3], ['d', 2]]
sort by ascending order : [['a', 1], ['d', 2], ['c', 3], ['b', 6]]
sort by descending order : [['b', 6], ['c', 3], ['d', 2], ['a', 1]]
a = [
{'a':1},
{'a':6},
{'a':3},
{'a':2},
]
print('original : ',a)
b = sorted(a,key=lambda x:x['a'])
print('sort by ascending order : ', b)
c = sorted(a,key=lambda x:x['a'], reverse=True)
print('sort by descending order : ', c)
original : [{'a': 1}, {'a': 6}, {'a': 3}, {'a': 2}]
sort by ascending order : [{'a': 1}, {'a': 2}, {'a': 3}, {'a': 6}]
sort by descending order : [{'a': 6}, {'a': 3}, {'a': 2}, {'a': 1}]
辞書型の要素もソートして取得することが出来ます。
a = {
'a':1,
'd':6,
'c':3,
'b':2,
}
print('keyでソート')
b = sorted(a.items(), key=lambda x:x[0])
c = sorted(a.items(), key=lambda x:x[0], reverse=True)
print('orig : ',a)
print('asc : ',b)
print('des : ',c)
print()
print('valueでソート')
b = sorted(a.items(), key=lambda x:x[1])
c = sorted(a.items(), key=lambda x:x[1], reverse=True)
print('orig : ',a)
print('asc : ',b)
print('des : ',c)
keyでソート
orig : {'b': 2, 'c': 3, 'd': 6, 'a': 1}
asc : [('a', 1), ('b', 2), ('c', 3), ('d', 6)]
des : [('d', 6), ('c', 3), ('b', 2), ('a', 1)]
valueでソート
orig : {'b': 2, 'c': 3, 'd': 6, 'a': 1}
asc : [('a', 1), ('b', 2), ('c', 3), ('d', 6)]
des : [('d', 6), ('c', 3), ('b', 2), ('a', 1)]
その他
set型リストをdict型へキャスト
何かと便利なのでメモメモ。
a = [
("a", 1),
("b", 2),
("c", 3),
("d", 4),
]
dict(a)
{'a': 1, 'b': 2, 'c': 3, 'd': 4}