Numpy selecting specific columns from each row - python

I have matrix A of shape (p, q, r, r) and another matrix I of shape (r, s). I want to select only s of the r elements from the last dimension of A, so that the shape of the new matrix becomes (p, q, r, s).
To simplify (ignoring the first two dimensions), let
>>> A
array([[5, 2, 5, 7],
[2, 6, 4, 3],
[4, 2, 3, 9],
[6, 2, 4, 3]])
>>> I
array([[1, 2],
[2, 2],
[3, 1],
[2, 1]])
I want the matrix
array([[2, 5],
[4, 4],
[9, 2],
[4, 2]])
How can I do it? A[..., I] gives a (4, 4, 2) matrix, selecting elements located at I from each row. I can solve the problem by
>>> c = np.arange(4)
>>> A[..., I][c, c, :]
array([[2, 5],
[4, 4],
[9, 2],
[4, 2]])
But I think it requires a lot of computation. Is there any more efficient way to solve this issue?
Edit:
For higher dimensional example, consider I to be same as before, and
A
array([[[[12, 15, 6, 12],
[16, 16, 4, 17],
[ 6, 19, 10, 9],
[ 5, 11, 18, 17]],
[[13, 12, 5, 6],
[12, 7, 5, 4],
[ 9, 19, 12, 4],
[15, 4, 16, 7]],
[[13, 6, 5, 17],
[ 8, 4, 10, 9],
[ 3, 13, 16, 4],
[ 3, 3, 4, 4]]],
[[[ 8, 3, 8, 18],
[ 7, 11, 8, 7],
[10, 8, 14, 9],
[ 8, 12, 16, 5]],
[[ 9, 10, 10, 7],
[11, 6, 10, 6],
[16, 19, 10, 14],
[ 9, 13, 13, 19]],
[[10, 8, 19, 12],
[ 9, 10, 17, 19],
[ 4, 11, 12, 14],
[ 8, 5, 16, 10]]]])
Expected output:
array([[[[15, 6],
[ 4, 4],
[ 9, 19],
[18, 11]],
[[12, 5],
[ 5, 5],
[ 4, 19],
[16, 4]],
[[ 6, 5],
[10, 10],
[ 4, 13],
[ 4, 3]]],
[[[ 3, 8],
[ 8, 8],
[ 9, 8],
[16, 12]],
[[10, 10],
[10, 10],
[14, 19],
[13, 13]],
[[ 8, 19],
[17, 17],
[14, 11],
[16, 5]]]]
A[...,I][..., c, c, :] yield this result

Since you're using integer array indexing, you'll need to specify which rows you want to select those columns from:
A[np.arange(A.shape[0])[:,None], I]
array([[2, 5],
[4, 4],
[9, 2],
[4, 2]])
Or you also have np.take_along_axis:
np.take_along_axis(A, I, 1)
For a larger array of shape (p, q, r, r), take full slices along the front axes, and use broadcasting in a similar way:
A[...,np.arange(A.shape[2])[:,None],I]
array([[[[15, 6],
[ 4, 4],
[ 9, 19],
[18, 11]],
[[12, 5],
[ 5, 5],
[ 4, 19],
[16, 4]],
...

Related

How to reorder the matrix [duplicate]

This question already has answers here:
What is the best way to perform an anti-transpose in python?
(4 answers)
Closed 4 months ago.
Does anyone could tell me how to reorder the matrix:
[[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15]]
To:
[[15, 10, 5],
[14, 9, 4],
[13, 8, 3],
[12, 7, 2],
[11, 6, 1]]
Since you have tagged the question numpy, I surmise that those are numpy matrix, and you are looking for a numpy solution (otherwise, if those are lists, Ann's zip is the correct solution).
For numpy you can
M[::-1,::-1].T
Example
M=np.array([[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15]])
M[::-1,::-1].T
returns
array([[15, 10, 5],
[14, 9, 4],
[13, 8, 3],
[12, 7, 2],
[11, 6, 1]])
as expected
I'd suggest using numpy, like so:
import numpy as np
matrix = np.array([[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15]])
transformed_matrix = matrix[::-1].T[::-1]
# array([[15, 10, 5],
# [14, 9, 4],
# [13, 8, 3],
# [12, 7, 2],
# [11, 6, 1]])
matrix[::-1] gives you the original matrix in reverse order (i.e. [11, 12, 13...] first and [1, 2, 3...] last).
Taking the transpose of that with .T rotates the matrix about - swapping rows and columns.
Lastly, indexing the transpose with [::-1] reverses the order, putting [15, 14, 13...] first and [5, 4, 3...] last.
Here is how you can use the zip() method to transpose your matrix:
m = [[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15]]
print([list(i)[::-1] for i in zip(*m)][::-1])
Output:
[[15, 10, 5],
[14, 9, 4],
[13, 8, 3],
[12, 7, 2],
[11, 6, 1]]
The index [::-1] reverses the array.

How to make a 2d numpy array from an empty numpy array by adding 1d numpy arrays?

So I'm trying to start an empty numpy array with a = np.array([]), but when i append other numpy arrays (like [1, 2, 3, 4, 5, 6, 7, 8] and [9, 10, 11, 12, 13, 14, 15, 16] to this array, then the result im basically getting is
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16].
But what i want as result is: [[1, 2, 3, 4, 5, 6, 7, 8], [9, 10, 11, 12, 13, 14, 15, 16]]
IIUC you want to keep adding lists to your np.array. In that case, you can use something like np.vstack to "append" the new lists to the array.
a = np.array([[1, 2, 3],[4, 5, 6]])
np.vstack([a, [7, 8, 9]])
>>> array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
You can also use np.c_[], especially if a and b are already 1D arrays (but it also works with lists):
a = [1, 2, 3, 4, 5, 6, 7, 8]
b = [9, 10, 11, 12, 13, 14, 15, 16]
>>> np.c_[a, b]
array([[ 1, 9],
[ 2, 10],
[ 3, 11],
[ 4, 12],
[ 5, 13],
[ 6, 14],
[ 7, 15],
[ 8, 16]])
It also works "multiple times":
>>> np.c_[np.c_[a, b], a, b]
array([[ 1, 9, 1, 9],
[ 2, 10, 2, 10],
[ 3, 11, 3, 11],
[ 4, 12, 4, 12],
[ 5, 13, 5, 13],
[ 6, 14, 6, 14],
[ 7, 15, 7, 15],
[ 8, 16, 8, 16]])

Conditional merging of sublists in a list

I have the following list of lists.
If last sublist has len>1:
x = [[0], [1, 2, 3], [4, 5], [6], [7, 8, 9], [10, 11, 12, 13], [15], [16, 17, 18]]
expected_output = [[0, 1, 2, 3], [4, 5], [6, 7, 8, 9], [10, 11, 12, 13], [15, 16, 17, 18]]
If last sublist has len==1:
x = [[0], [1, 2, 3], [4, 5], [6], [7, 8, 9], [10, 11, 12, 13], [15], [16, 17, 18], [19]]
expected_output = [[0, 1, 2, 3], [4, 5], [6, 7, 8, 9], [10, 11, 12, 13], [15, 16, 17, 18], [19]]
I'm trying to merge the sublists of length 1 with the next sublist.
If the last sublist length is one, I want to leave it as is.
I tried writing the following code.
xt = []
for i in range(len(x)-1):
if len(x[i]) == 1:
xt.append(x[i]+x[i+1])
# del x[i+1]
if len(x[i])>1:
xt.append(x[i])
print(xt)
Try this :
def ref1(l):
con = 0
l2 = []
while con<len(l)-1:
if len(l[con])==1:
l2.append(l[con]+l[con+1])
con +=2
else:
l2.append(l[con])
con+=1
if len(l[-1])==1:
l2.append(l[-1])
print(l2)
ref1([[0], [1, 2, 3], [4, 5], [6], [7, 8, 9], [10, 11, 12, 13], [15], [16, 17, 18]])
# OUTPUT : [[0, 1, 2, 3], [4, 5], [6, 7, 8, 9], [10, 11, 12, 13], [15, 16, 17, 18]]
ref1([[0], [1, 2, 3], [4, 5], [6], [7, 8, 9], [10, 11, 12, 13], [15], [16, 17, 18], [19]])
# OUTPUT : [[0, 1, 2, 3], [4, 5], [6, 7, 8, 9], [10, 11, 12, 13], [15, 16, 17, 18], [19]]
Code Analysis
xt = []
for i in range(len(x)-1):
if len(x[i]) == 1:
xt.append(x[i]+x[i+1])
This means you are adding the next sublist before visiting it
# del x[i+1]
if len(x[i])>1:
xt.append(x[i])
and this doesn't have a history of if the sublist has already been merged.
print(xt)
Advice
Visit the list the other way around, and check each time if the previous list is of length 1.
OR
Keep tab of if the previous action was a merge.
TO OP
If you need more help, please shout

python display remaining values after dividing the matrix

i = [1,2,3,4,5,6,7,8,9,10]
def ndiv(l,n):
return [l[s:e] for s, e in zip(range(0,len(l)+1,n),xrange(n,len(l)+1,n))]
for i in xrange(1,15,1):
print "CLUSTER {}".format((ndiv(l,i)))
#print
CLUSTER [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17]]
CLUSTER [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16]]
CLUSTER [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]]
CLUSTER [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
CLUSTER [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]
CLUSTER [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]]
CLUSTER [[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14]]
CLUSTER [[1, 2, 3, 4, 5, 6, 7, 8], [9, 10, 11, 12, 13, 14, 15, 16]]
CLUSTER [[1, 2, 3, 4, 5, 6, 7, 8, 9]]
Coding up to now. After dividing, the remaining values are not shown omitted.But I want to have the prices shown after we split them(EX.if divide '3' ->before [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]] / after [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15],[16],[17] ).How can I divide and then show the remaining numbers one by one?
You can compute 2 lists, one that splits contains batches of n and the other that maps remaining elements into one element list and finally merge them together
>>> l = list(xrange(1,18))
>>> def ndiv(l,n):
... return [l[i:i+n] for i in xrange(0,len(l)//n*n, n)] + [[e] for e in l[len(l)//n*n:]]
...
>>> ndiv(l, 5)
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16], [17]]

Numpy index, get bands of width 2

I am wondering if there is a way it index/slice a numpy array, such that one can get every other band of 2 elements. In other words, given:
test = np.array([[1,2,3,4,5,6,7,8],[9,10,11,12,13,14,15,16]])
I would like to get the array:
[[1, 2, 5, 6],
[9, 10, 13, 14]]
Thoughts on how this can be accomplished with slicing/indexing?
Not that difficult with a few smart reshapes :)
test.reshape((4, 4))[:, :2].reshape((2, 4))
Given:
>>> test
array([[ 1, 2, 3, 4, 5, 6, 7, 8],
[ 9, 10, 11, 12, 13, 14, 15, 16]])
You can do:
>>> test.reshape(-1,2)[::2].reshape(-1,4)
array([[ 1, 2, 5, 6],
[ 9, 10, 13, 14]])
Which works even for different shapes of initial arrays:
>>> test2
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
>>> test2.reshape(-1,2)[::2].reshape(-1,4)
array([[ 1, 2, 5, 6],
[ 9, 10, 13, 14]])
>>> test3
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16]])
>>> test3.reshape(-1,2)[::2].reshape(-1,4)
array([[ 1, 2, 5, 6],
[ 9, 10, 13, 14]])
How it works:
1. Reshape into two columns by however many rows:
>>> test.reshape(-1,2)
array([[ 1, 2],
[ 3, 4],
[ 5, 6],
[ 7, 8],
[ 9, 10],
[11, 12],
[13, 14],
[15, 16]])
2. Stride the array by stepping every second element
>>> test.reshape(-1,2)[::2]
array([[ 1, 2],
[ 5, 6],
[ 9, 10],
[13, 14]])
3. Set the shape you want of 4 columns, however many rows:
>>> test.reshape(-1,2)[::2].reshape(-1,4)
array([[ 1, 2, 5, 6],
[ 9, 10, 13, 14]])

Categories