Given I have two arrays:
array1 = np.array([np.nan,np.nan,np.nan,np.nan,2,np.nan,1,np.nan,np.nan,5,np.nan,np.nan,6,np.nan,10,9,np.nan])
array2 = np.array([np.nan,np.nan,np.nan,np.nan,45,np.nan,33,np.nan,np.nan,32,np.nan,np.nan,44,np.nan,10,53,np.nan])
I want to get array2 sorted in ascending order of array1 elements with same nan sequence:
[np.nan,np.nan,np.nan,np.nan,32,np.nan,10,np.nan,np.nan,33,np.nan,np.nan,44,np.nan,53,45,np.nan]
Seems I could use
np.argsort(array1)
= [ 6 4 9 12 15 14 0 13 11 10 8 5 3 2 1 7 16]
if there's a command to move elements in array2 like : put an element with index "6" to the first not nan place etc
Any ideas?
CodePudding user response:
Remove NaN, sort, add NaN.
from operator import itemgetter
#remove NaN
a = [x for x in array1 if not np.isnan(x)]
b = [y for y in array2 if not np.isnan(y)]
# a == [2.0, 1.0, 5.0, 6.0, 10.0, 9.0]
# b == [45.0, 33.0, 32.0, 44.0, 10.0, 53.0]
# sort
c = map(itemgetter(1), sorted(zip(a, b)))
# list(c) == [33.0, 45.0, 32.0, 44.0, 53.0, 10.0]
# add NaN
d = [(np.nan if np.isnan(x) else next(c)) for x in array1]
# d == [nan, nan, nan, nan, 33.0, nan, 45.0, nan, nan, 32.0, nan, nan, 44.0, nan, 53.0, 10.0, nan]
Note that the suggestion in Akshay Sehgal's answer is likely faster than mine, since it uses numpy directly rather than python lists and iterators.
CodePudding user response:
You can do this with numpy by overwriting the view over the second array for non nan elements.
idx = array1[~np.isnan(array1)].argsort()
array2[~np.isnan(array2)] = array2[~np.isnan(array2)][idx]
array2
array([nan, nan, nan, nan, 33., nan, 45., nan, nan, 32., nan, nan, 44.,
nan, 53., 10., nan])
Another "cleaner" way to do this is to just sort the arrays as is, remove nans and then overwrite the view for array2 as in the previous approach.
ordered = array2[array1.argsort()]
ordered = ordered[~np.isnan(ordered)]
array2[~np.isnan(array2)] = ordered
array2
array([nan, nan, nan, nan, 33., nan, 45., nan, nan, 32., nan, nan, 44.,
nan, 53., 10., nan])