Python: сортировка массива с помощью NaNs
Примечание: я использую массивы Python и numpy.
у меня есть много массивов, все из которых имеют два столбца и много строк. Во втором столбце есть некоторые значения NaN; в первом столбце есть только числа.
Я хотел бы отсортировать каждый массив в порядке возрастания в соответствии со вторым столбцом, оставив значения NaN. Это большой набор данных, поэтому я бы предпочел не преобразовывать значения NaN в нули или что-то еще.
Я хотел бы, чтобы он сортировал, как Итак:
105. 4.
22. 10.
104. 26.
...
...
...
53. 520.
745. 902.
184. nan
19. nan
сначала я попытался с помощью fix_invalid
который преобразует NaNs в 1x10^20
:
#data.txt has one of the arrays with 2 columns and a bunch of rows.
Data_0_30 = array(genfromtxt(fname='data.txt'))
g = open("iblah.txt", "a") #saves to file
def Sorted_i_M_W(mass):
masked = ma.fix_invalid(mass)
print >> g, array(sorted(masked, key=itemgetter(1)))
Sorted_i_M_W(Data_0_30)
g.close()
или Я заменил функцию что-то вроде этого:
def Sorted_i_M_W(mass):
sortedmass = sorted( mass, key=itemgetter(1))
print >> g, array(sortedmass)
для каждой попытки я получил что-то вроде:
...
[ 4.46800000e+03 1.61472200e+11]
[ 3.72700000e+03 1.74166300e+11]
[ 4.91800000e+03 1.75502300e+11]
[ 6.43500000e+03 nan]
[ 3.95520000e+04 8.38907500e+09]
[ 3.63750000e+04 1.27625700e+10]
[ 2.08810000e+04 1.28578500e+10]
...
где в месте расположения значения NaN сортировка возобновляется снова.
(для fix_invalid
NaN в приведенном выше отрывке показывает 1.00000000e+20
значение). Но я бы хотел, чтобы сортировка игнорировала значение NaN полностью.
какой самый простой способ, чтобы отсортировать этот массив так, как я хочу?
5 ответов
не уверен, что это можно сделать с numpy.sort
, но вы можете использовать numpy.argsort
обязательно:
>>> arr
array([[ 105., 4.],
[ 53., 520.],
[ 745., 902.],
[ 19., nan],
[ 184., nan],
[ 22., 10.],
[ 104., 26.]])
>>> arr[np.argsort(arr[:,1])]
array([[ 105., 4.],
[ 22., 10.],
[ 104., 26.],
[ 53., 520.],
[ 745., 902.],
[ 19., nan],
[ 184., nan]])
вы можете создать массив в маске:
a = np.loadtxt('test.txt')
mask = np.isnan(a)
ma = np.ma.masked_array(a, mask=mask)
и потом вроде a
использование маскированного массива:
a[np.argsort(ma[:, 1])]
вы можете использовать функцию сравнения
def cmpnan(x, y):
if isnan(x[1]):
return 1 # x is "larger"
elif isnan(y[1]):
return -1 # x is "smaller"
else:
cmp(x[1], y[1]) # compare numbers
sorted(data, cmp=cmpnan)
Если вы используете более старую версию numpy и не хотите обновлять (или если вы хотите код, поддерживающий более старые версии numpy), вы можете сделать:
import numpy as np
def nan_argsort(a):
temp = a.copy()
temp[np.isnan(a)] = np.inf
return temp.argsort()
sorted = a[nan_argsort(a[:, 1])]
в более новых версиях numpy, по крайней мере 1.6 я думаю, сортировка/argsort numpy уже имеет это поведение. Если вам нужно использовать сортировку в Python, вы можете сделать свою собственную функцию сравнения, как описано в других ответах.
Если вы действительно не хотите использовать массив numpy, вы можете отсортировать второй столбец, а затем получить индекс для вызова массива.
Это можно сделать только в одной строке:
yourarray[sorted(range(len(yourarray[:,1])), key=lambda k: yourarray[:,1][k])]