I have a variable amount of arrays with the same size and same dtype. Their cells (called pixels
in my code) either have a float number or a NaN.
I would like to merge these arrays but with 3 specific criterias. If for one pixel (called overlapping pixel):
- At least 2 arrays have a value (non-NaN): attribute to the overlapping pixel in the merged array the value of 1 of the input arrays only.
- Only 1 input array has a value, attribute to the overlapping pixel in the merged array the value of this input array's pixel.
- If none of the input arrays have a value for a specific pixel, we write a
np.nan
in the overlapping pixel.
In order to do that, I have a loop going through each pixel, and evaluating how many input arrays have a value. To satisfy the 1st criteria, I wrote a set of if/elif/else conditions. To satisfy the 2nd criteria, the else
part of my conditions is simply a np.nansum
(because all but 1 array have NaNs at this specific pixel).
I wrote a function that is not efficient at all, and quite limiting. How could I improve my code in order to treat a variable amount of arrays to merge ? (more than 3 arrays).
My code:
import numpy as np
def merger(*args):
# This function evaluates pixel per pixel the values of 2 to 3 arrays the same size.
# Each pixel either has a value or a NaN. We want to merge the arrays without summing their values at overlapping pixels.
# If at least two arrays have a value for an intersecting pixel, we pick one of the array's value to attribute to the merging pixel in the new array.
# If we have 2 arrays to merge
if len(args) == 2:
C = np.empty([args[0].shape[0], args[0].shape[1], args[0].shape[2]],dtype=float)
for b in range(args[0].shape[0]):
for i in range(args[0].shape[1]):
for j in range(args[0].shape[2]):
# If the two similar pixels have a value, take the value of the first array
if np.isnan(args[0][b,i,j]) == False and np.isnan(args[1][b,i,j]) == False:
C[b,i,j] = args[0][b,i,j]
# If all of the pixels are NaN, we input a NaN
elif np.isnan(args[0][b,i,j]) == True and np.isnan(args[1][b,i,j]) == True:
C[b,i,j] = np.nan
# Else, take the nansum of the two pixels (because one is a NaN, the other will be the real value)
else:
C[b,i,j] = np.nansum([args[0][b,i,j],args[1][b,i,j]])
# If we have 3 arrays to merge (A1, A2 and A3)
if len(args) == 3:
C = np.empty([args[0].shape[0], args[0].shape[1], args[0].shape[2]],dtype=float)
for b in range(args[0].shape[0]):
for i in range(args[0].shape[1]):
for j in range(args[0].shape[2]):
# If A1 and A2 have a value but not A3, pick the value of A1. If A1 and A3 have a value but not A2, pick the value of A1
if np.isnan(args[0][b,i,j]) == False and np.isnan(args[1][b,i,j]) == False and np.isnan(args[2][b,i,j]) == True or np.isnan(args[0][b,i,j]) == False and np.isnan(args[2][b,i,j]) == False and np.isnan(args[1][b,i,j]) == True:
C[b,i,j] = args[0][b,i,j]
# If A2 and A3 have a value but not A1, pick the value of A2
elif np.isnan(args[1][b,i,j]) == False and np.isnan(args[2][b,i,j]) == False and np.isnan(args[0][b,i,j]) == True:
C[b,i,j] = args[1][b,i,j]
# If all the arrays have a value, pick the value of A3
elif np.isnan(args[1][b,i,j]) == False and np.isnan(args[2][b,i,j]) == False and np.isnan(args[2][b,i,j]) == False:
C[b,i,j] = args[2][b,i,j]
# If all of the pixels are NaN, we input a NaN
elif np.isnan(args[1][b,i,j]) == True and np.isnan(args[2][b,i,j]) == True and np.isnan(args[2][b,i,j]) == True:
C[b,i,j] = np.nan
# If only one array has a value, nansum will attribute this value to the pixel
else:
C[b,i,j] = np.nansum([args[0][b,i,j],args[1][b,i,j], args[2][b,i,j]])
return C
# Example
A1 = np.array([[[1, 1, 1],[np.nan, np.nan, np.nan], [1, np.nan, 1]],[[1, 1, 1],[np.nan, np.nan, np.nan], [1, np.nan, 1]]])
A2 = np.array([[[1, np.nan, 1],[1, np.nan, np.nan], [1, np.nan, 1]],[[1, 1, 1],[np.nan, np.nan, 1], [np.nan, 1, 1]]])
A3 = np.array([[[1, 1, 1],[np.nan, np.nan, 1], [np.nan, 1, 1]],[[1, np.nan, 1],[1, np.nan, np.nan], [1, np.nan, 1]]])
merger(A1, A2, A3)
array([[[ 1., 1., 1.],
[ 1., nan, 1.],
[ 1., 1., 1.]],
[[ 1., 1., 1.],
[ 1., nan, 1.],
[ 1., 1., 1.]]])
CodePudding user response:
Unless I'm missing something, how is this any different than iteratively replacing A1 nan values with A2 then A3? Since you aren't summing anything and you are arbitrarily picking one non-null value from the other arrays.
A1 = np.array([[[1, 1, 1],[np.nan, np.nan, np.nan], [1, np.nan, 1]],[[1, 1, 1],[np.nan, np.nan, np.nan], [1, np.nan, 1]]])
A2 = np.array([[[1, np.nan, 1],[1, np.nan, np.nan], [1, np.nan, 1]],[[1, 1, 1],[np.nan, np.nan, 1], [np.nan, 1, 1]]])
A3 = np.array([[[1, 1, 1],[np.nan, np.nan, 1], [np.nan, 1, 1]],[[1, np.nan, 1],[1, np.nan, np.nan], [1, np.nan, 1]]])
A1[np.isnan(A1)] = A2[np.isnan(A1)]
A1[np.isnan(A1)] = A3[np.isnan(A1)]
print(A1)
Output
[[[ 1. 1. 1.]
[ 1. nan 1.]
[ 1. 1. 1.]]
[[ 1. 1. 1.]
[ 1. nan 1.]
[ 1. 1. 1.]]]