Suppose I have a 3D numpy array A, say given below:
A = np.array( [[[1,2,3], [4,5,6]] , [[7,8,9] , [10,11,12], [13,14,15]] ] , ndmin = 3 )
The only thing given about A is that it is a 3D arrays which is an array of arbitrary number of 2D arrays, where each 2D array is an array of arbitrary number of 1D arrays, and each 1D array has exactly 3 elements.
I want to remove the middle element from each 1D array from this 3D array, basically get the new array A1, and the removed column as X given below:
A1 = np.array( [[[1,3], [4,6]] , [[7,9] , [10,12], [13,15]] ] , ndmin = 3 )
X = np.array( [ [[2],[5]], [[8],[11],[14]] ], ndmin = 3 )
I want to write a function that given A it outputs (A1, X) and another function which given (A1, X) outputs A. I believe it should be possible to write the first function via array slicing, but I am not able to do so. Also how do I write the second function.
CodePudding user response:
For you ragged array, it is better to store in a list of np.arrays with shape n by 3:
A = [np.array([[1,2,3],
[4,5,6]]) ,
np.array([[7,8,9],
[10,11,12],
[13,14,15]])]
Now you could:
def remove_middle(arr):
x = [a[:, 1] for a in arr]
arr_new = [np.delete(a, 1, axis = 1) for a in arr]
return arr_new, x
def insert_middle(arr, x):
return [np.concatenate([a[:, :1], xx.reshape(-1, 1), a[:, 1:]], axis = 1) for a, xx in zip(arr, x)]
remove_middle(A)
([array([[1, 3],
[4, 6]]),
array([[ 7, 9],
[10, 12],
[13, 15]])],
[array([2, 5]), array([ 8, 11, 14])])
insert_middle(*remove_middle(A))
# gets back the original A
[array([[1, 2, 3],
[4, 5, 6]]),
array([[ 7, 8, 9],
[10, 11, 12],
[13, 14, 15]])]
CodePudding user response:
Without the ndmin=3 argument I can solve your answer using two nested list comprehensions in which the first indexes the middle argument and the second one deletes the middle argument of the inner arrays.
import numpy
A = np.array([[[1,2,3], [4,5,6]] , [[7,8,9] , [10,11,12], [13,14,15]]])
middle = [[array1d[1] for array1d in array2d] for array2d in A]
without_middle = [[np.delete(array1d, 1) for array1d in array2d] for array2d in A]
CodePudding user response:
With your strange data, this absurd-looking quintuple-nested list-comprehension is the best I could come up with :P
A1 = [[[[[e for i, e in enumerate(d) if i != 1] for d in c] for c in b] for b in a] for a in A]
X = [[[[[e for i, e in enumerate(d) if i == 1] for d in c] for c in b] for b in a] for a in A]
Output:
>>> A1
[[[[[1, 3], [4, 6]], [[7, 9], [10, 12], [13, 15]]]]]
>>> X
[[[[[2], [5]], [[8], [11], [14]]]]]
CodePudding user response:
Here is a solution. Note that lists are returned as raw python list which you can use as you want.
I changed your definition of A to a more suitable object.
import numpy as np
def f(A):
A1 = A.tolist()
X = []
for i in range(len(A1)):
temp = []
for j in range(len(A1[i])):
temp.append([A1[i][j].pop(1)])
X.append(temp)
return (A1, X)
def g(A1, X):
A = A1
for i in range(len(A1)):
for j in range(len(A1[i])):
A[i][j].insert(1, X[i][j][0])
return A
def main():
#A = np.array( [ [ [1,2,3], [4,5,6] ] , [ [7,8,9] , [10,11,12], [13,14,15] ] ] , ndmin = 3 )
A = np.asarray([ [ [1,2,3], [4,5,6] ] , [ [7,8,9] , [10,11,12], [13,14,15] ] ])
B, X = f(A)
print(g(B,X))
if __name__ == '__main__':
main()
Finally please note that this is one solution among many possible alternatives.