如何使用key作为isnan对numpy数组进行排序?

时间:2017-09-20 15:28:30

标签: python numpy

我有像

这样的numpy数组
np.array([[1.0, np.nan, 5.0, 1, True, True, np.nan, True],
       [np.nan, 4.0, 7.0, 2, True, np.nan, False, True],
       [2.0, 5.0, np.nan, 3, False, False, True, np.nan]], dtype=object)

现在我想用key作为isnan对值进行排序?我怎样才能做到这一点?所以我最终会在数组中

np.array([[1.0, 5.0, 1, True, True, True, np.nan, np.nan],
   [4.0, 7.0, 2, True, False, True, np.nan, np.nan],
   [2.0, 5.0, 3, False, False, True, np.nan, np.nan]], dtype=object)

np.sort()无效。通过将具有sorted函数的已排序列作为pd.isnull()应用于pandas,可以实现相同的效果,但是寻找速度的numpy答案。

在熊猫中

data = pd.DataFrame({'Key': [1, 2, 3], 'Var': [True, True, False], 'ID_1':[1, np.NaN, 2],
                'Var_1': [True, np.NaN, False], 'ID_2': [np.NaN, 4, 5], 'Var_2': [np.NaN, False, True],
                'ID_3': [5, 7, np.NaN], 'Var_3': [True, True, np.NaN]})

data.apply(lambda x : sorted(x,key=pd.isnull),1).values 

输出:

array([[1.0, 5.0, 1, True, True, True, nan, nan],
   [4.0, 7.0, 2, True, False, True, nan, nan],
   [2.0, 5.0, 3, False, False, True, nan, nan]], dtype=object)

3 个答案:

答案 0 :(得分:5)

方法#1

这是一种从some what借用masking概念的矢量化方法 -

def mask_app(a):
    out = np.empty_like(a)
    mask = np.isnan(a.astype(float))
    mask_sorted = np.sort(mask,1)
    out[mask_sorted] = a[mask]
    out[~mask_sorted] = a[~mask]
    return out

示例运行 -

# Input dataframe
In [114]: data
Out[114]: 
   ID_1  ID_2  ID_3  Key    Var  Var_1  Var_2 Var_3
0   1.0   NaN   5.0    1   True   True    NaN  True
1   NaN   4.0   7.0    2   True    NaN  False  True
2   2.0   5.0   NaN    3  False  False   True   NaN

# Use pandas approach for verification    
In [115]: data.apply(lambda x : sorted(x,key=pd.isnull),1).values
Out[115]: 
array([[1.0, 5.0, 1, True, True, True, nan, nan],
       [4.0, 7.0, 2, True, False, True, nan, nan],
       [2.0, 5.0, 3, False, False, True, nan, nan]], dtype=object)

# Use proposed approach and verify
In [116]: mask_app(data.values)
Out[116]: 
array([[1.0, 5.0, 1, True, True, True, nan, nan],
       [4.0, 7.0, 2, True, False, True, nan, nan],
       [2.0, 5.0, 3, False, False, True, nan, nan]], dtype=object)

方法#2

只需进行少量修改,即可使用this post -

创意的简化版
def mask_app2(a):
    out = np.full(a.shape,np.nan,dtype=a.dtype)
    mask = ~np.isnan(a.astype(float))
    out[np.sort(mask,1)[:,::-1]] = a[mask]
    return out

答案 1 :(得分:2)

因为你有一个对象数组,所以在Python中进行排序,然后制作你的数组。你可以写一个像这样的键:

from math import isnan

def key(x):
    if isnan(x):
        t = 3
        x = 0
    elif isinstance(x, bool):
        t = 2
    else:
        t = 1
    return t, x

此键返回一个双元素元组,其中第一个元素按类型给出初步排序。它认为所有NaN都等于且大于任何其他类型。

即使您从DataFrame开始使用数据,也可以执行以下操作:

values = [list(sorted(row, key=key)) for row in data.values]
values = np.array(values, dtype=np.object)

如果符合您的需求,您可以将列表理解替换为np.apply_along_axis

values = np.apply_along_axis(lambda row: np.array(list(sorted(row, key=key))),
                             axis=1, arr=data.values)

答案 2 :(得分:0)

您不能使用object数组和nan执行此操作。您需要找到所有适合的数字类型。当用作对象而不是浮点数时,nan会为<>==返回false。

此外,TrueFalse相当于0和1,因此我认为没有办法获得预期的结果。

您必须查看将dtype转换为float是否能为您的用例提供正确的结果。