删除重复的数组列,保持顺序

时间:2016-09-28 09:28:13

标签: python arrays numpy

是否有一种相对简单的方法可以删除(numpy)数组的列并保持列的顺序?

举个例子,考虑一下这个数组:

a = np.array([[2, 1, 1, 3],
              [2, 1, 1, 3]])

我想要删除第三列,以便:

a = np.array([[2, 1, 3],
              [2, 1, 3]])

1 个答案:

答案 0 :(得分:1)

方法#1 以下是使用broadcasting的方法 -

a[:,~np.triu((a[:,None,:] == a[...,None]).all(0),1).any(0)]

示例运行 -

In [115]: a
Out[115]: 
array([[2, 1, 3, 5, 1, 3, 7],
       [6, 5, 4, 6, 5, 4, 8]])

In [116]: a[:,~np.triu((a[:,None,:] == a[...,None]).all(0),1).any(0)]
Out[116]: 
array([[2, 1, 3, 5, 7],
       [6, 5, 4, 6, 8]])

<强>解释

1)输入数组 -

In [156]: a
Out[156]: 
array([[2, 1, 3, 5, 1, 3, 7],
       [6, 5, 4, 6, 5, 4, 8]])

2)使用广播执行元素相等比较,保持第一个轴对齐,这将对应于原始2D数组的列轴 -

In [157]: a[:,None,:] == a[...,None]
Out[157]: 
array([[[ True, False, False, False, False, False, False],
        [False,  True, False, False,  True, False, False],
        [False, False,  True, False, False,  True, False],
        [False, False, False,  True, False, False, False],
        [False,  True, False, False,  True, False, False],
        [False, False,  True, False, False,  True, False],
        [False, False, False, False, False, False,  True]],

       [[ True, False, False,  True, False, False, False],
        [False,  True, False, False,  True, False, False],
        [False, False,  True, False, False,  True, False],
        [ True, False, False,  True, False, False, False],
        [False,  True, False, False,  True, False, False],
        [False, False,  True, False, False,  True, False],
        [False, False, False, False, False, False,  True]]], dtype=bool)

3)由于我们正在寻找重复的cols,让我们沿着第一个轴寻找所有匹配 -

In [158]: (a[:,None,:] == a[...,None]).all(0)
Out[158]: 
array([[ True, False, False, False, False, False, False],
       [False,  True, False, False,  True, False, False],
       [False, False,  True, False, False,  True, False],
       [False, False, False,  True, False, False, False],
       [False,  True, False, False,  True, False, False],
       [False, False,  True, False, False,  True, False],
       [False, False, False, False, False, False,  True]], dtype=bool)

4)我们期待仅保留第一次出现,因此我们可以使用上三角矩阵将所有对角线和下三角形元素设置为False -

In [163]: np.triu((a[:,None,:] == a[...,None]).all(0),1)
Out[163]: 
array([[False, False, False, False, False, False, False],
       [False, False, False, False,  True, False, False],
       [False, False, False, False, False,  True, False],
       [False, False, False, False, False, False, False],
       [False, False, False, False, False, False, False],
       [False, False, False, False, False, False, False],
       [False, False, False, False, False, False, False]], dtype=bool)

5)接下来,我们沿着第一个轴寻找任何匹配,表示重复 -

In [164]: (np.triu((a[:,None,:] == a[...,None]).all(0),1)).any(0)
Out[164]: array([False, False, False, False,  True,  True, False], dtype=bool)

6)我们希望删除那些重复项,因此反转掩码 -

In [165]: ~(np.triu((a[:,None,:] == a[...,None]).all(0),1)).any(0)
Out[165]: array([ True,  True,  True,  True, False, False,  True], dtype=bool)

7)最后,我们使用最终输出的掩码索引输入数组的列 -

In [166]: a[:,~(np.triu((a[:,None,:] == a[...,None]).all(0),1)).any(0)]
Out[166]: 
array([[2, 1, 3, 5, 7],
       [6, 5, 4, 6, 8]])

方法#2 关注内存效率甚至可能更快,这是一种将每列视为索引元组的方法 -

lidx = np.ravel_multi_index(a,a.max(1)+1)
out = a[:,np.sort(np.unique(lidx,return_index=1)[1])]

<强>解释

1)输入数组 -

In [203]: a
Out[203]: 
array([[2, 1, 3, 5, 1, 3, 7],
       [6, 5, 4, 6, 5, 4, 8]])

2)计算每列的线性指数当量 -

In [207]: lidx = np.ravel_multi_index(a,a.max(1)+1)

In [208]: lidx
Out[208]: array([24, 14, 31, 51, 14, 31, 71])

3)获得每个独特线性指数的第一次出现

In [209]: np.unique(lidx,return_index=1)[1]
Out[209]: array([1, 0, 2, 3, 6])

4)将这些和索引排序为输入数组的cols,用于最终的o / p -

In [210]: np.sort(np.unique(lidx,return_index=1)[1])
Out[210]: array([0, 1, 2, 3, 6])

In [211]: a[:,np.sort(np.unique(lidx,return_index=1)[1])]
Out[211]: 
array([[2, 1, 3, 5, 7],
       [6, 5, 4, 6, 8]])

有关转换为索引元组的注意事项的详细信息,请参阅this post