Pick 3D numpy array with 1D array of indices - python

Given that there is 2 Numpy Array :
3d_array with shape (100,10,2),
1d_indices with shape (100)
What is the Numpy way/equivalent to do this :
result = []
for i,j in zip(range(len(3d_array)),1d_indices):
result.append(3d_array[i,j])
Which should return result.shape (100,2)
The closest I've come to is by using fancy indexing on Numpy :
result = 3d_array[np.arange(len(3d_array)), 1d_indices]

Your code snippet should be equivalent to 3d_array[:, 1d_indices].reshape(-1,2), example:
a = np.arange(100*10*2).reshape(100,10,2) # 3d array
b = np.random.randint(0, 10, 100) # 1d indices
def fun(a,b):
result = []
for i in range(len(a)):
for j in b:
result.append(a[i,j])
return np.array(result)
assert (a[:, b].reshape(-1, 2) == fun(a, b)).all()

Related

Numpy: Iterate multiplication of 3D array by 1D array

I have a 3D array (4,3,3) in which I would like to iteratively multiply with a 1D array (t variable) and sum to end up with an array (A) that is a summation of the four 3,3 arrays
I'm unsure on how I should be assigning indexes or how and if I should be using np.ndenumerate
Thanks
import numpy as np
import math
#Enter material constants for calculation of stiffness matrix
E1 = 20
E2 = 1.2
G12 = 0.8
v12=0.25
v21=(v12/E1)*E2
theta = np.array([30,-30,-30,30])
deg = ((math.pi*theta/180))
k = len(theta) #number of layers
t = np.array([0.005,0.005,0.005,0.005])
#Calculation of Q Values
Q11 = 1
Q12 = 2
Q21 = 3
Q22 = 4
Q66 = 5
Qbar = np.zeros((len(theta),3,3),order='F')
#CALCULATING THE VALUES OF THE QBAR MATRIX
for i, x in np.ndenumerate(deg):
m= np.cos(x) #sin of rotated lamina
n= np.sin(x) #cos of rotated lamina
Qbar11=Q11*3
Qbar12=Q22*4
Qbar16=Q16*4
Qbar21 = Qbar12
Qbar22=Q22*1
Qbar26=Q66*2
Qbar66=Q12*3
Qbar[i] = np.array([[Qbar11, Qbar12, Qbar16], [Qbar21, Qbar22, Qbar26], [Qbar16, Qbar26, Qbar66]], order = 'F')
print(Qbar)
A = np.zeros((3,3))
for i in np.nditer(t):
A[i]=Qbar[i]*t[i]
A=sum(A[i])
If I understand correctly, you want to multiply Qbar and t over the first axis, and then summing the result over the first axis (which results in an array of shape (3, 3)).
I created random arrays to make the code minimal:
import numpy as np
Qbar = np.random.randint(2, size=(4, 3, 3))
t = np.arange(4)
A = (Qbar * t[:, None, None]).sum(axis=0)
t[:, None, None] will create two new dimensions so that the shape becomes (4, 1, 1), which can be multiplied to Qbar element-wise. Then we just have to sum over the first axis.
NB: A = np.tensordot(t, Qbar, axes=([0],[0])) also works and can be faster for larger dimensions, but for the dimensions you provided I prefer the first solution.

What is a rank 1 array in Numpy

Consider the following vector:
import numpy as np
u = np.random.randn(5)
print(u)
[-0.30153275 -1.48236907 -1.09808763 -0.10543421 -1.49627068]
When we print its shape:
print(u.shape)
(5,)
I was told this is neither a column vector nor a row vector. So what is essentially this shape is in numpy (m,) ?
# one-dimensional array (rank 1 array)
# array([ 0.202421 , 1.04496629, -0.28473552, 0.22865349, 0.49918827])
a = np.random.randn(5,) # or b = np.random.randn(5)
# column vector (5 x 1)
# array([[-0.52259951],
# [-0.2200037 ],
# [-1.07033914],
# [ 0.9890279 ],
# [ 0.38434068]])
c = np.random.randn(5,1)
# row vector (1 x 5)
# array([[ 0.42688689, -0.80472245, -0.86294221, 0.28738552, -0.86776229]])
d = np.random.randn(1,5)
For example (see docs):
numpy.dot(a, b)
If both a and b are 1-D arrays, it is inner product of vectors (without complex conjugation).
If both a and b are 2-D arrays, it is matrix multiplication

Taking specific 2d array from 3d in numpy

Is there a way to avoid using the for loop and get the result just by calling arr with some indexing? Potentially dim1 will be equal to 50 000, dim2 up to 1000, dim3 fixed to 3.
import numpy as np
dim1 = 10
dim2 = 2
dim3 = 3
arr = np.arange(60).reshape(dim1,dim2,dim3)
arr2 = np.arange(dim1*dim2).reshape(dim1,dim2)
np.mod(arr2,dim3,out=arr2)
res = []
rng = np.arange(dim1)
for x in range(dim2):
sl = arr2[:,x]
temp = arr[rng,x,sl]
res.append(temp)
res = np.asarray(res).T
Basically, I would like to extract the values from arr which is a 3D array, however the matrix arr2 indicates which columns to select.
Best

How can I always have numpy.ndarray.shape return a two valued tuple?

I'm trying to get the values of (nRows, nCols) from a 2D Matrix but when it's a single row (i.e. x = np.array([1, 2, 3, 4])), x.shape will return (4,) and so my statement of (nRows, nCols) = x.shape returns "ValueError: need more than 1 value to unpack"
Any suggestions on how I can make this statement more adaptable? It's for a function that is used in many programs and should work with both single row and multi-row matices. Thanks!
You could create a function that returns a tuple of rows and columns like this:
def rowsCols(a):
if len(a.shape) > 1:
rows = a.shape[0]
cols = a.shape[1]
else:
rows = a.shape[0]
cols = 0
return (rows, cols)
where a is the array you input to the function. Here's an example of using the function:
import numpy as np
x = np.array([1,2,3])
y = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])
def rowsCols(a):
if len(a.shape) > 1:
rows = a.shape[0]
cols = a.shape[1]
else:
rows = a.shape[0]
cols = 0
return (rows, cols)
(nRows, nCols) = rowsCols(x)
print('rows {} and columns {}'.format(nRows, nCols))
(nRows, nCols) = rowsCols(y)
print('rows {} and columns {}'.format(nRows, nCols))
This prints rows 3 and columns 0 then rows 4 and columns 3. Alternatively, you can use the atleast_2d function for a more concise approach:
(r, c) = np.atleast_2d(x).shape
print('rows {}, cols {}'.format(r, c))
(r, c) = np.atleast_2d(y).shape
print('rows {}, cols {}'.format(r, c))
Which prints rows 1, cols 3 and rows 4, cols 3.
If your function uses
(nRows, nCols) = x.shape
it probably also indexes or iterates on x with the assumption that it has nRows rows, e.g.
x[0,:]
for row in x:
# do something with the row
Common practice is to reshape x (as needed) so it has at least 1 row. In other words, change the shape from (n,) to (1,n).
x = np.atleast_2d(x)
does this nicely. Inside a function, such a change to x won't affect x outside it. This way you can treat x as 2d through out your function, rather than constantly looking to see whether it is 1d v 2d.
Python: How can I force 1-element NumPy arrays to be two-dimensional?
is one of many previous SO questions that asks about treating 1d arrays as 2d.

Vectorized way of accessing row specific elements in a numpy array

I have a 2-D NumPy array and a set of indices the size of which is the first dimension of the NumPy array.
X = np.random.rand(5, 3)
a = np.random.randint(0, 3, 5)
I need to do something like
for i, ind in enumerate(a):
print X[i][ind]
Is there a vectorized way of doing this?
Here you go:
X = np.random.rand(5, 3)
a = np.random.randint(0, 3, 5)
In [12]: X[np.arange(a.size), a]
Out[12]: array([ 0.99653335, 0.30275346, 0.92844957, 0.54728781, 0.43535668])
In [13]: for i, ind in enumerate(a):
print X[i][ind]
# ....:
#0.996533345844
#0.30275345582
#0.92844956619
#0.54728781105
#0.435356681672
I'm assuming here that you don't need each value on a separate line and just want to extract the values.

Categories