方法1:與boolean indexing
矢量化的方法 -
# Calculate the reciprocal of prior as a numpy array
prior_reci = 1/np.asarray(prior)
# Mask of ones (1s) in array, m
mask = m==1
# Use the mask for m==1 and otherwise with proper scales: prior_reci
# and 0.1*prior_reci respectively and sum them up along the rows
out = (mask*prior_reci + ~mask*(0.1*prior_reci)).sum(1)
採樣運行 -
In [58]: m
Out[58]:
array([[1, 0, 1, 1],
[0, 0, 0, 0],
[1, 1, 1, 1],
[0, 0, 0, 0],
[0, 1, 0, 0]])
In [59]: prior
Out[59]: [0.1, 0.2, 0.3, 0.4]
In [60]: prior_reci = 1/np.asarray(prior)
...: mask = m==1
...:
In [61]: (mask*prior_reci + ~mask*(0.1*prior_reci)).sum(1)
Out[61]: array([ 16.33333333, 2.08333333, 20.83333333, 2.08333333, 6.58333333])
方法2:使用matrix-multiplication with np.dot
-
# Calculate the reciprocal of prior as a numpy array
prior_reci = 1/np.asarray(prior)
# Sum along rows for m==1 with scaling of prior_reci per row
# would be equivalent to np.dot(m,prior_reci).
# Similarly for m!=1, it would be np.dot(1-m,0.1*prior_reci)
# i.e. with the new scaling 0.1*prior_reci.
# Finally we need to combine them up with summation.
out = np.dot(m,prior_reci) + np.dot(1-m,0.1*prior_reci)
採樣運行 -
In [77]: m
Out[77]:
array([[1, 0, 1, 1],
[0, 0, 0, 0],
[1, 1, 1, 1],
[0, 0, 0, 0],
[0, 1, 0, 0]])
In [78]: prior
Out[78]: [0.1, 0.2, 0.3, 0.4]
In [79]: prior_reci = 1/np.asarray(prior)
In [80]: np.dot(m,prior_reci) + np.dot(1-m,0.1*prior_reci)
Out[80]: array([ 16.33333333, 2.08333333, 20.83333333, 2.08333333, 6.58333333])
運行測試早前上市的兩種方法比較 -
In [102]: # Parameters
...: H = 1000
...: W = 1000
...:
...: # Create inputs
...: m = np.random.randint(0,2,(H,W))
...: prior = np.random.rand(W).tolist()
...:
In [103]: %%timeit
...: prior_reci1 = 1/np.asarray(prior)
...: mask = m==1
...: out1 = (mask*prior_reci1 + ~mask*(0.1*prior_reci1)).sum(1)
...:
100 loops, best of 3: 11.1 ms per loop
In [104]: %%timeit
...: prior_reci2 = 1/np.asarray(prior)
...: out2 = np.dot(m,prior_reci2) + np.dot(1-m,0.1*prior_reci2)
...:
100 loops, best of 3: 6 ms per loop
通用的解決方案處理多個條件檢查可能解決了vec torized方式與np.einsum
-
# Define scalars that are to be matched against input 2D array, m
matches = [0,1,2,3,4] # Edit this to accomodate more matching conditions
# Define multiplying factors for the reciprocal version of prior
prior_multfactors = [0.1,1,0.2,0.3,0.4] # Edit this corresponding to matches
# for different multiplying factors
# Thus, for the given matches and prior_multfactors, it means:
# when m==0, then do: 0.1/prior
# when m==1, then do: 1/prior
# when m==2, then do: 0.2/prior
# when m==3, then do: 0.3/prior
# when m==4, then do: 0.4/prior
# Define prior list
prior = [0.1,0.2,0.3,0.4]
# Calculate the reciprocal of prior as a numpy array
prior_reci = 1/np.asarray(prior)
# Mask for every element of m satisfying or not
# all the matches to produce a 3D array mask
mask = m==np.asarray(matches)[:,None,None]
# Get scaling factors for each matches across each prior_reci value
scales = np.asarray(prior_multfactors)[:,None]*prior_reci
# Einsum-mation to give sum across rows corresponding to all matches
out = np.einsum('ijk,ik->j',mask,scales)
採樣運行 -
In [203]: m
Out[203]:
array([[1, 0, 1, 1],
[0, 0, 0, 0],
[4, 2, 3, 1],
[0, 0, 0, 0],
[0, 4, 2, 0]])
In [204]: matches, prior_multfactors
Out[204]: ([0, 1, 2, 3, 4], [0.1, 1, 0.2, 0.3, 0.4])
In [205]: prior
Out[205]: [0.1, 0.2, 0.3, 0.4]
In [206]: prior_reci = 1/np.asarray(prior)
...: mask = m==np.asarray(matches)[:,None,None]
...: scales = np.asarray(prior_multfactors)[:,None]*prior_reci
...:
In [207]: np.einsum('ijk,ik->j',mask,scales)
Out[207]: array([ 16.33333333, 2.08333333, 8.5 , 2.08333333, 3.91666667])
除非它會更好,如果一個是有點更明確在'where(m == 1,1./prior,0.1/prior)' – gabhijit
那麼...一個人也可以做'm.astype(np.bool)'但最終都給出了相同的... – plonser
謝謝,非常好。當我有三個不同的整數(0,1,2),並且想爲這些情況添加0.2/p時,您有簡單的numpy解決方案嗎? – spore234