I'm having difficulty conceptualizing a 3 dimensional matrix, which I need for a truth table of sorts. I am trying to go through a 3D matrix, and compare each element to all other elements adjacent to it (but not on diagonals). I have a function (truth_table) which is supposed to take a set of 3D coordinates and return a matrix which tells me which surrounding coordinates are safe to call upon without fear of an INDEX_OUT_OF_BOUNDS exception. I am new to N-dimensional matrices and am having trouble making this truth table, which was easy enough in 2D.
import numpy as np
array_rows=10
array_cols=10
array_height=10
laser_power=2e-3
T_MATRIX=np.full((array_rows,array_cols,array_height),0.0)
H_MATRIX=np.full((array_rows,array_cols,array_height),0.0)
H_MATRIX[5,5,5]=laser_power
constants=0.5
def truth_table(row,col,height):
skeleton=np.array([
[[False,False,False],[False,height<array_height-1,False],[False,False,False]],[[False,row>0,False],[col>0,False,col<array_cols-1],[False,row<array_rows-1,False]],[[False,False,False],[False,height>0,False],[False,False,False]]])
def update_T():
global T_MATRIX
for row in range(array_rows):
for col in range(array_cols):
for height in range(array_height):
T_MATRIX[row][col][height]+=H_MATRIX[row][col][height]*constants
def reset_H():
global H_MATRIX
for row in range(array_rows):
for col in range(array_cols):
for height in range(array_height):
H_MATRIX[row][col][height]=0.0
H_MATRIX[5,5,5]=laser_power
def update_H():
global H_MATRIX
for row in range(array_rows):
for col in range(array_cols):
for height in range(array_height):
my_table=truth_table(row,col,height)
count=np.sum(my_table)
T_DIFF=0.0
AVG_T=0.0
for r in range(3):
for c in range(3):
for h in range(3):
if(my_table[r][c][h]):
T_DIFF+=T_MATRIX[row][col][height]-T_MATRIX[row+(r-1)][col+(c-1)][height+(h-1)]
if(count>0):
AVG_T=T_DIFF/count
H_MATRIX[row][col][height]+=T_DIFF*constants
def update_stuff():
##UPDATE THE TEMP
update_T()
reset_H()
update_H()
update_stuff()
print T_MATRIX[5][5][5]
#print constants
Because this question is likely going to be abandoned or closed, here is something that might help your thinking about this problem. It looks like you are doing things where you are interested in calculating differences/averages between a cell's values and the value's of its nearest neighbors.
On a 3D lattice, a cell's nearest neighbors are located at the following positions (centered on the cell of interest):
[[[0, 0, 0],
[0, 1, 0],
[0, 0, 0]],
[[0, 1, 0],
[1, 0, 1],
[0, 1, 0]],
[[0, 0, 0],
[0, 1, 0],
[0, 0, 0]]]
which can be constructed with numpy using
f = np.zeros((3,3,3))
f[[0,1,1,1,1,2],[1,0,1,1,2,1],[1,1,0,2,1,1]] = 1
The convolution of this nearest-neighbor filter (or kernel) with any 3D array A1 of shape (N1,N2,N3) will give you a new array A2 of shape (N1,N2,N3) where each value in A2 is the sum of the neighbors' values in A1. For example:
>>> A1 = np.arange(27).reshape(3,3,3)
>>> A1
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]]])
>>> A2 = scipy.ndimage.convolve(A1, f)
>>> A2
array([[[ 13, 18, 23],
[ 28, 33, 38],
[ 43, 48, 53]],
[[ 58, 63, 68],
[ 73, 78, 83],
[ 88, 93, 98]],
[[103, 108, 113],
[118, 123, 128],
[133, 138, 143]]])
The first entry of A2 is 13 = 1 + 3 + 9. The middle entry of A2 is 78 = 4 + 10 + 12 + 14 + 16 + 22.
You can use these convolutions to easily get some of the quantities you are looking for. It looks like H_MATRIX could be constructed simply by
H_MATRIX = constants * (T_MATRIX - convolve(T_MAXTRIX, f))
using the f defined above. Alternatively, you could define a different f that has a 1 in the center and -1 at the other 6 positions which might give you just H_MATRIX = constants * convolve(T_MATRIX, f).
Related
I want to define a 3d numpy array with shape = [3, 3, 5] and also with values as a range starting with 11 and step = 3 in column-wise manner. I mean:
B[:,:,0] = [[ 11, 20, 29],
[ 14, 23, 32],
[17, 26, 35]]
B[:,:,1] = [[ 38, ...],
[ 41, ...],
[ 44, ...]]
...
I am new to numpy and I doubt doing it with np.arange or np.mgrid maybe. but I don't how to do.
How can this be done with minimal lines of code?
You can calculate the end of the range by multiplying the shape by the step and adding the start. Then it's just reshape and transpose to move the column around:
start = 11
step = 3
shape = [5, 3, 3]
end = np.prod(shape) * step + start
B = np.arange(start, end, step).reshape([5, 3, 3]).transpose(2, 1, 0)
B[:, :, 0]
# array([[11, 20, 29],
# [14, 23, 32],
# [17, 26, 35]])
I am working with a 1800 x 900 matrix. For each cell in the matrix, I need to do a similar operation, which can be described with an example:
a1b1 a1b2 a1b3 .... a1b900
a2b1 a2b2 ..
.
a1800b1 ... ... ..a1800b900
For each cell in a new matrix, I want its value to be equivalent to, the sum of its top left, top and top right neighbor. So, I want a2b2 = a1b1 + a1b2 + a1b3. For the top row, it could be the same value as the current cell.
I can easily do this using 2 for loops, but is there I way I can vectorize this so that it speeds up the whole process?
you can vectorize it like below
arr = np.arange(16).reshape(4,4)
arr2 = np.pad(arr, [(1,0), (1,1)], mode="constant")[:-1, :]
result = arr+arr2[:,0:-2]+arr2[:,1:-1]+arr2[:,2:]
Description
np.pad(arr, [(1,0), (1,1)], mode="constant") pad zeros to left, right and top of matrix. index [:-1, :] will remove the last row effectively shifting the matrix by one row
arr2[:,0:-2], arr2[:,1:-1], arr2[:,2:] will give top left, top and top right element for each corresponding element of arr. If there is no element it gives 0 (the zeros padded in previous step)
Result
## arr
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
## result
array([[ 0, 1, 2, 3],
[ 5, 8, 12, 12],
[17, 24, 28, 24],
[29, 40, 44, 36]])
Having an array A with the shape (2,6, 60), is it possible to index it based on a binary array B of shape (6,)?
The 6 and 60 is quite arbitrary, they are simply the 2D data I wish to access.
The underlying thing I am trying to do is to calculate two variants of the 2D data (in this case, (6,60)) and then efficiently select the ones with the lowest total sum - that is where the binary (6,) array comes from.
Example: For B = [1,0,1,0,1,0] what I wish to receive is equal to stacking
A[1,0,:]
A[0,1,:]
A[1,2,:]
A[0,3,:]
A[1,4,:]
A[0,5,:]
but I would like to do it by direct indexing and not a for-loop.
I have tried A[B], A[:,B,:], A[B,:,:] A[:,:,B] with none of them providing the desired (6,60) matrix.
import numpy as np
A = np.array([[4, 4, 4, 4, 4, 4], [1, 1, 1, 1, 1, 1]])
A = np.atleast_3d(A)
A = np.tile(A, (1,1,60)
B = np.array([1, 0, 1, 0, 1, 0])
A[B]
Expected results are a (6,60) array containing the elements from A as described above, the received is either (2,6,60) or (6,6,60).
Thank you in advance,
Linus
You can generate a range of the indices you want to iterate over, in your case from 0 to 5:
count = A.shape[1]
indices = np.arange(count) # np.arange(6) for your particular case
>>> print(indices)
array([0, 1, 2, 3, 4, 5])
And then you can use that to do your advanced indexing:
result_array = A[B[indices], indices, :]
If you always use the full range from 0 to length - 1 (i.e. 0 to 5 in your case) of the second axis of A in increasing order, you can simplify that to:
result_array = A[B, indices, :]
# or the ugly result_array = A[B, np.arange(A.shape[1]), :]
Or even this if it's always 6:
result_array = A[B, np.arange(6), :]
An alternative solution using np.take_along_axis (from version 1.15 - docs)
import numpy as np
x = np.arange(2*6*6).reshape((2,6,6))
m = np.zeros(6, int)
m[0] = 1
#example: [1, 0, 0, 0, 0, 0]
np.take_along_axis(x, m[None, :, None], 0) #add dimensions to mask to match array dimensions
>>array([[[36, 37, 38, 39, 40, 41],
[ 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]]])
Suppose I have a numpy array img, with img.shape == (468,832,3). What does img[::2, ::2] do? It reduces the shape to (234,416,3) Can you please explain the logic?
Let's read documentation together (Source).
(Just read the bold part first)
The basic slice syntax is i:j:k where i is the starting index, j is the stopping index, and k is the step (k \neq 0). This selects the m elements (in the corresponding dimension) with index values i, i + k, ..., i + (m - 1) k where m = q + (r\neq0) and q and r are the quotient and remainder obtained by dividing j - i by k: j - i = q k + r, so that i + (m - 1) k < j.
...
Assume n is the number of elements in the dimension being sliced.
Then, if i is not given it defaults to 0 for k > 0 and n - 1 for k < 0
. If j is not given it defaults to n for k > 0 and -n-1 for k < 0 . If
k is not given it defaults to 1. Note that :: is the same as : and
means select all indices along this axis.
Now looking at your part.
[::2, ::2] will be translated to [0:468:2, 0:832:2] because you do not specify the first two or i and j in the documentation. (You only specify k here. Recall the i:j:k notation above.) You select elements on these axes at the step size 2 which means you select every other elements along the axes specified.
Because you did not specify for the 3rd dimension, all will be selected.
It slices every alternate row, and then every alternate column, from an array, returning an array of size (n // 2, n // 2, ...).
Here's an example of slicing with a 2D array -
>>> a = np.arange(16).reshape(4, 4)
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
>>> a[::2, ::2]
array([[ 0, 2],
[ 8, 10]])
And, here's another example with a 3D array -
>>> a = np.arange(27).reshape(3, 3, 3)
>>> 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, 25, 26]]])
>>> a[::2, ::2] # same as a[::2, ::2, :]
array([[[ 0, 1, 2],
[ 6, 7, 8]],
[[18, 19, 20],
[24, 25, 26]]])
Well, we have the RGB image as a 3D array of shape:
img.shape=(468,832,3)
Now, what does img[::2, ::2] do?
we're just downsampling the image (i.e. we're shrinking the image size by half by taking only every other pixel from the original image and we do this by using a step size of 2, which means to skip one pixel). This should be clear from the example below.
Let's take a simple grayscale image for easier understanding.
In [13]: arr
Out[13]:
array([[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55],
[60, 61, 62, 63, 64, 65]])
In [14]: arr.shape
Out[14]: (6, 6)
In [15]: arr[::2, ::2]
Out[15]:
array([[10, 12, 14],
[30, 32, 34],
[50, 52, 54]])
In [16]: arr[::2, ::2].shape
Out[16]: (3, 3)
Notice which pixels are in the sliced version. Also, observe how the array shape changes after slicing (i.e. it is reduced by half).
Now, this downsampling happens for all three channels in the image since there's no slicing happening in the third axis. Thus, you will get the shape reduced only for the first two axis in your example.
(468, 832, 3)
. . |
. . |
(234, 416, 3)
Given a numpy 2D array of points, aka 3D array with size of the 3rd dimension equals to 2, how do I get the minimum x and y coordinate over all points?
Examples:
First:
I edited my original example, since it was wrong.
data = np.array(
[[[ 0, 1],
[ 2, 3],
[ 4, 5]],
[[11, 12],
[13, 14],
[15, 16]]])
minx = 0 # data[0][0][0]
miny = 1 # data[0][0][1]
4 x 4 x 2:
Second:
array([[[ 0, 77],
[29, 12],
[28, 71],
[46, 17]],
[[45, 76],
[33, 82],
[14, 17],
[ 3, 18]],
[[99, 40],
[96, 3],
[74, 60],
[ 4, 57]],
[[67, 57],
[23, 81],
[12, 12],
[45, 98]]])
minx = 0 # data[0][0][0]
miny = 3 # data[2][1][1]
Is there an easy way to get now the minimum x and y coordinates of all points of the data? I played around with amin and different axis values, but nothing worked.
Clarification:
My array stores positions from different robots over time. First dimension is time, second is the index of an robot. The third dimension is then either x or y of a robots for a given time.
Since I want to draw their paths to pixels, I need to normalize my data, so that the points are as close as possible to the origin without getting negative. I thought that subtracting [minx,miny] from every point will do that for me.
alko's answer didn't work for me, so here's what I did:
import numpy as np
array = np.arange(15).reshape(5,3)
x,y = np.unravel_index(np.argmin(array),array.shape)
Seems you need consecutive min alongaxis. For your first example:
>>> np.min(np.min(data, axis=1), axis=0)
array([ 0, 1])
For the second:
>>> np.min(np.min(data, axis=1), axis=0)
array([0, 3])
The same expression can be stated (in numpy older than 1.7), as pointed out by #Jamie, s
>>> np.min(data, axis=(1, 0))
array([0, 3])
You should take the min of a slice of the array.
Assuming first coordinate is x and second is y
minx = min(a[:,0])
miny = min(a[:,1])
>>>a=np.array([[1,2],[3,4],[5,6]])
>>> a
array([[1, 2],
[3, 4],
[5, 6]])
>>> min(a[:,0])
1
>>> max(a[:,0])
5
>>> max(a[:,1])
6
minx = np.min(data[0])
miny = np.min(data[1])
You can use function numpy.amin to find the minima along the desired axis.