Reputation: 1117
I haven't used numpy much and am struggling to figure out the vectorized implementation of the following:
Change
and pct_change
are numpy
arrays which are 5*2000
in size.
I wanted to calculate each element in the array Change_after_calculation
like:
###Carry out this calculation for each number
###in Change_after_calculation where Change has a correspondingly -ve number
Change_after_calculation = (numpy.ones((5,2000)) + pct_change) * Change
###If Change has a correspondingly +ve number do the below
Change_after_calculation = Change
I could do the above with multiple for loops like this, but if there is a vectorized way to do it, I'd prefer to do that:
for p in 2000:
for n in 5:
if Change[n,p] < 0:
Change_after_calculation[n,p] = (1+pct_change[n,p]) * Change[n,p]
else:
Change_after_calculation[n,p] = Change[n,p]
Upvotes: 2
Views: 316
Reputation: 120
Your code is not very reproducible (it doesn't run, so I constructed my own snippet based on what you wrote).
If I understood correctly, you just need to create a mask based on your condition (change[n,p] < 0) and do an assignment for the arrays based on this mask.
# defining arrays for testing
P, N = 2000, 5
change = np.random.randint(-1, high=2, size=(N,P))
change_after_calculation1 = np.zeros((N,P))
change_after_calculation2 = np.zeros((N,P))
pct_change = np.random.random((N,P))
# your code
for p in range(P):
for n in range(N):
if change[n,p] < 0:
change_after_calculation1[n,p] = (1+pct_change[n,p]) * change[n,p]
else:
change_after_calculation1[n,p] = change[n,p]
# vectorized version
mask = change < 0
change_after_calculation2[mask] = (1 + pct_change[mask]) * change[mask]
change_after_calculation2[~mask] = change[~mask]
# test that arrays match
print(np.allclose(change_after_calculation1, change_after_calculation2))
Upvotes: 0
Reputation: 19332
Try this oneliner without any need for defining another array from the start to hold the result -
(Change>=0)*Change + (Change<0)*(pct_change+1)*Change
On a toy example -
Change = np.random.randint(-2,4,size=(2,5))
pct_change = np.random.randint(1,3,size=(2,5))
Change_after_calculation = np.zeros_like(pct_change)
for p in range(5):
for n in range(2):
if Change[n,p] < 0:
Change_after_calculation[n,p] = (1+pct_change[n,p]) * Change[n,p]
else:
Change_after_calculation[n,p] = Change[n,p]
#OUTPUT -
array([[ 0, -1, 0, 3, 3],
[ 2, -1, 3, 2, -2]])
#using one-liner
Change_after_calculation = (Change>=0)*Change + (Change<0)*(pct_change+1)*Change
#OUTPUT -
array([[ 0, -2, 0, 3, 3],
[ 2, -3, 3, 2, -4]])
Upvotes: 3
Reputation: 2343
You can use NumPy's fancy indexing for this
# calculate a mask array for fancy indexing
less_than = Change < 0
# Do conditional math
Change_after_calculation[less_than] = (1 + pct_change[less_than]) * Change[less_than]
Change_after_calculation[~less_than] = Change[~less_than]
If Change_after_calculation
isn't initialized beforehand you can initialize it as
Change_after_calculation = np.empty_like(Change)
Upvotes: 5