I like to stress the value of @hpaulj comment to my question:
Does b_dict
have to be a dict? If you had an array, eg. ref = np.array([0, 10,20,30])
you quickly select the values by index,
ref[a]
. I would try to avoid dict when working with numpy.
I found that using NumPy's indexing will lead to a few to several orders of magnitude faster in performance than when trying to work with a python dict
.
Building on @Ehsan's solution, below is a script that makes such a comparison.
import numpy as np
from operator import itemgetter
import timeit
import matplotlib.pyplot as plt
#@kmundnic solution
def m1(a):
def get_b(x):
b = { 1:10., 2:20., 3:30. }
#b = dict( zip( np.arange(1,101),np.arange(10,1001,10) ) )
return b[x]
return np.fromiter(map(get_b, a),dtype=np.float)
#@bigbounty solution
def m2(a):
b = { 1:10., 2:20., 3:30. }
#b = dict( zip( np.arange(1,101),np.arange(10,1001,10) ) )
return np.vectorize(b.get)(a)
#@Ehsan solution
def m3(a):
b = { 1:10., 2:20., 3:30. }
#b = dict( zip( np.arange(1,101),np.arange(10,1001,10) ) )
return np.array(itemgetter(*a)(b))
#@Sun Bear solution
def m4(a):
def get_b( a ):
b = { 1:10., 2:20., 3:30. }
#b = dict( zip( np.arange(1,101),np.arange(10,1001,10) ) )
return b[ a ]
return np.array( [get_b(i) for i in a] )
#@hpaulj solution
def m5(a):
b = np.array([10, 20, 30])
#b = np.arange(10,1001,10)
return b[a]
sizes=[10,100,1000,10000]
pm1 = []
pm2 = []
pm3 = []
pm4 = []
pm5 = []
for size in sizes:
a = np.full( size, 2 )
pm1.append( timeit.timeit( 'm1(a)', number=1000, globals=globals() ) )
pm2.append( timeit.timeit( 'm2(a)', number=1000, globals=globals() ) )
pm3.append( timeit.timeit( 'm3(a)', number=1000, globals=globals() ) )
pm4.append( timeit.timeit( 'm4(a)', number=1000, globals=globals() ) )
pm5.append( timeit.timeit( 'm5(a)', number=1000, globals=globals() ) )
print( 'm1 slower than m5 by :',np.array(pm1) / np.array(pm5) )
print( 'm2 slower than m5 by :',np.array(pm2) / np.array(pm5) )
print( 'm3 slower than m5 by :',np.array(pm3) / np.array(pm5) )
print( 'm4 slower than m5 by :',np.array(pm4) / np.array(pm5) )
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot( sizes, pm1, label='m1' )
ax.plot( sizes, pm2, label='m2' )
ax.plot( sizes, pm3, label='m3' )
ax.plot( sizes, pm4, label='m4' )
ax.plot( sizes, pm5, label='m5' )
ax.grid( which='both' )
ax.set_xscale('log')
ax.set_yscale('log')
ax.legend()
ax.get_xaxis().set_label_text( label='len(a)', fontweight='bold' )
ax.get_yaxis().set_label_text( label='Runtime (sec)', fontweight='bold' )
plt.show()
Results:
len(b) = 3:
m1 slower than m5 by : [ 4.22462367 29.79407905 85.03454097 339.2915358 ]
m2 slower than m5 by : [ 8.64220685 11.57175871 13.76761749 46.1940683 ]
m3 slower than m5 by : [ 3.25785432 21.63131578 54.71305704 220.15777696 ]
m4 slower than m5 by : [ 4.60710166 30.93616607 91.8936744 371.00398273 ]
len(b) = 100:
m1 slower than m5 by : [ 218.98603678 1976.50128737 9697.76615006 17742.79151719 ]
m2 slower than m5 by : [ 41.76535891 53.85600913 109.35129345 164.13075291 ]
m3 slower than m5 by : [ 24.82715462 36.77830986 87.56253196 141.04493237 ]
m4 slower than m5 by : [ 222.04184193 2001.72120836 9775.22464369 18431.00155305 ]

b_dict
have to be adict
? If you had an array, eg.ref = np.array([0, 10,20,30])
you quickly select the values by index,ref[a]
. I would try to avoiddict
when working withnumpy
.dict
. I have experimented on your comment and reported my findings below.