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

計算の順序として以下の様なイメージです。

  1. [0,1,2,3,4] => [0 + 1,2,3,4] = [1,2,3,4]
  2. [1,2,3,4] => [1 + 2,3,4] = [3,3,4]
  3. [3,3,4] => [3 + 3,4] = [6,4]
  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}