Python:使用 NaN 对数组进行排序

Posted

技术标签:

【中文标题】Python:使用 NaN 对数组进行排序【英文标题】:Python: sorting an array with NaNs 【发布时间】:2014-02-06 23:58:23 【问题描述】:

注意:我使用的是 Python 和 numpy 数组。

我有很多数组,它们都有两列和多行。第二列中有一些 NaN 值;第一列只有数字。

我想根据第二列按升序对每个数组进行排序,将 NaN 值排除在外。这是一个大数据集,所以我宁愿不必将 NaN 值转换为零或其他东西。

我希望它像这样排序:

105.  4.
22.   10.
104.  26.
...
...
...
53.   520.
745.  902.
184.  nan
19.   nan

首先我尝试使用 fix_invalid 将 NaN 转换为 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 值。

按照我想要的方式对该数组进行排序的最简单方法是什么?

【问题讨论】:

在对列表的其余部分进行排序之前,您是否尝试过使用filter() 调用来删除带有nan 的元素? 你为什么在 python 中排序而不是使用 numpy? 在最新版本的numpy中,函数sort可以按照你所寻求的方式处理nans。这是链接docs.scipy.org/doc/numpy/reference/generated/numpy.sort.html 为什么不把 NaN 放在最后呢?我相信这最终不会那么慢得多。但是,如果可以的话,只需使用 numpy 函数会快得多 基于@freude 的评论,您可以看到here 对浮点数进行比较的C 函数如何处理这个问题,因为np.nan != np.nan 的计算结果为True,而任何其他涉及@987654337 的比较@返回False 【参考方案1】:

不确定是否可以使用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]])

【讨论】:

另一个值得注意的问题是 np.argsort 无法对包含 np.nan 的对象数组进行排序。如果数组是 dtype == object,则 np.nan 将不会正确放置(并且没有警告)【参考方案2】:

如果你真的不想使用 numpy 数组,你可以对第二列进行排序,然后获取索引来调用你的数组。

只能像这样在一行中完成:

yourarray[sorted(range(len(yourarray[:,1])), key=lambda k: yourarray[:,1][k])]

【讨论】:

【参考方案3】:

你可以创建一个掩码数组:

a = np.loadtxt('test.txt')

mask = np.isnan(a)
ma = np.ma.masked_array(a, mask=mask)

然后使用掩码数组对a进行排序:

a[np.argsort(ma[:, 1])]

【讨论】:

【参考方案4】:

你可以使用比较功能

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)

见http://docs.python.org/2.7/library/functions.html#sorted

【讨论】:

【参考方案5】:

如果您使用的是旧版本的 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,numpy 的 sort/argsort 已经具有这种行为。如果您出于某种原因需要使用 python 的排序,您可以按照其他答案中的说明制作自己的比较函数。

【讨论】:

以上是关于Python:使用 NaN 对数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章

尝试在 python 中对数组进行线性回归,但我不断收到错误“数组不得包含 infs 或 NaN”。没有 inf 或 NaN

如何将长双打与 qsort 以及关于 NaN 进行比较?

Python\Numpy:将数组与 NAN 进行比较 [重复]

如何使用python对2D数组进行冒泡排序

如何忽略 numpy 数组中的 NaN 数据点并在 Python 中生成规范化数据?

Python pandas 使用 fillna() 来避免对 NaN 值进行错误拆分