Python 使用NaN值进行排序时可能存在错误

Python 使用NaN值进行排序时可能存在错误,python,pandas,Python,Pandas,如果我制作如下所示的数据帧: In [128]: test = pd.DataFrame({'a':[1,4,2,7,3,6], 'b':[2,2,2,1,1,1], 'c':[2,6,np.NaN, np.NaN, 1, np.NaN]}) In [129]: test Out[129]: a b c 0 1 2 2 1 4 2 6 2 2 2 NaN 3 7 1 NaN 4 3 1 1 5 6 1 NaN 基本排序按预期执行。列c上的排序适当

如果我制作如下所示的数据帧:

In [128]: test = pd.DataFrame({'a':[1,4,2,7,3,6], 'b':[2,2,2,1,1,1], 'c':[2,6,np.NaN, np.NaN, 1, np.NaN]})
In [129]: test
Out[129]:
   a  b   c
0  1  2   2
1  4  2   6
2  2  2 NaN
3  7  1 NaN
4  3  1   1
5  6  1 NaN
基本排序按预期执行。列c上的排序适当地分隔了nan值。对a列和b列执行多级排序将按预期顺序排列:

In [133]: test.sort(columns='c', ascending=False)
Out[133]:
   a  b   c
5  6  1 NaN
3  7  1 NaN
2  2  2 NaN
1  4  2   6
0  1  2   2
4  3  1   1

In [134]: test.sort(columns=['b', 'a'], ascending=False)
Out[134]:
   a  b   c
1  4  2   6
2  2  2 NaN
0  1  2   2
3  7  1 NaN
5  6  1 NaN
4  3  1   1
但对b列和c列进行多级排序并不能得到预期的结果:

In [135]: test.sort(columns=['b', 'c'], ascending=False)
Out[135]:
   a  b   c
1  4  2   6
0  1  2   2
2  2  2 NaN
3  7  1 NaN
4  3  1   1
5  6  1 NaN
事实上,即使仅对c列进行排序,但使用多级排序命名法也会失败:

In [136]: test.sort(columns=['c'], ascending=False)
Out[136]:
   a  b   c
1  4  2   6
0  1  2   2
2  2  2 NaN
3  7  1 NaN
4  3  1   1
5  6  1 NaN

我认为这应该给出与上面第133行完全相同的结果。这是熊猫虫还是有什么我不知道的?(仅供参考,pandas v0.11.0,numpy v1.7.1,python 2.7.2.5,windows 7上的32位)

这是一个有趣的例子。请注意,即使是普通python也不能得到这样的“正确”:

这里的原因是因为
NaN
既不大于也不小于其他元素——因此没有定义严格的顺序。正因为如此,
python
将它们放在一边

>>> nan > 6
False
>>> nan < 6
False
>nan>6
假的
>>>nan<6
假的

Pandas必须在单列情况下进行显式检查——可能从numpy 1.4开始使用
np.argsort
np.sort
np.sort
NaN
值放在末尾。

感谢上面的提示。我想这已经是一个众所周知的问题了。我想出的一个权宜之计是:

test['c2'] = test.c.fillna(value=test.c.min() - 1)
test.sort(['b', 'c2'])
test = test.drop('c2', axis = 1)

此方法在常规numpy中不起作用,因为.min()将返回nan,但在pandas中它可以正常工作。

我注意到test.sort(columns='c',升序=False)的可能重复项。在这种情况下,sort(columns='b',升序=False)确实给出了正确答案。但我不知道这是否是一个稳健的解决方案。有人有想法吗?只有当熊猫排序算法稳定时,这种想法才会起作用。我在文档中没有找到任何东西(numpy的排序算法在默认情况下并不稳定)。我现在正在尝试查找源…@mgilson在此上签出它调用
k.argsort
。。。其中,
k
是数据帧的一列——可能这是一个numpy数组,它给出了索引,告诉熊猫如何重新排序数据。不幸的是,np.argsort(默认情况下)使用的
quicksort
算法不稳定,因此您的解决方案不是100%健壮的。我相信Numpy确实有一个
nanmin
函数:)。
test['c2'] = test.c.fillna(value=test.c.min() - 1)
test.sort(['b', 'c2'])
test = test.drop('c2', axis = 1)