代码之家  ›  专栏  ›  技术社区  ›  Fnord

保持numpy数组每行的n个最高值,其他所有值为零[重复]

  •  3
  • Fnord  · 技术社区  · 8 年前

    我有一个numpy数组的数据,我只需要保存在那里 n

    我当前的解决方案:

    import numpy as np
    np.random.seed(30)
    
    # keep only the n highest values
    n = 3
    
    # Simple 2x5 data field for this example, real life application will be exteremely large
    data = np.random.random((2,5))
    #[[ 0.64414354  0.38074849  0.66304791  0.16365073  0.96260781]
    # [ 0.34666184  0.99175099  0.2350579   0.58569427  0.4066901 ]]
    
    
    # find indices of the n highest values per row
    idx = np.argsort(data)[:,-n:]
    #[[0 2 4]
    # [4 3 1]]
    
    
    # put those values back in a blank array
    data_ = np.zeros(data.shape) # blank slate
    for i in xrange(data.shape[0]):
        data_[i,idx[i]] = data[i,idx[i]]
    
    # Each row contains only the 3 highest values per row or the original data
    #[[ 0.64414354  0.          0.66304791  0.          0.96260781]
    # [ 0.          0.99175099  0.          0.58569427  0.4066901 ]]
    

    data_ 有 n data.shape[1] 小于 n 但唯一的问题是 for loop ,这很慢,因为我的实际用例是在非常非常大的阵列上。

    1 回复  |  直到 8 年前
        1
  •  6
  •   DSM    8 年前

    你可以根据 np.argsort --np.argsort ,第一个获取索引顺序,第二个获取秩——以矢量化的方式,然后使用 np.where 或者简单地将其他所有内容乘法为零:

    In [116]: np.argsort(data)
    Out[116]: 
    array([[3, 1, 0, 2, 4],
           [2, 0, 4, 3, 1]])
    
    In [117]: np.argsort(np.argsort(data))  # these are the ranks
    Out[117]: 
    array([[2, 1, 3, 0, 4],
           [1, 4, 0, 3, 2]])
    
    In [118]: np.argsort(np.argsort(data)) >= data.shape[1] - 3
    Out[118]: 
    array([[ True, False,  True, False,  True],
           [False,  True, False,  True,  True]], dtype=bool)
    
    In [119]: data * (np.argsort(np.argsort(data)) >= data.shape[1] - 3)
    Out[119]: 
    array([[ 0.64414354,  0.        ,  0.66304791,  0.        ,  0.96260781],
           [ 0.        ,  0.99175099,  0.        ,  0.58569427,  0.4066901 ]])
    
    In [120]: np.where(np.argsort(np.argsort(data)) >= data.shape[1]-3, data, 0)
    Out[120]: 
    array([[ 0.64414354,  0.        ,  0.66304791,  0.        ,  0.96260781],
           [ 0.        ,  0.99175099,  0.        ,  0.58569427,  0.4066901 ]])