I have a matrix mat like below;
mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
and a list s = [1, 2, 5].
I have to subtract along axis=1. I did as follow and it works..
mat - s = array([[ 0, 0, -2],
[ 3, 3, 1],
[ 6, 6, 4]])
However, if I subtract along axis=0;
ie,
mat - s[:,None]
I get errors.
TypeError: list indices must be integers or slices, not tuple
Here's a little hack:
s = np.array([1,2,5])
(mat.T - s).T
Output:
array([[0, 1, 2],
[2, 3, 4],
[2, 3, 4]])
Edit: .T does not change anything if s is 1d so you can remove it.
You were on the right track with the use of [:,None], but your definition of s was wrong.
In [128]: mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
In [129]: s = [1, 2, 5]
In [130]: mat - s
Out[130]:
array([[ 0, 0, -2],
[ 3, 3, 1],
[ 6, 6, 4]])
In this subtraction, s has automatically been 'promoted' to numpy array.
The [..,...] indexing does not work with a list:
In [131]: s[:,None]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-131-bafcfb7b67c1> in <module>
----> 1 s[:,None]
TypeError: list indices must be integers or slices, not tuple
The tuple in this error is the comma expression: s[:, None] is the same as s[(:,None)]. The python parser passes a tuple to the s.__getitem__ method. numpy arrays handle tuples (multidimensonal indexing), lists don't.
If we start with an array, then we can apply the reshape, and perform the desired subtraction:
In [132]: sa = np.array(s)
In [133]: sa
Out[133]: array([1, 2, 5])
In [134]: sa[:,None]
Out[134]:
array([[1],
[2],
[5]])
In [135]: mat - sa[:,None]
Out[135]:
array([[0, 1, 2],
[2, 3, 4],
[2, 3, 4]])
sa is 1d, so transpose doesn't change anything:
In [136]: sa.T
Out[136]: array([1, 2, 5])
Related
I have a 2D numpy array that I want to extract a submatrix from.
I get the submatrix by slicing the array as below.
Here I want a 3*3 submatrix around an item at the index of (2,3).
>>> import numpy as np
>>> a = np.array([[0, 1, 2, 3],
... [4, 5, 6, 7],
... [8, 9, 0, 1],
... [2, 3, 4, 5]])
>>> a[1:4, 2:5]
array([[6, 7],
[0, 1],
[4, 5]])
But what I want is that for indexes that are out of range, it goes back to the beginning of array and continues from there. This is the result I want:
array([[6, 7, 4],
[0, 1, 8],
[4, 5, 2]])
I know that I can do things like getting mod of the index to the width of the array; but I'm looking for a numpy function that does that.
And also for an one dimensional array this will cause an index out of range error, which is not really useful...
This is one way using np.pad with wraparound mode.
>>> a = np.array([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 0, 1],
[2, 3, 4, 5]])
>>> pad_width = 1
>>> i, j = 2, 3
>>> startrow, endrow = i-1+pad_width, i+2+pad_width # for 3 x 3 submatrix
>>> startcol, endcol = j-1+pad_width, j+2+pad_width
>>> np.pad(a, (pad_width, pad_width), 'wrap')[startrow:endrow, startcol:endcol]
array([[6, 7, 4],
[0, 1, 8],
[4, 5, 2]])
Depending on the shape of your patch (eg. 5 x 5 instead of 3 x 3) you can increase the pad_width and start and end row and column indices accordingly.
np.take does have a mode parameter which can wrap-around out of bound indices. But it's a bit hacky to use np.take for multidimensional arrays since the axis must be a scalar.
However, In your particular case you could do this:
a = np.array([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 0, 1],
[2, 3, 4, 5]])
np.take(a, np.r_[2:5], axis=1, mode='wrap')[1:4]
Output:
array([[6, 7, 4],
[0, 1, 8],
[4, 5, 2]])
EDIT
This function might be what you are looking for (?)
def select3x3(a, idx):
x,y = idx
return np.take(np.take(a, np.r_[x-1:x+2], axis=0, mode='wrap'), np.r_[y-1:y+2], axis=1, mode='wrap')
But in retrospect, i recommend using modulo and fancy indexing for this kind of operation (it's basically what the mode='wrap' is doing internally anyways):
def select3x3(a, idx):
x,y = idx
return a[np.r_[x-1:x+2][:,None] % a.shape[0], np.r_[y-1:y+2][None,:] % a.shape[1]]
The above solution is also generalized for any 2d shape on a.
I have 2 numpy arrays:
a = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
b = np.array([2, 1, 2])
I want to use b as starting indices into the columns of a and set all the values of a from those column indexes onwards to 0 like this:
np.array([[1, 2, 3],
[4, 0, 6],
[0, 0, 0]])
i.e., set elements of column 1 from position 2 onwards to 0, set elements of column 2 from position 1 onwards to 0, and set elements of column 3 from position 2 onwards to 0.
When I try this:
a[:, b:] = 0
I get
TypeError: only integer scalar arrays can be converted to a scalar index
Is there a way to slice using an array of indices without a for loop?
Edit: updated the example to show the indices can be arbitrary
You can use boolean array indexing. First, create a mask of indices you want to set to 0 and then apply the mask to array and assign the replacement value (e.g., 0 in your case).
mask = b>np.arange(a.shape[1])[:,None]
a[~mask]=0
output:
array([[1, 2, 3],
[4, 0, 6],
[0, 0, 0]])
I think the issue is in a[:,b:]; here b: means little if b is not a scaler e.g. 5: means 6th onwards but [1,2,3]: means nothing when array is 2d.
It should be a[:,b]. Setting a[:,b] = 0 will set all columns specified in b to 0. Following is the run.
In [2]: import numpy as np
In [3]: a = np.array([[1, 2, 3],
...: [4, 5, 6],
...: [7, 8, 9]])
...:
...: b = np.array([2, 1, 2])
...:
In [4]: a
Out[4]:
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
In [5]: b
Out[5]: array([2, 1, 2])
In [6]: b.dtype
Out[6]: dtype('int64')
In [7]: a[:, b:] = 0
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-6e5050513225> in <module>
----> 1 a[:, b:] = 0
TypeError: only integer scalar arrays can be converted to a scalar index
In [8]: a[:, b] = 0
In [9]: a
Out[9]:
array([[1, 0, 0],
[4, 0, 0],
[7, 0, 0]])
But that's not what you want.
To get what you want, you need to specify rows indices and column indices e.g. (1,1), (2,0), (2,1), (2,2).
In [11]: a[[1,2,2,2], [1, 0, 1,2]] = 0
In [12]: a
Out[12]:
array([[1, 2, 3],
[4, 0, 6],
[0, 0, 0]])
I have split a numpy array like so:
x = np.random.randn(10,3)
x_split = np.split(x,5)
which splits x equally into five numpy arrays each with shape (2,3) and puts them in a list. What is the best way to combine a subset of these back together (e.g. x_split[:k] and x_split[k+1:]) so that the resulting shape is similar to the original x i.e. (something,3)?
I found that for k > 0 this is possible with you do:
np.vstack((np.vstack(x_split[:k]),np.vstack(x_split[k+1:])))
but this does not work when k = 0 as x_split[:0] = [] so there must be a better and cleaner way. The error message I get when k = 0 is:
ValueError: need at least one array to concatenate
The comment by Paul Panzer is right on target, but since NumPy now gently discourages vstack, here is the concatenate version:
x = np.random.randn(10, 3)
x_split = np.split(x, 5, axis=0)
k = 0
np.concatenate(x_split[:k] + x_split[k+1:], axis=0)
Note the explicit axis argument passed both times (it has to be the same); this makes it easy to adapt the code to work for other axes if needed. E.g.,
x_split = np.split(x, 3, axis=1)
k = 0
np.concatenate(x_split[:k] + x_split[k+1:], axis=1)
np.r_ can turn several slices into a list of indices.
In [20]: np.r_[0:3, 4:5]
Out[20]: array([0, 1, 2, 4])
In [21]: np.vstack([xsp[i] for i in _])
Out[21]:
array([[9, 7, 5],
[6, 4, 3],
[9, 8, 0],
[1, 2, 2],
[3, 3, 0],
[8, 1, 4],
[2, 2, 5],
[4, 4, 5]])
In [22]: np.r_[0:0, 1:5]
Out[22]: array([1, 2, 3, 4])
In [23]: np.vstack([xsp[i] for i in _])
Out[23]:
array([[9, 8, 0],
[1, 2, 2],
[3, 3, 0],
[8, 1, 4],
[3, 2, 0],
[0, 3, 8],
[2, 2, 5],
[4, 4, 5]])
Internally np.r_ has a lot of ifs and loops to handle the slices and their boundaries, but it hides it all from us.
If the xsp (your x_split) was an array, we could do xsp[np.r_[...]], but since it is a list we have to iterate. Well we could also hide that iteration with an operator.itemgetter object.
In [26]: operator.itemgetter(*Out[22])
Out[26]: operator.itemgetter(1, 2, 3, 4)
In [27]: np.vstack(operator.itemgetter(*Out[22])(xsp))
I have a np.array with dtype as object. Each element here is a np.array with dtype as float and shape as (2,2) --- in maths, it is a 2-by-2 matrix. My aim is to obtain one 2-dimenional matrix by converting all the object-type element into float-type element. This can be better presented by the following example.
dA = 2 # dA is the dimension of the following A, here use 2 as example only
A = np.empty((dA,dA), dtype=object) # A is a np.array with dtype as object
A[0,0] = np.array([[1,1],[1,1]]) # each element in A is a 2-by-2 matrix
A[0,1] = A[0,0]*2
A[1,0] = A[0,0]*3
A[1,1] = A[0,0]*4
My aim is to have one matrix B (the dimension of B is 2*dA-by-2*dA). The form of B in maths should be
B =
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
If dA is fixed at 2, then things can be easier, because I can hard-code
a00 = A[0,0]
a01 = A[0,1]
a10 = A[1,0]
a11 = A[1,1]
B0 = np.hstack((a00,a01))
B1 = np.hstack((a10,a11))
B = np.vstack((B0,B1))
But in reality, dA is a variable, it can be 2 or any other integer. Then I don't know how to do it. I think nested for loops can help but maybe you have brilliant ideas. It would be great if there is something like cell2mat function in MATLAB. Because here you can see A[i,j] as a cell in MATLAB.
Thanks in advance.
Here's a quick way.
Your A:
In [137]: A
Out[137]:
array([[array([[1, 1],
[1, 1]]), array([[2, 2],
[2, 2]])],
[array([[3, 3],
[3, 3]]), array([[4, 4],
[4, 4]])]], dtype=object)
Use numpy.bmat, but convert A to a python list first, so bmat does what we want:
In [138]: B = np.bmat(A.tolist())
In [139]: B
Out[139]:
matrix([[1, 1, 2, 2],
[1, 1, 2, 2],
[3, 3, 4, 4],
[3, 3, 4, 4]])
The result is actually a numpy.matrix. If you need a regular numpy array, use the .A attribute of the matrix object:
In [140]: B = np.bmat(A.tolist()).A
In [141]: B
Out[141]:
array([[1, 1, 2, 2],
[1, 1, 2, 2],
[3, 3, 4, 4],
[3, 3, 4, 4]])
Here's an alternative. (It still uses A.tolist().)
In [164]: np.swapaxes(A.tolist(), 1, 2).reshape(4, 4)
Out[164]:
array([[1, 1, 2, 2],
[1, 1, 2, 2],
[3, 3, 4, 4],
[3, 3, 4, 4]])
In the general case, you would need something like:
In [165]: np.swapaxes(A.tolist(), 1, 2).reshape(A.shape[0]*dA, A.shape[1]*dA)
Out[165]:
array([[1, 1, 2, 2],
[1, 1, 2, 2],
[3, 3, 4, 4],
[3, 3, 4, 4]])
Your vstack/hstack could be written more compactly, and generally as
In [132]: np.vstack((np.hstack(a) for a in A))
Out[132]:
array([[1, 1, 2, 2],
[1, 1, 2, 2],
[3, 3, 4, 4],
[3, 3, 4, 4]])
since for a in A iterates on the rows of A.
Warren suggests np.bmat, which is fine. But if you look at the bmat code, you'll see that it just doing this kind of nested concatenate (expressed a row loop with arr_rows.append(np.concatenate...)).
Assume we have two matrices:
x = np.random.randint(10, size=(2, 3, 3))
idx = np.random.randint(3, size=(2, 3))
The question is to access the element of x using idx, in the way as:
dim1 = x[0, range(0,3), idx[0]] # slicing x[0] using idx[0]
dim2 = x[1, range(0,3), idx[1]]
res = np.vstack((dim1, dim2))
Is there a neat way to do this?
You can just index it the basic way, only that the size of indexer array has to match. That's what those .reshape s are for:
x[np.array([0,1]).reshape(idx.shape[0], -1),
np.array([0,1,2]).reshape(-1,idx.shape[1]),
idx]
Out[29]:
array([[ 0.10786251, 0.2527514 , 0.11305823],
[ 0.67264076, 0.80958292, 0.07703623]])
Here's another way to do it with reshaping -
x.reshape(-1,x.shape[2])[np.arange(idx.size),idx.ravel()].reshape(idx.shape)
Sample run -
In [2]: x
Out[2]:
array([[[5, 0, 9],
[3, 0, 7],
[7, 1, 2]],
[[5, 3, 5],
[8, 6, 1],
[7, 0, 9]]])
In [3]: idx
Out[3]:
array([[2, 1, 2],
[1, 2, 0]])
In [4]: x.reshape(-1,x.shape[2])[np.arange(idx.size),idx.ravel()].reshape(idx.shape)
Out[4]:
array([[9, 0, 2],
[3, 1, 7]])