Related
I have two index array like these:
import numpy as np
p_index = np.array([2, 0, 0, 2, 0, 2, 1, 2, 1])
m_index = np.array([0, 1, 1, 2, 1, 1, 2, 0, 0])
two object array like these:
p = np.array([17, 13, 16])
m = np.array([15, 14, 19])
and a matrix like this:
t=np.array([18, 16, 14, 12, 11, 19, 11, 16, 11])
I need to do a for-loop like this:
for i in range(len(t)):
newvalue = max(p[p_index[i]],m[m_index[i]])+t[i]
p[p_index[i]] = newvalue
m[m_index[i]] = newvalue
I take array as example,but p,m,t,and the index array are all Matrix with same rows actually.I need to do this to every row.How can I do it without for-loop?
NEW↓:
If I take Matrice as example it will like these:
p_index = np.array([[2, 0, 0, 2, 0, 2, 1, 2, 1],
[0, 2, 0, 1, 1, 1, 1, 2, 2],
[1, 2, 0, 2, 1, 1, 0, 0, 2],
[0, 2, 1, 1, 1, 1, 0, 1, 1]])
m_index = np.array([[0, 1, 1, 2, 1, 1, 2, 0, 0],
[2, 2, 2, 2, 1, 0, 1, 1, 2],
[2, 2, 2, 0, 1, 0, 2, 2, 2],
[1, 0, 0, 1, 0, 2, 1, 2, 1]])
t=np.array([[18, 16, 14, 12, 11, 19, 11, 16, 11],
[10, 14, 18, 17, 14, 15, 18, 19, 17],
[18, 17, 18, 18, 10, 12, 17, 15, 14],
[15, 15, 16, 15, 19, 12, 13, 19, 17]])
p = np.array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
m = np.array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
row,col = np.shape(t)
for i in range(row):
for j in range(col):
newvalue = max(p[i][p_index[i][j]],m[i][m_index[i][j]])+t[i][j]
p[i][p_index[i][j]] = newvalue
m[i][m_index[i][j]] = newvalue
f = np.max(p,axis=1).reshape(len(p),1)
And actually I just need the final 'f'
If we iterate without actually modifying p and m:
In [247]: for i in range(len(t)):
...: print(max(p[p_index[i]],m[m_index[i]])+t[i])
...:
34
33
31
31
28
35
30
32
26
We can get the same values with a single numpy expression:
In [250]: np.maximum(p[p_index], m[m_index])+t
Out[250]: array([34, 33, 31, 31, 28, 35, 30, 32, 26])
But with your full loop, p and m elements are modified several times, each depending on a previous iteration:
In [258]: for i in range(len(t)):
...: newvalue = max(p[p_index[i]],m[m_index[i]])+t[i]
...: print(newvalue)
...: p[p_index[i]] = newvalue
...: m[m_index[i]] = newvalue
...:
34
33
47 # versus 31
46
58 # versus 28
77
57
93
104
In [259]: p,m
Out[259]: (array([ 58, 104, 93]), array([104, 77, 57]))
There are some numpy tools for performing things like cumulative sums, and working with duplicate indices, but you can't (readily) apply these to general functions such as your max(...)+t.
I am trying to pad two dimensions of an N-dimensional matrix with different paddings and override the values. Consider the Following example:
def determineShifts(layer):
u = range(0, 2*layer + 1)
b = range(0, 2*layer + 1)
shifts = []
mat = np.zeros((2 * layer + 1, 2 * layer + 1), dtype=object)
for x, i in enumerate(u):
for y, j in enumerate(b):
up = (j, 2*layer - j)
left = (i, 2*layer - i)
mat[x, y] = (left, up)
return mat
layer = 1
b = np.ones((3,3,3,3))
shifts = determineShifts(layer)
I want to pad the second last and final dimension of the array b such that the resulting shape is (3,3,5,5) and override the element of that matrix and repeat the process for all nodes, which in this case is (3,3). I would prefer to override the values (currently I receive a broadcasting error) rather than making a copy of the desired shape and iterating through the first and second dimension. A sample is included below:
c = np.ones((3,3,5,5))
for i in range(np.shape(c)[0]):
for j in range(np.shape(c)[1]):
c[i,j] = np.pad(b[i,j], shifts[i,j])
Is there some way to apply a function to the matrix to apply all the shifts to each of the elements (3,3, 3, 3) -> (3, 3, 5, 5) such that the code is computationally efficient?
np.pad() accepts different padding values for each axis, but not different ones within each axis, as per your example.
One general approach is to do a bit of arithmetic for the relocation of elements and then use fancy indexing. In your case, it looks like you are trying to stagger the 2D blocks of the last two dimensions in such a way that they move by 1: vertically for axis 0 and horizontally for axis 1.
You can do the same with the following arithmetic:
def stagger_ix(s):
r = np.arange(np.prod(s))
block = r // np.prod(s[-2:])
shift_i, shift_j = block // s[1], block % s[1]
i, j = r // s[-1] % s[-2], r % s[-1]
newshape = np.array(s)
newshape[-2:] += newshape[:2] - 1
ix = (
block * np.prod(newshape[-2:])
+ (i + shift_i) * newshape[-1]
+ (j + shift_j)
)
return newshape, ix
def stagger(b):
newshape, ix = stagger_ix(b.shape)
# now insert b in a zero(newshape), as per shift logic
c = np.zeros(np.prod(newshape), dtype=b.dtype)
c[ix] = b.ravel()
c = c.reshape(newshape)
return c
Your c array can be obtained as:
c = stagger(np.ones((3,3,3,3)))
Other examples -
# for example matrices
def rp1(s):
return (np.arange(np.prod(s)) + 1).reshape(s)
>>> stagger(rp1((2,2,2,2)))
array([[[[ 1, 2, 0],
[ 3, 4, 0],
[ 0, 0, 0]],
[[ 0, 5, 6],
[ 0, 7, 8],
[ 0, 0, 0]]],
[[[ 0, 0, 0],
[ 9, 10, 0],
[11, 12, 0]],
[[ 0, 0, 0],
[ 0, 13, 14],
[ 0, 15, 16]]]])
>>> stagger(rp1((2,3,2,5)))
array([[[[ 1, 2, 3, 4, 5, 0, 0],
[ 6, 7, 8, 9, 10, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0]],
[[ 0, 11, 12, 13, 14, 15, 0],
[ 0, 16, 17, 18, 19, 20, 0],
[ 0, 0, 0, 0, 0, 0, 0]],
[[ 0, 0, 21, 22, 23, 24, 25],
[ 0, 0, 26, 27, 28, 29, 30],
[ 0, 0, 0, 0, 0, 0, 0]]],
[[[ 0, 0, 0, 0, 0, 0, 0],
[31, 32, 33, 34, 35, 0, 0],
[36, 37, 38, 39, 40, 0, 0]],
[[ 0, 0, 0, 0, 0, 0, 0],
[ 0, 41, 42, 43, 44, 45, 0],
[ 0, 46, 47, 48, 49, 50, 0]],
[[ 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 51, 52, 53, 54, 55],
[ 0, 0, 56, 57, 58, 59, 60]]]])
This question already has answers here:
using an numpy array as indices of the 2nd dim of another array? [duplicate]
(2 answers)
Closed 3 years ago.
I have a matrix and would like to get the last non-negative element. I happen to already have these indices in an array b
a= [[3, 4, 1, 0, 0, 0, 0, 0, 0],
[6, 0, 0, 0, 0, 0, 0, 0, 0],
[24,5, 6, 7, 7, 78, 0, 0, 0],
[4, 56, 0, 0, 0, 0, 0, 0, 0],
[23, 5, 7, 11, 12, 52, 65, 54, 0]]
b = [2, 0, 5, 1, 7]
Is there an elegant way to extra the last non-zero elements?
c = [1, 6, 78, 56, 54] from a?
A loop works, but is not very pythonic.
You can use list comprehensions and enumerate built-in function:
[a[i][j] for i, j in enumerate(b)]
[1, 6, 78, 56, 54]
Something more pythonic might be:
a= [[3, 4, 1, 0, 0, 0, 0, 0, 0],
[6, 0, 0, 0, 0, 0, 0, 0, 0],
[24,5, 6, 7, 7, 78, 0, 0, 0],
[4, 56, 0, 0, 0, 0, 0, 0, 0],
[23, 5, 7, 11, 12, 52, 65, 54, 0]]
c = [next(a_element for a_element in sublist[::-1] if a_element>0) for sublist in a ]
However, this will raise a StopIteration exception if no a_element is >0
Another possibility I found:
a[range(len(b)), b]
Similar to the (better) answer by #vurmux, you can also zip:
res = [sub[i] for i, sub in zip(b, a)]
print(res) # -> [1, 6, 78, 56, 54]
How to use one array filter out another array with non-zero value?
from numpy import array
a = array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
b = array([[0, 0, 1, 0, 0],
[0, 0, 2, 0, 0],
[0, 0, 3, 0, 0],
[0, 0, 4, 0, 0],
[0, 0, 5, 0, 0]])
Expected result:
array([[ 0, 0, 2, 0, 0],
[ 0, 0, 7, 0, 0],
[ 0, 0, 12, 0, 0],
[ 0, 0, 17, 0, 0],
[ 0, 0, 22, 0, 0]])
Thank you
The easiest way if you want a new array would be np.where with 3 arguments:
>>> import numpy as np
>>> np.where(b, a, 0)
array([[ 0, 0, 2, 0, 0],
[ 0, 0, 7, 0, 0],
[ 0, 0, 12, 0, 0],
[ 0, 0, 17, 0, 0],
[ 0, 0, 22, 0, 0]])
If you want to change a in-place you could instead use boolean indexing based on b:
>>> a[b == 0] = 0
>>> a
array([[ 0, 0, 2, 0, 0],
[ 0, 0, 7, 0, 0],
[ 0, 0, 12, 0, 0],
[ 0, 0, 17, 0, 0],
[ 0, 0, 22, 0, 0]])
One line solution:
a * (b != 0)
I'd like to know how to make a simple data cube (matrix) with three 1D arrays or if there's a simpler way. I want to be able to call a specific value at the end from the cube such as cube[0,2,6].
x = arange(10)
y = arange(10,20,1)
z = arange(20,30,1)
cube = meshgrid(x,y,z)
But this doesn't give the desired result, as it gives mulitple arrays and can't call a specific number easily. I'd like to be able to use this for large data sets that would be laborious to do by hand, later on. Thanks
meshgrid as its name suggests creates an orthogonal mesh. If you call it with 3 arguments it will be a 3d mesh. Now the mesh is 3d arrangement of points but each point has 3 coordinates. Therefore meshgrid returns 3 arrays one for each coordinate.
The standard way of getting one 3d array out of that is to apply a vectorised function with three arguments. Here is a simple example:
>>> x = arange(7)
>>> y = arange(0,30,10)
>>> z = arange(0,200,100)
>>> ym, zm, xm = meshgrid(y, z, x)
>>> xm
array([[[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6]],
[[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6]]])
>>> ym
array([[[ 0, 0, 0, 0, 0, 0, 0],
[10, 10, 10, 10, 10, 10, 10],
[20, 20, 20, 20, 20, 20, 20]],
[[ 0, 0, 0, 0, 0, 0, 0],
[10, 10, 10, 10, 10, 10, 10],
[20, 20, 20, 20, 20, 20, 20]]])
>>> zm
array([[[ 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0]],
[[100, 100, 100, 100, 100, 100, 100],
[100, 100, 100, 100, 100, 100, 100],
[100, 100, 100, 100, 100, 100, 100]]])
>>> cube = xm + ym + zm
>>> cube
array([[[ 0, 1, 2, 3, 4, 5, 6],
[ 10, 11, 12, 13, 14, 15, 16],
[ 20, 21, 22, 23, 24, 25, 26]],
[[100, 101, 102, 103, 104, 105, 106],
[110, 111, 112, 113, 114, 115, 116],
[120, 121, 122, 123, 124, 125, 126]]])
>>> cube[0, 2, 6]
26