如何对二进制值数组的行进行排序,就像它们是长二进制数一样?

时间:2017-10-26 11:06:30

标签: python arrays sorting numpy

有一个2D numpy数组,每行约有500000行,每行512个值:

[
  [1,0,1,...,0,0,1], # 512 1's or 0's
  [0,1,0,...,0,1,1],
  ...
  [0,0,1,...,1,0,1], # row number 500000
]

如何对行进行排序,就像每行是一个长的512位整数一样?

[
  [0,0,1,...,1,0,1],
  [0,1,0,...,0,1,1],
  [1,0,1,...,0,0,1],
  ...
]

4 个答案:

答案 0 :(得分:3)

您也可以使用void视图(来自@Jaime here)和argsort来查看字符串,而不是转换为字符串。

def sort_bin(b):
    b_view = np.ascontiguousarray(b).view(np.dtype((np.void, b.dtype.itemsize * b.shape[1])))
    return b[np.argsort(b_view.ravel())] #as per Divakar's suggestion

测试

np.random.seed(0)

b = np.random.randint(0, 2, (10,5))
print(b)
print(sort_bin(b))

[[0 1 1 0 1]
 [1 1 1 1 1]
 [1 0 0 1 0]
 ..., 
 [1 0 1 1 0]
 [0 1 0 1 1]
 [1 1 1 0 1]]
[[0 0 0 0 1]
 [0 1 0 1 1]
 [0 1 1 0 0]
 ..., 
 [1 1 1 0 1]
 [1 1 1 1 0]
 [1 1 1 1 1]]

由于b_view只是b

的视图,所以应该更快,内存更少
t = np.random.randint(0,2,(2000,512))

%timeit sort_bin(t)
100 loops, best of 3: 3.09 ms per loop

%timeit np.array([[int(i) for i in r] for r in np.sort(np.apply_along_axis(lambda r: ''.join([str(c) for c in r]), 0, t))])
1 loop, best of 3: 3.29 s per loop

实际上快了约1000倍

答案 1 :(得分:0)

你可以用stable方式对它们进行512次排序,从最右边的位开始。

  1. 按最后一位排序
  2. 按倒数第二位排序,稳定(不要弄乱先前排序的结果)
  3. ... ...
  4. 按第一位排序,稳定
  5. 一个较小的例子:假设你想按位对这三个2位数字进行排序:

    11
    01
    00
    

    在第一步中,按正确的位排序,产生:

    00
    11
    01
    

    现在按第一位排序,在这种情况下,我们在该列中有两个0s。如果您的排序算法不稳定,则允许在结果中以任何顺序放置这些相同的项目,这可能导致01出现在我们不想要的00之前,因此我们使用稳定对第一列进行排序,保持相等项的相对顺序,得到所需的:

    00
    01
    11
    

答案 2 :(得分:0)

创建每个A B B1 Dog Cat Car Dog Cat Pie Cat Car Pie Cat Car Cat Car Pie (null) Car Cat Car Car Cat Pie Cat Pie (null) 的{​​{1}},然后应用string

因此,如果我们要测试row

np.sort()

我们可以使用np.apply_along_axis创建每个array的{​​{1}}:

a = np.array([[1,0,0,0],[0,0,0,0],[1,1,1,1],[0,0,1,1]])

现在会strings

row

现在我们可以a = np.apply_along_axis(lambda r: ''.join([str(c) for c in r]), 0, a) aarray(['1010', '0010', '0011', '0011'], dtype='<U4')

sort

制作strings

np.sort()

然后我们可以转换回原始格式:

a = np.sort(a)

使a

array(['0010', '0011', '0011', '1010'], dtype='<U4')

如果你想把这一切都塞进一行:

a = np.array([[int(i) for i in r] for r in a])

答案 3 :(得分:0)

这很慢但完成了工作。

def sort_col(arr, col_num=0):
# if we have sorted over all columns return array
if col_num >= arr.shape[1]:
    return arr

# sort array over given column
arr_sorted = arr[arr[:, col_num].argsort()]

# if the number of 1s in the given column is not equal to the total number
# of rows neither equal to 0, split on 1 and 0, sort and then merge
if len(arr) > np.sum(arr_sorted[:, col_num]) > 0:
    arr_sorted0s = sort_col(arr_sorted[arr_sorted[:, col_num]==0], col_num+1)
    arr_sorted1s = sort_col(arr_sorted[arr_sorted[:, col_num]==1], col_num+1)
    # change order of stacking if you want ascenting order
    return np.vstack((arr_sorted0s, arr_sorted1s))

# if the number of 1s in the given column is equal to the total number
# of rows or equal to 0, just go to the next iteration
return sort_col(arr_sorted, col_num + 1)



np.random.seed(0)
a = np.random.randint(0, 2, (5, 4))
print(a)
print(sort_col(a))

# prints
[[0 1 1 0]
 [1 1 1 1]
 [1 1 1 0]
 [0 1 0 0]
 [0 0 0 1]]
[[0 0 0 1]
 [0 1 0 0]
 [0 1 1 0]
 [1 1 1 0]
 [1 1 1 1]]

编辑。或者更好地使用Daniels解决方案。在我发布代码之前,我没有检查新的答案。