Simplify numpy expression [duplicate] - python-3.x

This question already has answers here:
Access n-th dimension in python [duplicate]
(5 answers)
Closed 2 years ago.
How can I simplify this:
import numpy as np
ex = np.arange(27).reshape(3, 3, 3)
def get_plane(axe, index):
return ex.swapaxes(axe, 0)[index] # is there a better way ?
I cannot find a numpy function to get a plane in a higher dimensional array, is there one?
EDIT
The ex.take(index, axis=axe) method is great, but it copies the array instead of giving a view, what I originally wanted.
So what is the shortest way to index (without copying) a n-th dimensional array to get a 2d slice of it, with index and axis?

Inspired by this answer, you can do something like this:
def get_plane(axe, index):
slices = [slice(None)]*len(ex.shape)
slices[axe]=index
return ex[tuple(slices)]
get_plane(1,1)
output:
array([[ 3, 4, 5],
[12, 13, 14],
[21, 22, 23]])

What do you mean by a 'plane'?
In [16]: ex = np.arange(27).reshape(3, 3, 3)
Names like plane, row, and column, are arbitrary conventions, not formally defined in numpy. The default display of this array looks like 3 'planes' or 'blocks', each with rows and columns:
In [17]: ex
Out[17]:
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, 25, 26]]])
Standard indexing lets us view any 2d block, in any dimension:
In [18]: ex[0]
Out[18]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [19]: ex[0,:,:]
Out[19]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [20]: ex[:,0,:]
Out[20]:
array([[ 0, 1, 2],
[ 9, 10, 11],
[18, 19, 20]])
In [21]: ex[:,:,0]
Out[21]:
array([[ 0, 3, 6],
[ 9, 12, 15],
[18, 21, 24]])
There are ways of saying I want block 0 in dimension 1 etc, but first make sure you understand this indexing. This is the core numpy functionality.
In [23]: np.take(ex, 0, 1)
Out[23]:
array([[ 0, 1, 2],
[ 9, 10, 11],
[18, 19, 20]])
In [24]: idx = (slice(None), 0, slice(None)) # also np.s_[:,0,:]
In [25]: ex[idx]
Out[25]:
array([[ 0, 1, 2],
[ 9, 10, 11],
[18, 19, 20]])
And yes you can swap axes (or transpose), it that suits your needs.

Related

What is the Easiest way to extract subset of a 2D matrix in python?

mat = [[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, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35]]
Lets say I want to extract upper left 2x2 matrix
[[0, 1,],
[6, 7, ]]
doing mat2=mat[:2][:2] doesnt work.
It extracts the rows correctly but not columns.Seems like I need to loop throughto get the columns.
Additionally I need to do a deepcopy to mat2 suchthat modifying mat2 dont change mat.
This is because [:2] returns a list containing the first 2 elements of your matrix.
For example :-
arr = [[1, 2], [1, 3]]
print(arr[:2]) # will print the first 2 elements of the array, that is [1, 2] and [1, 3], packed into a list. So, Output : [[1, 2], [1, 3]].
In the same way,
mat = [[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, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35]]
mat2 = mat[:2] # => [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]]
# Now, if you again try to get the first 2 elements from mat2 you will get the first 2 elements of mat2, not the first 2 elements of the lists inside mat2.
mat3 = mat2[:2] # => [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]]
That is where you went wrong, but this concept is quite counter-intuitive, so no worries.
So the solution would be to get the first 2 elements from matrix mat and then loop over its elements and then get the first 2 elements from them.
Therefore, this should work for you:
list(x[:2] for x in mat[:2])
Or, as #warped pointed, if you can use numpy, you can do the following:
import numpy as np
mat = np.array(mat)
mat[:2, :2]

creating tensor by composition of smaller tensors

I would like to create a 4x4 tensor that is composed of four smaller 2x2 tensors in this manner:
The tensor I would like to create:
in_t = torch.tensor([[14, 7, 6, 2],
[ 4, 8, 11, 1],
[ 3, 5, 9, 10],
[12, 15, 16, 13]])
I would like to create this tensor composed from these four smaller tensors:
a = torch.tensor([[14, 7], [ 4, 8]])
b = torch.tensor([[6, 2], [11, 1]])
c = torch.tensor([[3, 5], [12, 15]])
d = torch.tensor([[9, 10], [16, 13]])
I have tried to use torch.cat like this:
mm_ab = torch.cat((a,b,c,d), dim=0)
but I end up with an 8x2 tensor.
You can control the layout of your tensor and achieve the desired result with a combination of torch.transpose and torch.reshape. You can perform an outer transpose followed by an inner transpose:
>>> stack = torch.stack((a,b,c,d))
tensor([[[14, 7],
[ 4, 8]],
[[ 6, 2],
[11, 1]],
[[ 3, 5],
[12, 15]],
[[ 9, 10],
[16, 13]]])
Reshape-tranpose-reshape-transpose-reshape:
>>> stack.reshape(4,2,-1).transpose(0,1).reshape(-1,2,4).transpose(0,1).reshape(-1,4)
tensor([[14, 7, 6, 2],
[ 4, 8, 11, 1],
[ 3, 5, 9, 10],
[12, 15, 16, 13]])
Essentially, reshapes allow you to group and view your tensor differently while transpose operation will alter its layout (it won't remain contiguous) meaning you can achieve the desired output.
If you concatenate all your tensors this way below, you will get exactly your output:
tensor a
tensor b
tensor c
tensor d
You really started with a good and easy approach, this is the completion of your attempt:
p1 = torch.concat((a,b),axis=1)
p2 = torch.concat((c,d),axis=1)
p3 = torch.concat((p1,p2),axis=0)
print(p3)
#output
tensor([[14, 7, 6, 2],
[ 4, 8, 11, 1],
[ 3, 5, 9, 10],
[12, 15, 16, 13]])

Get Specific Element from a 2d List Using Condition

Here is a list.
list=[[[5, 1, 50], [7, 10, 52], 2], [[7, 10, 52], [10, 5, 163], 3], [[10, 5, 163], [13, 9, 85], 3], [[13, 9, 85], [14, 3, 176], 1], [[14, 3, 176], [15, 7, 96], 1]]
I want to retrieve an element from the list based on the minimum value which are 2,3,3,1,1 or we can say list[i][j]. From these element I want to find the minimum which is 1 and from that I want to retrieve the element [[[13, 9, 85], [14, 3, 176], 1]]. As here two 1 exist, indexwise I am choosing first one.
Can you tell me how can I do the code?
Sorry for being noob.
Just use find minimum concept with O(N)
list1=[[[5, 1, 50], [7, 10, 52], 2], [[7, 10, 52], [10, 5, 163], 3], [[10, 5, 163], [13, 9, 85], 3], [[13, 9, 85], [14, 3, 176], 1], [[14, 3, 176], [15, 7, 96], 1]]
# Assign first element as a minimum.
min1 = list1[0][2]
minIx = 0;
for i in range(len(list1)):
# If the other element is less than min element
if list1[i][2] < min1:
min1 = list1[i][2] #It will change
minIx = i
print("The smallest element in the list is ",list1[minIx])

Sampling from a 2d numpy array

I was wondering if there was a reasonably efficient way of sampling from a 2d numpy array. If I have a generic array:
dims = (4,4)
test_array = np.arange(np.prod(dims)).reshape(*dims)
test_array
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
Then I'd like to randomly set, say, two elements from it to a specific value (let's say 100). I've tried creating an indexing array and then applying that:
sample_from = np.random.randint(low=0, high=5, size=(2,2))
sample_from
array([[0, 2],
[1, 1]])
But if I try using this to index, it gives me a slightly unexpected answer:
test_array[sample_from]
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[ 4, 5, 6, 7]]])
What I would have expected (and the kind of result I'd like) is if I'd just entered the indexing array directly:
test_array[[0,2],[1,1]] = 100
test_array
giving:
array([[ 0, 100, 2, 3],
[ 4, 5, 6, 7],
[ 8, 100, 10, 11],
[ 12, 13, 14, 15]])
Any help gratefully received.
You could use np.random.choice + np.unravel_index to assign directly to your array.
test_array[
np.unravel_index(np.random.choice(np.prod(dims), 2, replace=False), dims)
] = 100

Transform a column into specific rows using numpy

I am trying to extract a column and arrange into multiple rows.
My Input: data
-2.74889,1.585,223.60
-2.74889,1.553,228.60
-2.74889,1.423,246.00
-2.74889,1.236,249.10
-2.74889,0.928,243.80
-2.74889,0.710,242.20
-2.74889,0.558,243.50
...
...
...
k = np.reshape(data[:,2], (2,10))
Output:
[[ 223.6 228.6 246. 249.1 243.8 242.2 243.5 244. 244.8
245.2 ]
[ 224.6 230. 250.7 249.3 244.4 242.1 242.8 243.8 244.7
245.1 ]]
My question is how to add square brackets for each number(for example 223.6) and remain them in 1 row?
Thanks,
Prasad.
It's not entirely clear what you mean, but perhaps it's something like this?
>>> import numpy as np
>>> data = np.arange(30).reshape(10,3)
>>> data
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, 25, 26],
[27, 28, 29]])
>>> data[:, 2, None]
array([[ 2],
[ 5],
[ 8],
[11],
[14],
[17],
[20],
[23],
[26],
[29]])
You need to expand the dimensions of the array when you reshape.
Setup
x = np.arange(60).reshape(20, 3)
reshape with an additional dimension
x[:, 2].reshape((-1, 10, 1))
expand_dims with axis=2
np.expand_dims(x[:, 2].reshape(-1, 10), axis=2)
atleast_3d
np.atleast_3d(x[:, 2].reshape(-1, 10))
All three produce:
array([[[ 2],
[ 5],
[ 8],
[11],
[14],
[17],
[20],
[23],
[26],
[29]],
[[32],
[35],
[38],
[41],
[44],
[47],
[50],
[53],
[56],
[59]]])

Resources