è²ã Pythonãéãããããã®äžã®äžã«æ¹æ³ã¯ãããŸãããæ¬èšäºã§ã¯CythonãPyPyãªã©ã®é«éåã®TIPSã«è§ŠããŠãããŸãã
ãã®èšäºã§è§Šããããš
- ãããã¡ã€ã©ãŒãªã©ã®èšæž¬é¢ä¿
- ãã«ãã€ã³ã¢ãžã¥ãŒã«ãªã©ã®æ©èœ
- Pythonã®ãã£ãã·ã¥é¢ä¿
- Cython
- Numba
- PyPyïŒç޹ä»ã ãïŒ
- ãã®ä»äžéšã®ãµãŒãããŒãã£ãŒã®ã©ã€ãã©ãªé¢ä¿
ãã®èšäºã§è§Šããªããã©ãã®ãã¡æžããããããªãå 容
- 䞊ååŠçïŒmultiprocessingïŒã䞊è¡åŠçïŒthreadingïŒãéåæåŠçïŒasyncioïŒããããã®çµã¿åããïŒconcurrent.futuresïŒãªã©
- Daské¢ä¿
- PyPyã®èžã¿èŸŒãã æ€èšŒå 容ãªã©
- 話é¡ã®Vaex
èšäºã§äœ¿ãç°å¢
- Windows10ïŒããŒã«ã«ã®JupyterïŒãšUbuntuïŒã¯ã©ãŠãäžã®ã«ãŒãã«ïŒã§é²ããŠãããŸãã
- èšèªã¯Python3.7.1ïŒwinïŒãšPython3.6.6ïŒUbuntuïŒã䜿ããŸãã
- Jupyteräžã§ã®å®è¡ãåæãšããŸãã.pyãã¡ã€ã«ã ãšå°ã話ãå€ãã£ãŠãããšããããŒã¡ãŒã¡ãããŸãã
ãŸãã¯èšæž¬ããæ¹æ³ãåŠã¶
ãŸãã¯ãšã«ããèšæž¬ããŸããã©ããé
ãã®ããããããææ¡ã§ããªããšãæ¹åããããšããŠé 匵ã£ãŠã广ãèãã£ããããŸãã
100ç§ã®åŠçã10ïŒ
æ¹åããæ¹ãã10ç§ã®åŠçã50ïŒ
æ¹åããããã广ã倧ãããç°¡åãªããšãå€ãã®ã§åè
ãæ¢ããŠããããšãã£ãæãã§ãã
%timeitã®ããžãã¯ã³ãã³ã
ãŸãã¯ã銎æã¿ã®timeitã®ããžãã¯ã³ãã³ãã§ããçµæ§Pythonæ¬ã§ãåºãŠããããšãå€ãã®ã§ããåç¥ã®æ¹ãå€ããšæããŸãã
æå®ãããã³ãŒããäœåºŠãå®è¡ãããçµæã®åŠçæéãåºåãããŸãã
ããžãã¯ã³ãã³ãå šè¬ã«èšããããšã§ãããåäžè¡ã§ããã°%ãäžã€ãã»ã«å ã®è€æ°è¡ã®åŠçã§ããã°%%timeitãš%èšå·ãäºã€äžŠã¹ãããšã§äœ¿ããŸãã
åäžè¡ã®äŸ :
%timeit [i for i in range(3000000)]
267 ms ± 50.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
è€æ°è¡ã§ã®äŸ :
%%timeit
index_list = []
for i in range(3000000):
index_list.append(i)
417 ms ± 4.27 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%prunã®ããžãã¯ã³ãã³ã
ã·ã³ãã«ãªåŠçã§ããã°timeitã®ããžãã¯ã³ãã³ãã§äºè¶³ããŸãã
ããããé·ãåŠçãšãã§ããã€ãã®äžã§è²ã
ãªé¢æ°ãåŒã³åºããŠããããããšå°ãææ¡ãé£ãããªããŸãã
ãããã£ãå Žåã¯%prunã®ããžãã¯ã³ãã³ãã䜿ããšãå®è¡ããã颿°åäœã§è²ã
èšæž¬çµæãèŠãããšãã§ããŸãã
def sample_func_1():
index_list = []
for i in range(1000000):
index_list.append(i)
def sample_func_2():
index_list = []
for i in range(2000000):
index_list.append(i)
def sample_func_3():
index_list = []
for i in range(6000000):
index_list.append(i)
def sample_func_4():
sample_func_1()
sample_func_2()
sample_func_3()
é©åœãª4ã€ã®é¢æ°ãçšæããŸããã
4ã€ç®ã®é¢æ°ã¯ããããã®é¢æ°ãåŒã³åºããŠããã ãã§ãã
ããžãã¯ã³ãã³ããšãšãã«ã4ã€ç®ã®é¢æ°ãå®è¡ããŠã¿ãŸãã
%%prun
sample_func_4()
ãããããšãdocstringã衚瀺ãããšãã®ããã«ãJupyterã®äžã®æ¹ã«èšæž¬çµæã衚瀺ãããŸãã
9000000 0.613 0.000 0.613 0.000 {method 'append' of 'list' objects}
appendã¡ãœããã9000000ååŒã°ããŠããããããã§æéã0.61ç§ããã£ãŠãããããã®ã»ãã®é¢æ°ã¯1åãã€åŒã°ããŠãããããšãã£ãããšãåãããŸãã
ïŒâ»4çªç®ã®é¢æ°ã颿°åŒã³åºãã ãã§ããã0.1ç§ãããã£ãŠãããšããã®ã¯éåæããããŸãããèšæž¬ã®ãªãŒããŒããããšããªã®ã§ããããã»ã»ïŒåºæ¬é ã颿°ãç¹å®ããã®ãç®çãªã®ã§ãåé¡ãªããšå€æããŠé²ããŸãïŒ
åã«ã©ã ã¯ä»¥äžã®ãããªå 容ã衚ããŸãã
- ncalls: ãã®é¢æ°ã®åŒã³åºãåæ°
- tottime: ãã®é¢æ°ã®ãã»ãã®é¢æ°å®è¡ãé€ããåŠçæé
- percall: ãã®é¢æ°ã®1åã®åŒã³åºããããã®åŠçæéïŒä»åã®appendã¿ãããªãåŠçã¯æ©ããã©èšå€§ãªåæ°å®è¡ãããããªå 容ã ãšå€ã0ã«ãªããŸãïŒ
- cumtime: ä»ã®åŒã³åºããŠãã颿°ãªã©ãå«ããå®è¡æé
- filename:lineno: 察象ã®é¢æ°åãè¡çªå·ïŒã»ã«å ã®è¡çªå·ïŒã衚ããŸã
è¡åäœã§ã®åŠçæéã調ã¹ã : line_profiler
prunã§ã®èšæž¬ã§é
ã颿°ãåãã£ããšããŠããããããããã®é¢æ°ããšãŠãé·ããŠã颿°ã®äžã§ã©ã®åŠçãé
ãã®ããåãããªãã»ã»ãšããã±ãŒã¹ããããããããŸããã
ãããã£ãéã«ã¯line_profilerã®ã©ã€ãã©ãªã䜿ãããšã§ã颿°å
ã®è¡åäœã§è©³çްã調ã¹ãŠããããšãã§ããŸãã
ãŸãã¯ã©ã€ãã©ãªãå¿ èŠã«ãªãã®ã§å ¥ã£ãŠããªããã°pipã§ã€ã³ã¹ããŒã«ããŸãã
$ pip install line_profiler
ãããã¯ãWindowsç°å¢ãšãã®å Žåã§äžã€Anacondaãªã©ã䜿ã£ãŠããå Žåãcondaçµç±ã®æ¹ãã€ã³ã¹ããŒã«ã楜ãããããŸãããïŒç§ã®ãšãã¯Ubuntuç°å¢ã§ã¯ããã£ãšpipã§ããããã®ã®ãWindowsã§ã¯C++é¢ä¿ã§ãšã©ãŒã«ãªããå¥éãµã€ãããèœãšããŠãããã®å¯Ÿå¿ãèŠæ±ããããããã®ã§ïŒ
$ conda install -c anaconda line_profiler
ä»åã¯line_profiler-2.1.2ã®ããŒãžã§ã³ã䜿ã£ãŠãããŸãã
äœ¿ãæ¹ã¯ã颿°ã®è¿œå ãå®è¡ãªã©ãããŠããã®åŸã«print_statsã¡ãœãããåŒã¶ãšèšæž¬çµæã衚瀺ããŠãããŸãã
import line_profiler
def sample_func():
index_list = []
for i in range(1000000):
index_list.append(i)
for i in range(3000000):
index_list.append(i)
for i in range(10000000):
index_list.append(i)
profiler = line_profiler.LineProfiler()
profiler.add_function(sample_func)
_ = profiler.runcall(sample_func)
profiler.print_stats()
ãã®è¡ã§åŠçãäœåå®è¡ããŠããã®ãïŒHitsïŒãåŠçæéã¯ã©ããªãã®ãªã®ãïŒTimeïŒã1åãããã®åŠçæéã¯ã©ã®çšåºŠãªã®ãïŒPer HitïŒã颿°å šäœã§å ããå²åã¯ã©ã®ããããªã®ãïŒïŒ TimeïŒã察象è¡ã®å 容ïŒLine ContentsïŒã衚瀺ãããŸãã
é©åãªããŒã¿æ§é ãªã©ã䜿ã£ãŠéããã
é床æ¹åã§è²ã ãªãã¯ããã¯ããããã®ã®ããŸãã¯å¿ èŠãªæ©èœãšããã«é©ãããã®ãäœãªã®ãããšããåŒãåºããå€ããã£ãŠãããšããã®ãã·ã³ãã«ã§åœ¹ã«ç«ã€ã±ãŒã¹ããããŸãã
ãµã³ãã«ãšããŠããã€ãèŠãŠãã£ãŠã¿ãŸãã
ãªã¹ãã®å é ãå€åããã±ãŒã¹ãåŸæãªdeque
äŸãã°ããªã¹ããžã®èŠçŽ ã®è¿œå ãèããŠã¿ãŸãããã
append颿°ã§ããªã¹ãã®æ«å°Ÿã«è¿œå ããå Žåã远å å
ã®ãªã¹ãã®ä»¶æ°ãå€ããŠããããŸã§é床ã§åé¡ã«ãªã£ãŠã¯ããŸããã
远å å ã®ãªã¹ãã®ä»¶æ°ãå°ãªãå Žåãšå€ãå Žåã®æ¯èŒãä»¶æ°ã倧ãããªã£ãŠãç¹ã«ããã©ãŒãã³ã¹ã«åœ±é¿ãåºãŠãããã¯ããŸãã :
small_list = [i for i in range(1000)]
large_list = [i for i in range(100000000)]
%%timeit
small_list.append(10)
76.3 ns ± 4.95 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
large_list.append(10)
74.4 ns ± 24.7 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
ããããããšãã°ãªã¹ãã®å é ã«è¿œå ãå¿ èŠãªã±ãŒã¹ãpopã§å é ã®èŠçŽ ãåãåºãããããå Žåãªã©ã«ã¯ãã€ã³ããã¯ã¹ããããã®ã§ãªã¹ãã®ä»¶æ°ãå€ããšå€§ããªè² æ ãšãªããŸãã
ãªã¹ãã®ä»¶æ°ã®å€ãã§ããã©ãŒãã³ã¹ã倧ããå€ãã£ãŠããäŸ :
small_list = [i for i in range(1000)]
large_list = [i for i in range(100000000)]
%%timeit -n 100
small_list.insert(0, 10)
643 ns ± 70.1 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit -n 3
large_list.insert(0, 10)
68.7 ms ± 569 µs per loop (mean ± std. dev. of 7 runs, 3 loops each)
åŠçæéããå°ããã»ãã®ãªã¹ãã§ã¯ããç§ã®åäœã§çµãã£ãŠããäžæ¹ã§ã倧ãããªã¹ãã®æ¹ã§ã¯ããªç§åäœã®åŠçæéãããããŸã§ã®å·®ãåºãŠããŸããã
â»timeit ã®-nåŒæ°ã¯å®è¡åæ°ã§ããããã©ã«ãã¿ããåæã«å®è¡åæ°ã決ããããç¶æ ã ãšå°ãªããªã¹ãã®æ¹ã«èšå€§ã«å€ã远å ãããŠããŸã£ãŠã段ã é ããªããããå°ãªãåæ°ã«ããŠããŸãã
ãŸããããããããæ«å°Ÿã«èŠçŽ ã远å ããå Žåã§ãã1件远å ãããå é ã®1ä»¶ãåãé€ããã¿ãããªãã¥ãŒã®å®è£ ãå¿ èŠã«ãªãããšããããããããŸããã
ãããã£ãå Žåã«ã¯ãäŸãã°ãã«ãã€ã³ã¢ãžã¥ãŒã«ã®dequeãªã©ã䜿ããšããŸãããšæ¹åã§ããŸãã
dequeã¢ãžã¥ãŒã«ã䜿ãããšã§ãå°ãããªã¹ãã§ã倧ãããªã¹ãã§ããããããçæéã§å é ã«èŠçŽ ã远å ã§ããäŸ :
from collections import deque
small_list = [i for i in range(1000)]
large_list = [i for i in range(100000000)]
q1 = deque(small_list)
%%timeit -n 100
q1.insert(0, 10)
84.4 ns ± 2.33 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)
q2 = deque(large_list)
%%timeit -n 100
q2.insert(0, 10)
80.7 ns ± 3.04 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)
äœæããdequeã®ãªããžã§ã¯ãã¯ãè¥å¹²ãªã¹ããšã¯äœ¿ãåæãéããŸããããªã¹ãåæ§ã€ã³ããã¯ã¹ãªã©ã§å€ã«ã¢ã¯ã»ã¹ã§ããŸããå é ã®èŠçŽ ã«ã¢ã¯ã»ã¹ãããšã远å ããèŠçŽ ã«ãªã£ãŠããããšãåãããŸãã
q1[0]
10
ãŸããdequeã®ç¬¬äºåŒæ°ã®maxlenãæå®ããããšã§ãæ«å°Ÿã«èŠçŽ ãå ããéã«ããã®åã ãå é ã®èŠçŽ ãåãé€ãããšããå®è£ ãã§ããŸãã
q3 = deque(large_list, maxlen=10000000)
len(q3)
10000000
%%timeit -n 100
q3.append(100)
51.6 ns ± 4.54 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)
æ«å°Ÿã®èŠçŽ ã«ã¢ã¯ã»ã¹ããŠã¿ããšããããã«è¿œå ããèŠçŽ ã«ãªã£ãŠããŸãã
q3[-1]
100
ãŸãã远å ããåãå é ã®èŠçŽ ãåãé€ãããå šäœã®ä»¶æ°ãå€ãã£ãŠããªãç¹ã確èªã§ããŸãã
len(q3)
10000000
ãªã¹ãã§æ«å°Ÿã«èŠçŽ ãå ããŠãããã«å é ã®èŠçŽ ãåé€ããŠã»ã»ãšããã®ã«æ¯ã¹ããšãã·ã³ãã«ã«ããã£ãšéããªããŸãã
ãã¡ããããªã¹ãã«å¯ŸããŠdequeã®æ¹ããã¹ãŠã®ã±ãŒã¹ã§å¥œãŸããããšèšããããšãåœç¶ãããªããšã¯ãªããäŸãã°å é ãžã®è¿œå ãåé€ãªã©ã«ããã€ã³ããã¯ã¹ãããããããªåŠçã¯åŸæãšããŠããäžæ¹ã§ãçãäžã®ããããžã®èŠçŽ ã®è¿œå ã¯èŠæãšããŠããŸãã
q4 = deque(large_list)
%%timeit -n 100
q4.insert(5000000, 200)
11.6 ms ± 135 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
dequeã䜿ã£ãŠããŠãããªç§ã®åäœãšã倧åé ããªã£ãŠããŸããŸããããã®ããã«ãåŸæã»äžåŸæãªé åãããã®ã§ãå®è£ ãããå 容ãéèšå 容ãªã©ã«å¿ããŠããŸãããšäœ¿ãåããããšã倧åã«ãªã£ãŠããŸãã
ããŒã®ãã§ãã¯ãäžèŠãªdefaultdict
ã«ãŒãã§åããŠãããããã®ããŒã®å€ãã€ã³ã¯ãªã¡ã³ãããŠãããããªåŠçïŒãããã¯ä»»æã®å€ãå ç®ãªã©ããŠããåŠçïŒãèããŠã¿ãŸãã
ãããã£ãéã«ãéåžžã®dictã®å Žåã€ã³ã¯ãªã¡ã³ãã®éã«ããŒã®æç¡ããã§ãã¯ãããããªåå²ãå¿
èŠã«ãªã£ãŠããŸãã
æ®éã®èŸæžã§åŠçããäŸ :
import numpy as np
random_key_arr = np.random.randint(low=0, high=100, size=10000000)
%%timeit
sample_dict = {}
for random_key_int in random_key_arr:
has_key = random_key_int in sample_dict
if has_key:
sample_dict[random_key_int] += 1
else:
sample_dict[random_key_int] = 1
2.14 s ± 1.74 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
倧ããåŠçã§ã¯ãªãã®ã§ãããã§ã1000äžä»¶ã®ã«ãŒãçšåºŠã§ããã°ååæ©ãã¹ããŒãã§åŠçã§ããŸããã
ãããããããã£ãå Žåã¯defaultdictã䜿ããšèšè¿°ãã·ã³ãã«ã«ãªããäœåãªåå²ãç¡ããªãã®ã§å°ãæ©ããªã£ããããŸãã
defaultdictã¯ãdequeãšåããcollectionsããã±ãŒãžã«å«ãŸãããã«ãã€ã³ã®ã¢ãžã¥ãŒã«ã§ãèŸæžçææã«æ ŒçŽãããå€ã®åãæå®ããããšã§ããã®åã«å¿ããåæå€ãèªåã§èšå®ããŠãããŸããããšãã°ãintãæå®ããã°0ãstrãæå®ããã°ç©ºæåãèšå®ãããŸãã
from collections import defaultdict
%%timeit
sample_dict = defaultdict(int)
for random_key_int in random_key_arr:
sample_dict[random_key_int] += 1
1.55 s ± 1.12 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
èšè¿°ããã£ããããŠãäžã€é床ã埮åŠã«æ©ããªããŸããã
ãªããããŒãè€æ°å¿
èŠãªå Žåã¯ããŒã«tupleã䜿ããããããã¯lambdaåŒã§ããã«defaultdictãæ ŒçŽãããšãè€æ°ã®ããŒãæã£ãèŸæžãæ±ããŸãããã¡ãã®å Žåãããã¹ãããéšåã«ifæãæžããªããŠæžãã®ã§ã·ã³ãã«ã§ãã
äœãèããã«ãã¹ãããŠããããŸãè¯ããªãäŸ :
random_key_arr_1 = np.random.randint(low=0, high=100, size=1000000)
random_key_arr_2 = np.random.randint(low=0, high=100, size=30)
%%timeit
sample_dict = {}
for random_key_1 in random_key_arr_1:
has_key = random_key_1 in sample_dict
if not has_key:
sample_dict[random_key_1] = {}
for random_key_2 in random_key_arr_2:
has_key = random_key_2 in sample_dict[random_key_1]
if has_key:
sample_dict[random_key_1][random_key_2] += 1
else:
sample_dict[random_key_1][random_key_2] = 1
10 s ± 22.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
sample_dict = defaultdict(lambda: defaultdict(int))
for random_key_1 in random_key_arr_1:
for random_key_2 in random_key_arr_2:
sample_dict[random_key_1][random_key_2] += 1
ãã¹ããããããªã±ãŒã¹ã§ã¯å€§åèšè¿°ã®ã·ã³ãã«ãã«å·®ãåºãŠããŸãã
6.81 s ± 16.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
â»ããŒã«tupleã䜿ãå Žåã¯ãã¹ãããã±ãŒã¹ã§ã¯ããã¹ãããŠãéåžžã®èŸæžãšdefaultdictã§ãããŸã§ã·ã³ãã«ãã«å·®ã¯ãããŸããã
åçŽã«èŠçŽ ã®ã«ãŠã³ãã ããªããCounterã§ãã£ãšã·ã³ãã«ã«ã§ãã
ãããããåè¿°ã®ãããªèŸæžã§ã®ã«ãŒããå¿ èŠãªããã«ãŠã³ãã ãã§ããã°ãã«ãã€ã³ã®collections.Counterã¢ãžã¥ãŒã«ã§äžç¬ã§åŠçãçµãããŸãã
from collections import Counter
random_key_arr = np.random.randint(low=0, high=100, size=10000000)
%%timeit
counter = Counter(random_key_arr_1)
116 ms ± 136 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
1000äžä»¶ã®ã«ãŠã³ãã§çŽ116ããªç§ãçµæ§æ©ãã§ãã
å°ãªããšãã«ãŒããåãããã¯å€§åæ©ãã§ããïŒãã¡ãããPandasãšã䜿ã£ãŠãããæãã§ã¯ãããŸããã»ã»ïŒ
çæããCounterãªããžã§ã¯ãã¯ãèŸæžæèŠã§ã«ãŠã³ãå€ã«ã¢ã¯ã»ã¹ãã§ããŸãã
counter[50]
10045
ãã®ãŸãŸåºåãããšãããŒãšä»¶æ°ã§ã®çµã¿åããã«ãªã£ãŠããããšãåãããŸãã
counter
Counter({63: 9890,
16: 10009,
8: 10123,
18: 10030,
46: 10127,
57: 9737,
...
åæ¹äžèŽæ€çŽ¢ã ãã§ãããªããã©ã€æšãªã©ã䜿ãã®ããã
ããšãã°ãQiitaã®ã¿ã°ã®èšå®æã«åºãŠããåè£ãæ¢ãããããã±ãŒã¹ãæ®éã«å€å®ããŠãããã®ã§ãããã¿ã°ãèšå€§ã«ãªã£ãŠãããšçµæ§é床çã«èŸããã®ããããŸãã
ãããã£ãå Žåã«ã¯ãã©ã€æšã¿ãããªããŒã¿æ§é ã䜿ããšéåžžã«é«éã«æ€çŽ¢ãã§ããŸãã
è²ã ãªãã©ã€æšã®ã©ã€ãã©ãªããããŸãããä»åã¯patricia-trieãšããã©ã€ãã©ãªã䜿ããŸãã
$ pip install patricia-trie
Successfully installed patricia-trie-10
詊ãã«ãã©ã³ãã ãªæååãçšæããŠè©ŠããŠã¿ãŸãããã
16æåã®AïœZãŸã§ã®ã¢ã«ãã¡ãããã®çµã¿åããã®æååãçæãã颿°ãçšæããŸããã
from random import choice
from string import ascii_uppercase
def make_random_str():
"""
16æåã®AïœZã®çµã¿åããã®ã©ã³ãã ãªæååãçæããã
Returns
-------
random_str : str
çæãããæååã
"""
return ''.join(choice(ascii_uppercase) for i in range(16))
以äžã®ãããªæååãçæãããŸãã
make_random_str()
'ILWYLJBHPOHMUBCZ'
ãŸãã¯300äžä»¶ã®æååãçšæããŠãäœãèããã«ã«ãŒãã§ãæååã®å é ã"ABC"ã§å§ãŸãæååãæ¢ã察å¿ã®é床ãèŠãŠã¿ãŸãã
random_str_list = [make_random_str() for i in range(3000000)]
%%timeit
matched_str_list = []
for random_str in random_str_list:
if random_str.startswith('ABC'):
matched_str_list.append(random_str)
289 ms ± 2.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
ä»¶æ°ã®å²ã«ã¯ãŒã¡ãŒã¡éãã§ãããããã£ã¡ã ãå®è¡ããããããªã±ãŒã¹ã§ã¯å€§åèŸãå°è±¡ã§ãã
ãã©ã€æšã䜿ã£ãŠã¿ãŸãããã
èŸæžã®åœ¢åŒãå¿
èŠã ã£ããããã®ã§ãããŒã«ã©ã³ãã ãªæååãå€ã¯åç
§ããªãã®ã§0ãæå®ããèŸæžãçšæããŸãã
from patricia import trie
random_str_dict = {random_str: 0 for random_str in random_str_list}
random_str_trie = trie(**random_str_dict)
ãã®ãã©ã€æšã®çšæã®éšåã¯å°ãæéãããããŸãã
æºåãã§ãããã以äžã®ããã«ãããšåæ¹äžèŽã§æ€çŽ¢ãã§ããŸãã
matched_str_list = list(random_str_trie.iter('ABC'))
matched_str_list[:3]
['ABCIMAZBADIAJLMU', 'ABCIXODUIXBVHFNA', 'ABCIAIMMAZVGEVYY']
éåºŠãæž¬ã£ãŠã¿ãŸãã
%%timeit
matched_str_list = list(random_str_trie.iter('ABC'))
178 µs ± 918 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
300äžä»¶ã®æ€çŽ¢ããããªç§ã®åäœãããã€ã¯ãç§ã®åäœã«ãªããŸã§ã倧忩ããªããŸããã
ç¹åŸŽãšããŠãèšç®é床ãã»ãŒæååã®æå€§é·ã«äŸåãã圢ã«ãªã£ãŠããŸãïŒå¯Ÿè±¡ã®ä»¶æ°ã«ã»ãšãã©äŸåããŸããïŒããã®ãããé·æãšãã«ã¯äžåããããããŸããããã¿ã°ãåæ¹äžèŽã§åé¡ããªãå ¥åè£å®ãªããã§ãæ€çŽ¢å¯Ÿè±¡ãèšå€§ã«ãã£ãŠäžã€ããã©ãŒãã³ã¹ãèŠæ±ããããããªã±ãŒã¹ã§åãçºæ®ããŸãã
ãã®ä»ã«ããäŸãã°marisa-trieã®ãããªãæ®éã®èŸæžãããã¢ã¯ã»ã¹ãé ããäœ¿çšæãå°ã ç¹æ®ãªãã®ã®ãèŸæžã®ã¡ã¢ãªäœ¿çšéãå§åçã«äœãæžãããŒã¿æ§é ãªã©è²ã ãããŸãã
String data in a MARISA-trie may take up to 50x-100x less memory than in a standard Python dict; the raw lookup speed is comparable; trie also provides fast advanced methods like prefix search.
marisa-trie
ä»ã«ããããããããŸããããšãŠãèšäºãé·ããªã£ãŠããŸãã®ã§å²æããŸãã
ããããã®ç¹åŸŽã»åãäžåããææ¡ããŠãããŠãåŒãåºããå€ãããŠãããšãããä»äºã§æ±ããšãã«èŠä»¶ã«ããããããã®ãéžã¹ãŠåœ¹ç«ã€ãããããŸããã
Pythonäžã®ãã£ãã·ã¥ã®è©±
ã¯ãšãªããã£ãã·ã¥ãããããã®ãšåæ§ãPythonã®é¢æ°ãªã©ããã£ãã·ã¥ãããšéãã§ãããããŸãã
ïŒãã ãåŒæ°ã®çµã¿åãããèšå€§ã«ãªãã±ãŒã¹ãªã©ãæ¯åãã£ãã·ã¥ããªãã»ã»ãããªå Žåã¯éã«è² æ
ã«ãªãã ããªã®ã§ãã©ãã§ã䜿ãããšãããã®ã§ããããŸããïŒ
ãã®ãããããã«ãã€ã³ã§çšæãããŠãããã®ãäžå¿ã«èŠãŠãããŸãã
颿°ãã¡ã¢ãªäžã«ãã£ãã·ã¥ãã
functoolsã¢ãžã¥ãŒã«ã®lru_cacheããã³ã¬ãŒã¿ãŒãšããŠäœ¿ããšãåŒæ°ã®å 容ããã§ã«å®è¡ããããšã®ãããã¿ãŒã³ã®å Žåã¯ãã£ãã·ã¥ããŠããã€ã¬ã¯ãã«è¿åŽå€ãè¿ããŠãããããã«ãªããŸãã
from functools import lru_cache
@lru_cache()
def add(a, b):
print(f'èšç®åŠçãå®è¡ããŸã : a = {a}, b = {b}')
return a + b
add(a=100, b=300)
èšç®åŠçãå®è¡ããŸã : a = 100, b = 300
400
1åç®ã®å®è¡ã¯éåžžã®é¢æ°ã®å®è¡ãšå€ãããŸããã
ããäžåºŠãåãåŒæ°æ¡ä»¶ã§å®è¡ããŠã¿ãŸãã
add(a=100, b=300)
400
ä»åºŠã¯ããèšç®åŠçãå®è¡ããŸãããšããéšåã®printãããããçµæã ãè¿ã£ãŠããŸãããã€ãŸãã颿°ã®äžèº«ã¯éãããè¿åŽå€ããã€ã¬ã¯ãã«ãã£ãã·ã¥ããè¿åŽãããŠããŸãã
å¥ã®åŒæ°ã®æ¡ä»¶ã§å®è¡ããŠã¿ãŸãã
add(a=300, b=500)
èšç®åŠçãå®è¡ããŸã : a = 300, b = 500
800
ãã®ããã«ããã§ã«å®è¡æžã¿ã®åŒæ°æ¡ä»¶ã®éã«ã¯ãã£ãã·ã¥ãããã®ãŸãŸè¿åŽãããã§ã¯ãªãå Žåã«ã¯é¢æ°ã®äžãéããŠå€ãè¿åŽãããšããæåã«ãªããŸãã
åŒæ°ã®æ¡ä»¶ã®çµã¿åããããäœåºŠãåããã®ãå®è¡ããããããªæ¡ä»¶ã®éã«é«ã广ãçºæ®ããŸãã
ãã£ãã·ã¥ããæ¡ä»¶æ°ãå€ããã«ã¯ãåŒæ°ã®maxsizeã®å€ã倿ŽããŸãïŒããã©ã«ãã§ã¯128ãšãã£ãå°ãªãå€ãèšå®ãããŠããŸãïŒã
@lru_cache(maxsize=1024)
def add(a, b):
print(f'èšç®åŠçãå®è¡ããŸã : a = {a}, b = {b}')
return a + b
ãã®ä»¶æ°ãããå€ãã®åç
§ããããå Žåã«ã¯ãå€ããã£ãã·ã¥ããæ¶ããŠæ°ãããã£ãã·ã¥ã远å ãããŸããïŒlruãleast recently usedã®ç¥ãªã®ã§ãæè¿ã®ãã®ãæ®ããŸãïŒ
æ°å€ã倧ããã»ã©è²ã
ãªæ¡ä»¶ã®ãã£ãã·ã¥ãã§ããäžæ¹ã§ãã¡ã¢ãªãå€ãå¿
èŠã«ãªã£ãŠããŸãã
äžèŠã«ãªã£ããã£ãã·ã¥ãªã©ã¯ãcache_clear颿°ã§æ¶ãããšãã§ããŸãããã®é¢æ°ã¯ãã³ã¬ãŒã¿ãŒãèšå®ããã颿°ãæã¡ãŸããïŒé¢æ°ã颿°ãæã€ãšãããã¡ãã£ãšäžæè°ãªæèŠã»ã»ïŒ
add.cache_clear()
ãã£ã¹ã¯äžã§ãã£ãã·ã¥ãã
ã¡ã¢ãªäžã®ãã£ãã·ã¥ã¯éããŠãæè»œã§ããããããŸã§ã®é床ã¯äžèŠã§ãäžã€ã¡ã¢ãªã¯ä»ã®ãšããã«å²ããããšããã±ãŒã¹ããŒã¡ãŒã¡ãããŸãã
ãããã£ãã±ãŒã¹ã§ã¯joblibã©ã€ãã©ãªã䜿ããšãã£ã¹ã¯äžãžã®é¢æ°ã®ãã£ãã·ã¥ãªã©ãã§ããŸãã
ãŸãã¯ãã€ã³ã¹ããŒã«ããããŠããªããã°ã€ã³ã¹ããŒã«ããŸãã
$ pip install joblib
...
Successfully installed joblib-0.13.2
â»æ³šæ : Windowsäžã§è©ŠããŠãããããªãããã£ãã·ã¥ãããŸãããšãããŸããã§ãããããããããæ¥æ¬ã®Windowsã§ãã¹çãªãšããã§åé¡ãããã®ãããããŸããã»ã»ïŒãã¹ã®éœåã§ãã£ãã·ã¥ãç¡ãå€å®ã«ãªã£ãŠãããªã©ïŒã以äžã®ãã®ã¯ãUbuntuç°å¢ã§é²ããŠããŸãã
locationã®åŒæ°ã§ããã£ãã·ã¥ãæ ŒçŽãããã£ã¬ã¯ããªãæå®ããŸãã
import time
from joblib import Memory
memory = Memory(location='./disk_cache', verbose=0)
äœ¿ãæ¹ã¯ã¡ã¢ãªäžã®ãã£ãã·ã¥ãšäŒŒããããªæãã§ã颿°ã«ãã³ã¬ãŒã¿ãŒãæå®ãããšãã£ãã·ã¥ããŠãããŸãã
@memory.cache
def add(a, b):
print(f'èšç®åŠçãå®è¡ããŸã : a = {a}, b = {b}')
time.sleep(3)
return a + b
ååã®å®è¡ã¯æ®éã«é¢æ°ã®äžãéããŸãã
add(a=100, b=200)
èšç®åŠçãå®è¡ããŸã : a = 100, b = 200
300
äºåç®ããã¯é¢æ°ã®äžãéããããã€ã¬ã¯ãã«å€ãè¿åŽãããŠããããšãåãããŸãã
add(a=100, b=200)
300
ãã¡ããã颿°ã«clear颿°ã远å ãããã®ã§ããã¡ããåç §ããããšã§ãã£ãã·ã¥ã®ã¯ãªã¢ãã§ããŸãã
add.clear()
Cython
Cython ã¯ãCèšèªã«ããPythonã®æ¡åŒµã¢ãžã¥ãŒã«ã®äœæã®åŽåã軜æžããããšãç®çãšããŠéçºãããããã°ã©ãã³ã°èšèªã§ããããã®èšèªä»æ§ã¯ã»ãšãã© Python ã®ãã®ãšåã (äžäœäºæ) ã ããCã®é¢æ°ãçŽæ¥åŒã³åºããããCèšèªã®å€æ°ã®åãã¯ã©ã¹ã宣èšã§ãããªã©ã®æ¡åŒµãè¡ãããŠããã
Wikipediaãã
PythonæèŠã§æžããŠéããšããåã®Cythonãæ·±æããããšCythonåäœã§ãªã©ã€ãªãŒã®æ¬1åã«ãªãããããªã®ã§æ°è»œã«äœ¿ããŠäžã€é«éåã®æ©æµããŒã¡ãŒã¡åŸãããç¯å²ã§ãã®èšäºã§ã¯è§ŠããŠãããŸãã
Cythonã®ç°å¢
Ubuntuã§Anacondaãå
¥ããŠããã°ãã»ãŒäœãèããã«äœ¿ããŸãã
Windowsã ãšã¡ãã£ãšé¢åãªæãã«ãªã£ãŠããŸãã
ãã®ãŸãŸäœ¿ãããšãããšã以äžã®ãšã©ãŒãšãã§æãããŸãã
DistutilsPlatformError: Unable to find vcvarsall.bat
Python3.5以éã䜿ã£ãŠãããšæ³å®ããŠãVisual Studio ã³ãã¥ããã£ãšããå ¥ããã®ãæ¯èŒçã·ã³ãã«ã»ã»ãªã®ã§ããããïŒ
åè : Pythonã§Unable to find vcvarsall.batãšèšãããéã®ãŸãšã
çµæ§é¢åãããããªå°è±¡ãåããã®ãšãä»äºã ãšå€§äœLinuxã§äœæ¥ããŠããããšãå€ãã®ã§ãä»åã®èšäºã®å 容ã¯Ubuntuç°å¢ã§é²ããŸããïŒWindowsã®æ¹ã¯ããã£ãšè©Šãããå Žåã«ã¯Colaboratoryãªã©æšå¥šã§ãïŒ
CythonãJupyteräžã§äœ¿ã
以äžã®ãããªããžãã¯ã³ãã³ããå®è¡ãããšãJupyteräžã§Cythonã䜿ããããã«ãªããŸãã
%load_ext Cython
ããšã¯ãCythonã§æžãããã»ã«ã®å é ã§%%cythonãšããžãã¯ã³ãã³ãã®èšè¿°ãããã°ããã®èšè¿°ãCythonã®ãã®ã«ãªããŸãã
%%cython
def hello_cython():
print('Hello!')
ä»ã®ã»ã«ããã¯ãããžãã¯ã³ãã³ãç¡ãã§åŒã³åºããŸãã
hello_cython()
Cythonã®å€æ°å®çŸ©
cdefããŒã¯ãŒãã§ãå宣èšä»ãã§å€æ°ãå®çŸ©ã§ããŸããintãdoubleãšãã£ãè²ã
ãªåãçšæãããŠããŸãã
å宣èšãããããšã§ãã³ãŒãã®å®è¡ã倧忩ããªããŸãã
ããç°¡åãªäŸãšããŠã1ååã€ã³ã¯ãªã¡ã³ãããåŠçã詊ããŠã¿ãŸãã
ãŸãã¯æ®éã®Pythonã®ã³ãŒãã
def sample_func():
a = 0
for i in range(100000000):
a += 1
return a
%timeit sample_func()
6.91 s ± 174 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
6.91ç§ã
ç¶ããŠCythonã®ã³ãŒãã
%%cython
def sample_func_cython():
cdef int a = 0
for i in range(100000000):
a += 1
return a
%timeit sample_func_cython()
71.5 ns ± 3.45 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
71.5ããç§ãå šç¶éããŸãã
ç¹çãã¹ãç¹ãšããŠãäžå¿ã¯å¥ã®èšèªæ±ãïŒã§ãããPythonãšã»ãŒåããããªèšè¿°ã§æžããŠåŠç¿ã³ã¹ããäœãããã®ãŸãŸJupyteräžã.pyãã¡ã€ã«ã§ããã£ãšäœ¿ããŠãéåžžã®Pythonã®ã³ãŒããšã飿ºãç°¡åã«ã§ããç¹ã§ããããã
ãªããcdefã®åŸã®èšè¿°ãçç¥ããŠãå宣èšç¡ãã§äœ¿ã£ãŠã¿ããšãçã®Pythonãããã¯æ©ããã®ã®æ¥µç«¯ã«é ããªããŸãã
1.59 s ± 6.08 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Cythonã§ã®ãã£ã¹ã
<åå>ãšèšè¿°ããããšã§ãã£ã¹ãããããšãã§ããŸãã
%%cython
cdef int a = 100
cdef double b
b = <double> a
print(b)
Cythonã§ã®é¢æ°å®çŸ©
Cythonã§ã¯ã以äžã®ãããªé¢æ°å®çŸ©ã®ããŒã¯ãŒãããããŸããããããç¹åŸŽãç°ãªããŸãã
- def -> PythonãããåŒã³åºããã§ããã颿°åŒã³åºãã®ãªãŒããŒãããã¯éåžžã®Pythonãšå€ãããããŒã¡ãŒã¡é ãã
- cdef -> 颿°åŒã³åºãã®ãªãŒããŒããããå°ãªãããã ããPythonåŽããåŒã³åºãããCythonç°å¢ã§ã®ã¿ãã䜿ããªããPython飿ºããã«ã¯äžåãã3ã€ã®äžã§ã¯äžçªéãïŒ
- cpdef -> Cythonç°å¢ã®æã«ã¯Cythonçšã®éããã®ãPythonç°å¢ããåŒã³åºããéã«ã¯é ããã©Python飿ºãã§ãã圢ãšãªãã
ç¹ã«é¢æ°åŒã³åºãåæ°ã¯å€ããªããªããã®ã§ããã°defãå€ãåŒã³åºããŠäžã€PythonããåŒã³åºããªããã®ã¯cdefãäž¡æ¹ã§äœ¿ãã€ã€äžã€Cythonç°å¢ã§ããªãã¹ãæ©ããŸãŸäœ¿ãããå Žåã¯cpdefãšãã£ãæãã§ããããã
ã©ã®ã¿ã¡ãPythonäžããåŒã³åºãå Žåã«ã¯ãªãŒããŒãããã圱é¿ããŠããã®ã§ãPythonããèšå€§ãªåæ°åŒã³åºãã®ã¯äžåããªãšããããããŸãã
åŒæ°ãšè¿åŽå€
åºæ¬ã¯Pythonãšäžç·ã§ãããåãæå®ãããšãããç°ãªããŸãã
åŒæ°ã§ããã°ãint aãšãã£ããããªèšè¿°ãè¿åŽå€ã§ããã°é¢æ°åã®åã«èšè¿°ãã圢åŒã®ããã§ãã
%%cython
cpdef int sample_func_cython(int a):
a += 1
return a
ãªããPythonåŽããåŒã³åºãå Žåã«ã¯ãè¿åŽå€ã«åãæå®ããŠãããã©ãŒãã³ã¹åäžã«è²¢ç®ããªãå°è±¡ããããŸãã
ãŸããdefã§å®çŸ©ããå Žåãããããè¿åŽå€ã®åã®æå®ãããŠãããšãšã©ãŒã«ãªããŸãã
%%cython
def int sample_func_cython(int a):
a += 1
return a
/tmp/.cache/ipython/cython/_cython_magic_05fbbf12e127a0f1a676e1014a1f2a9d.pyx:2:8: Expected '(', found 'sample_func_cython'. Did you use cdef syntax in a Python declaration? Use decorators and Python type annotations instead.
Cythonã®ã¯ã©ã¹
ã¯ã©ã¹ã®æ¹ã¯ãcdefãšæžããŠãæ®éã«Pythonããã¢ã¯ã»ã¹ãã§ããŸãã
ãã ãã屿§ã®å Žåã¯publicãšæå®ããªããšãPythonåŽããã¢ã¯ã»ã¹ã¯ã§ããŸããã
ä»ã®ã__init__ãselfãªã©ã¯Pythonãšåãã§ãã
%%cython
cdef class Fruit:
cdef public int fruit_id
cdef public int price
def __init__(self, int fruit_id, int price):
self.fruit_id = fruit_id
self.price = price
apple = Fruit(1, 100)
apple.fruit_id
1
apple.price
100
ãªããCythonã®é¢æ°ãPythonããåŒã³åºãå ŽåãããŒã¯ãŒãåŒæ°ãåãä»ããŠãããªãããã§ãã
%%cython
cpdef int sample_func_cython(int a):
a += 1
return a
sample_func_cython(a=100)
TypeError: sample_func_cython() takes no keyword arguments
äžæ¹ã§ãã¯ã©ã¹ã®æ¹ã®ã³ã³ã¹ãã©ã¯ã¿ãªã©ã¯ãããŒã¯ãŒãåŒæ°ãåãä»ããŠãããããã§ãã
apple = Fruit(fruit_id=1, price=100)
ã¯ã©ã¹å ã®é¢æ°ã¯publicã®èšè¿°ã¯äžèŠãªãã®ã®ãPythonããåç §ããéã«ã¯defãããã¯cpdefãããªããšåç §ã§ããŸããã
%%cython
cdef class Fruit:
cdef int fruit_id
def __init__(self, int fruit_id):
self.fruit_id = fruit_id
def get_fruit_id(self):
return self.fruit_id
apple = Fruit(fruit_id=1)
apple.get_fruit_id()
1
Cythonã§ã®é å
cdef åå 倿°å[è¡æ°][åæ°] ãšãã圢åŒã§ãé åãå®çŸ©ã§ããŸãããã¯ãã«ã§ãã£ããããããã¯ãã£ãšãµã€ãºã®å€§ãããã³ãœã«ãªã©ã®å Žåã¯æ¬åŒ§ã®æ°ã墿žãããŠãã ãããïŒ[10]ãšã[10][10][10]ãšãã£ãããã«ïŒ
10è¡5åã®æŽæ°ã®é åãäœæããäŸ :
%%cython
cdef int arr[10][5]
print(arr)
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
æŽæ°ãåç §ã¯æ®éã«ã€ã³ããã¯ã¹ã§è¡ããŸããã
%%cython
cdef int arr[10][5]
arr[2][3] = 10
print(arr[2][3])
10
ãã ããPythonã®æèŠã§ãã¡ã³ã·ãŒã€ã³ããã¯ã¹ãã¹ã©ã€ã¹ãªã©ã¯ã§ããŸãããåå¥ã«ã€ã³ããã¯ã¹ã«ã¢ã¯ã»ã¹ããå¿ èŠããããŸãã
Cythonã§é ãèšè¿°ãããŠããªãã調ã¹ã
äŸãã°ãåãèšè¿°ããŠããªããšãã§é ããªãèŠå ã®åæãªã©ããããã£ãããšã調ã¹ããå Žåã¯cythonã®ããžãã¯ã³ãã³ãã§åŒæ°ã«-aãæå®ãããšã詳现ã衚瀺ããŠãããŸãã
%%cython -a
cdef int func_1(int c):
return c * 2
def func_2(d):
return d * 2
cdef a = 0
cdef int b = 0
cdef int i
for i in range(100000000):
a += 1
b += 2
以äžã®ãããªã¢ãŠãããããããŒãäžã«è¡šç€ºãããŸãã
çœãéšåã®è¡ã¯æå¥ç¡ãã«éããé»è²ãè¡ã®åæã¯åŠçãå€ãé
ãåæã§ãã
æ¿ãé»è²ã«ãªãã»ã©é
ããªããŸãã
ããšãã°ãå宣èšãããŠããªããšããcdefã§ã¯ãªãdefã§å®çŸ©ããŠãããšãããªã©ã該åœããŸãã
åè¡ãã¯ãªãã¯ãããšãCythonäžã§å¿ èŠãªåŠçã衚瀺ã§ããŸãã
çœãè¡ãã¯ãªãã¯ãããšãå°ãªãè¡æ°ã®å 容ã衚瀺ãããå¿ èŠãªåŠçãå°ãªããŠæžãã§ããããšãåãããŸãã
éã«é»è²ãåæãã¯ãªãã¯ãããšãè²ã ãªåŠçãåºãŠããŠãå¿ èŠãªåŠçãå€ãè² è·ã®é«ãããšãåãããŸãã
ãã£ãããšãã¥ãŒãã³ã°ãããå Žåã«ã¯ãããã£ãæãã§ç¢ºèªããŠã¿ãŠãé»è²ããªã£ãŠããåæã§çŽããããªåæãããã°ä¿®æ£ãããšéããªããŸãã
Numba
Cythonåæ§ãé«éåã§ããèŠãããNumbaã
Cythonãäºåã«å
éšã§ã³ã³ãã€ã«çãªåŠçãè¡ãã®ã«å¯ŸããŠããã¡ãã¯JITïŒJust-In-TimeïŒãšåŒã°ããæ¹åŒã§ã颿°åŒã³åºããªã©ã§å¿
èŠã«ãªã£ããšãã«æºåããããé«éåãªã©ããããŸãã
Numbaã®ç°å¢èšå®
åºæ¬çã«ã¯Anacondaãªã©ã§ãã®ãŸãŸäœ¿ããã®ã§ãAnacondaãªã©ã§ãã®ãŸãŸæ±ãã®ãã·ã³ãã«ã§ãããããããŸããã
pipã§ããŒãžã§ã³ãå€ãããããå Žåãä»ã®äŸåãããã®ãšã®å
Œãåãã§ãšã©ãŒã«æ©ãŸããããããã®ã§ãpipåäœã§ã€ã³ã¹ããŒã«ãããããå ŽåãããããããŒã¡ãŒã¡æéãããããããããŸããã
ïŒã¢ããããŒããªã©ããå Žåã¯pipã§ã¯ãªãcondaçµç±ãªã©ã»ã»ãç¡é£ãªã®ã§ããããïŒïŒ
Cythonã®æãšç°ãªãããã¡ãã¯Anacondaã ãå ¥ããŠããã°ãWindowsäžã§ãä»ã«å¯Ÿå¿ããªããŠã䜿ããŠããŸãã
ãŸããNumbaèªäœãããŒãžã§ã³ã¢ããã§çµæ§å€§ããå€ãã£ããããŠããããã§ãããŒãžã§ã³ã«ãã£ãŠãããããããã®èšäºã®ããã«åããªãå ŽåããããããããŸããããäºæ¿ãã ããã
æ¬èšäºã§ã¯ä»¥äžã®ããŒãžã§ã³ã§é²ããŸãã
import numba
numba.__version__
'0.41.0'
åºæ¬çãªäœ¿ãæ¹ã¯ãšãŠãã·ã³ãã«ã§ã颿°ã«jitã®ãã³ã¬ãŒã¿ãŒãä»ããã ãã§ãã
import numba as nb
@nb.jit
def sample_func(x, N):
for i in range(N):
x += 1
return x
5000äžåã®ã«ãŒããåããŠã¿ãŸãã
%%timeit
sample_func(x=100, N=50000000)
210 ns ± 2.64 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
ããç§ã®åäœã倧忩ãã§ãã
ãã³ã¬ãŒã¿ãŒã®æå®ç¡ãã®çã®Pythonã§è©ŠããŠã¿ããšå·®ãæŽç¶ã§ãã
ãã³ã¬ãŒã¿ãŒç¡ãã®å
ã®é¢æ°ã¯ã颿°ã«è¿œå ãããpy_func颿°ã§åç
§ãã§ããŸãã
ãã¡ãã¡å¥éå®çŸ©ããªããŠãæžãã®ã§ãé床æ¯èŒãªã©ã®éã«äŸ¿å©ã§ãã
%%timeit
sample_func.py_func(x=100, N=50000000)
2.08 s ± 11.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
2.08ç§ã倧åé ãã
Numbaã§é ãåæããªãã調ã¹ã
Cythonåæ§ãNumbaã§ã颿°å
ã§é
ããªãèŠå ã®åæãç¡ãã調ã¹ãæ©èœãæäŸãããŠããŸãã
ãŸããCythonã§å¶çŽãããã®ãšåæ§ããã¡ãã§ãNumbaç¹æã®å¶éããããŸãã
åºæ¬çã«Numbaèªäœãæ°å€èšç®ãé«éåããç®çã§äœãããŠããã®ã§ãæ°å€èšç®ä»¥å€ã¯éããªããªãã±ãŒã¹ãå€ãã§ããæååã®é£çµãªã©ã®åºæ¬çãªæäœãªã©ã§ããé«éåã®å¯Ÿè±¡å€ãšãªããŸããïŒå°æ¥ã®ããŒãžã§ã³ã§ã¯å€ãã£ãŠããããïŒ
ãã³ã¬ãŒã¿ãŒãä»ãã颿°ã®inspect_types颿°ã§è©³çްã調ã¹ãããšãã§ããŸãã
詊ãã«ãNumbaã§é«éåãå¹ããªãæååãæå®ããéã®æåã調ã¹ãŠã¿ãŸãã
ãªããJITã®æ§è³ªäžãå®éã«é¢æ°ãåŒã³åºããªããšã³ã³ãã€ã«ããããªãã®ã§ã1床åŒã³åºããŠããinspect_typesãå®è¡ããŸãã
@nb.jit
def sample_func(x, text):
for i in range(300000):
x += 1
for i in range(30000):
text += 'a'
return x, text
_, _ = sample_func(x=100, text='apple')
sample_func.inspect_types()
sample_func (int64, unicode_type)
--------------------------------------------------------------------------------
# File: <ipython-input-5-4908c684f6c2>
# --- LINE 1 ---
# label 0
@nb.jit
# --- LINE 2 ---
def sample_func(x, text):
# --- LINE 3 ---
# x = arg(0, name=x) :: pyobject
# text = arg(1, name=text) :: pyobject
# jump 2
# label 2
# $36 = const(LiftedLoop, LiftedLoop(<function sample_func at 0x00000221A20420D0>)) :: XXX Lifted Loop XXX
# $37 = call $36(x, func=$36, args=[Var(x, <ipython-input-5-4908c684f6c2> (3))], kws=(), vararg=None) :: XXX Lifted Loop XXX
# del $36
# x = static_getitem(value=$37, index=0, index_var=None) :: pyobject
# del $37
# jump 26
for i in range(300000):
# --- LINE 4 ---
# label 26
...
ãªã«ããé·ãããã¹ããåºåãããŸããã
ããèŠãŠã¿ããšãã»ã«ã®ã³ãŒããåè§£ããã€ã€ããããã«:: pyobjectãšãã£ã説æãä»äžãããŠããŸãã
ãã®pyobjectãšãã£ãèšè¿°ã«ãªã£ãŠããåæããã³ã³ãã€ã«åŸã®åã瀺ããŸãã
pyobjectãšãªã£ãŠããå ŽåãjitåŽã§ããŸãããšã³ã³ãã€ã«ãã§ãããPythonã®ãªããžã§ã¯ããšããŠæ±ã£ãŠããïŒïŒé
ããŸãŸïŒããšã瀺ããŠããŸãã
éã«ãint64ãªã©ã®ä»ã®åã«ãªã£ãŠããã°ãã€ãã£ãã¢ãŒããšåŒã°ããç¶æ
ã«ã³ã³ãã€ã«ãããŠãããéåžžã«é«éã«åŠçããããŸãã
ã€ãŸã颿°å ã§pyobjectãååšããªãç¶æ ã«ãã¹ãã§ãããããpyobjectãååšããå Žåãéããªããªãã©ãããNumbaã®ãªãŒããŒãããã§éã«é ããªã£ããããŸãã
詊ãã«ãæååé¢ä¿ãå«ãŸãªã圢ã«ããŠãæ°å€èšç®ã®ã¿ãæ±ã颿°ã«ããŠã¿ãŠå 容ã確èªããŠã¿ãŸãããã
@nb.jit
def sample_func(x):
for i in range(300000):
x += 1
return x
_ = sample_func(x=100)
sample_func.inspect_types()
sample_func (int64,)
--------------------------------------------------------------------------------
# File: <ipython-input-8-fefc9b602652>
# --- LINE 1 ---
# label 0
@nb.jit
# --- LINE 2 ---
def sample_func(x):
# --- LINE 3 ---
# x = arg(0, name=x) :: int64
# jump 2
# label 2
# $2.1 = global(range: <class 'range'>) :: Function(<class 'range'>)
# $const2.2 = const(int, 300000) :: Literal[int](300000)
# $2.3 = call $2.1($const2.2, func=$2.1, args=[Var($const2.2, <ipython-input-8-fefc9b602652> (3))], kws=(), vararg=None) :: (int64,) -> range_state_int64
# del $const2.2
# del $2.1
# $2.4 = getiter(value=$2.3) :: range_iter_int64
...
ä»åºŠã¯ãpyobjectã®èšè¿°ãæ¶ããint64ãªã©ã®åã®èšèŒãšãªããŸããããã®ç¶æ ã§ããã°éåžžã«é«éã«é¢æ°ãå®è¡ãããŸãã
ãã£ãããpyobjectãå«ãŸããŠããç¶æ ã§äœ¿ã£ãŠããŸã£ãããé²ãããã«ããã³ã¬ãŒã¿ãŒã®åŒæ°ã§nopython=Trueãšæå®ãããšãpyobjectã蚱容ããªããªããŸããããå«ãŸããå Žåã«ã¯ãšã©ãŒã§åŒŸãããŸãã
æååãæäœããåŠçã§åŒŸãããäŸ :
@nb.jit(nopython=True)
def sample_func(text):
for i in range(100):
text += 'a'
return text
sample_func(text='apple')
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Invalid use of Function(<built-in function iadd>) with argument(s) of type(s): (unicode_type, Literal[str](a))
Known signatures:
* (int64, int64) -> int64
* (int64, uint64) -> int64
* (uint64, int64) -> int64
* (uint64, uint64) -> uint64
* (float32, float32) -> float32
* (float64, float64) -> float64
* (complex64, complex64) -> complex64
* (complex128, complex128) -> complex128
* parameterized
...
This is not usually a problem with Numba itself but instead often caused by
the use of unsupported features or an issue in resolving types.
To see Python/NumPy features supported by the latest release of Numba visit:
http://numba.pydata.org/numba-doc/dev/reference/pysupported.html
and
http://numba.pydata.org/numba-doc/dev/reference/numpysupported.html
ãã®åŠçã¯å¯Ÿå¿ããŠããªããããµããŒãããŠãããã€ã¯ãããèŠãŠãããšãã芪åãªãšã©ãŒãåºãŸãã
ããçšåºŠè§Šã£ãŠã¿ãææãšããŠã¯ãå¶éã¯çµæ§è²ã ãããæ°å€èšç®ã§éšåçã«äœ¿ã£ããã»ã»ãšãã£ãå ·åãçŸå®çãªãšããã§ããããã
PyPy
ã©ã€ãã©ãªé¢ä¿ã®PyPIãªã©ãšååã䌌ãŠããŸããå¥ç©ã§ãã
ãã¡ããNumbaãšåæ§ãJITæ¹åŒã§ãã
ãã ããç¹åŸŽçãªç¹ãšããŠãCythonãNumbaãªã©ãšæ¯ã¹ãéã«ããããžãã¯ã³ãã³ãããã³ã¬ãŒã¿ãŒãªã©ãèšè¿°ããªããŠãåæã«é«éåããããšããç¹ãç°ãªããŸãã
æ¯ååå¥ã«ããžãã¯ã³ãã³ããªã©ãæžããªããŠæžã¿ãŸããããã¡ãã¡çްãããã¥ãŒãã³ã°ããããšãã£ãè² æ
ãæžããŸãã
ãŸããPythonã®ãã«ãã€ã³ã¢ãžã¥ãŒã«ããµãŒãããŒãã£ãŒã®ã©ã€ãã©ãªãªã©ãé«éåã§ãããšããã¯åæã«é«éåãããã®ã§ããã³ã¬ãŒã¿ãŒãªã©ãä»ããã®ãé£ããåæãªã©ã§ãé«éåã®å¯Ÿå¿ãã§ããŸãã
ããã ãèããšãªãã ãåããã«èŠããŸãããäžæ¹ã§CythonãNumbaãšæ¯ã¹ããšããPythonç°å¢èªäœãæ¢åã®ãã®ãšã¯å¥ã«ãªããã®ã§ãCythonãªã©ã§ãéšåçã«é«éåãããã¿ãããªæ°è»œãªå°å ¥ãã§ããŸããã
äŸãã°ããã§ã«ãªãªãŒã¹ãããŠããDjangoã¢ããªãªã©ã§ã¯ãå€ãã®ã³ãŒããååšãããããžã§ã¯ããªã©ã§ã¯ããæ°è»œã«PyPyã«ç§»è¡ãããããšã¯åºæ¥ãªããããªå°è±¡ã¯ãããŸãã
ãããžã§ã¯ãã®æåããPyPyåæã§çµããããããã¯ãã€ã¯ããµãŒãã¹çã«åãåããŠéšåçã«åæ ãããããããã¯æéããããŠå¯Ÿå¿ããããå¿
èŠã«ãªããããªå°è±¡ããããŸãã
ãã¿ãŸããããä»äºã§è§Šã£ãŠããDjangoã®ãã®ãªã©ã¯ãPyPyç§»è¡ãªã©ã¯å·¥æ°ãšãªãœãŒã¹çã«çŸå®çã§ã¯ãªãã®ã§è©ŠããŠããŸããã
Djangoé¢ä¿ã®ãã®ãæéšå ãããå
¬éããŠããã£ããã£ãã®ã§ããã¡ããåŒçšããçšåºŠã§çããŠãããŸãã
æ€èšŒããã£ãããã£ãäºããããããªãæéãããã£ãã
...
çµæçã«ã¯ CPU 䜿çšçã¯ååã«ãªãæ§èœã¯åã«ãªã£ãããã¡ãããæ¬çªã§ãã ã
ããããåŸã ã« CPython ç°å¢ã PyPy ç°å¢ãžãšçœ®ãæããŠãããPyPy ã®æå€§ã®é åã¯ãã®æ§èœã ãããæ§èœã倧ããäžãããããæ¢åç°å¢ã«ããã£ãŠãããµãŒãè²»çšãåæžããããšãåºæ¥ãã
ãã ãæ³šæããŠæ¬²ããã®ã¯ PyPy ã¯ãšãŠã€ããªãã¡ã¢ãªãŒãæ¶è²»ããã
PyPy ãæ¬çªã«å°å ¥ãã
Jupyterã§ããã°ãããŒãããšã«åãåããããç°å¢ãå¥ã®ãã®ã䜿ã£ãããšããã®ãçŸå®çã§æ°è»œã«è©Šããããªæ°é ã¯ãããŸããæ®å¿µãªããWindowsçã«é¢ããŠã¯ãŸã 䜿ããã¬ãã«ã§ã¯ãªããããªã®ãšãColaboratoryãªã©ã®ã¯ã©ãŠãã«ãŒãã«ã§äœ¿ã£ãããã§ããªãç¹ãèªå® ã®PCãå£ããŠæ°ããããéœåããŸã Ubuntuãªã©ãå ¥ããŠããªããããæéãããããããªã®ã§ä»åã¯æ¬èšäºã§ã¯æ€èšŒãªã©ã¯ã¹ãããããŸããïŒå°æ¥ãæ©äŒãããã°å¥ã®èšäºã§è©ŠããŠã¿ãŸããïŒ
PyPy3.5ã®Windowsçã«é¢ããŠã¯ãããã¯ã·ã§ã³ãŠãŒã¹ã®ã¬ãã«ã«ã¯éããŠããªããšèããããŠãããå©çšããå Žåã¯æ³šæãå¿ èŠã
PyPy 7.0.0ç»å Žã3系統åæãªãªãŒã¹
åè
- Advanced Python Programming: Build high performance, concurrent, and multi-threaded apps with Python using proven design patterns
- PyPy ãæ¬çªã«å°å ¥ãã
ä»ã«ãPythonãªã©ãäžå¿ã«è²ã
èšäºãæžããŠããŸãããã¡ããã©ããïŒ
ä»ãŸã§ã«æçš¿ããäž»ãªèšäºãã¡




