根据稀疏信息填充数组

时间:2017-10-11 07:28:31

标签: python numpy

我有以下稀疏结构来描述底层密集数组A

a = np.array([1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1])
b = np.array([1, 5, 2, 3])
每当a更改值时,

1都会包含A。只要b更改值,A就会包含新值。也就是说,我的ab示例产生以下数组:

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

如果给出稀疏信息,我怎样才能有效地恢复A?我对b为n维时可扩展的解决方案特别感兴趣。

在2d中,我们会有相同的a,但

bb = np.array([[1, 5, 2, 2], [2, -1, 0, 1]])

产生

AA = np.array([[1, 1, 1, 1, 1, 5, 5, 2, 2, 2, 3], [2, 2, 2, 2, 2, -1, -1, 0, 0, 0, 1]])

2 个答案:

答案 0 :(得分:2)

非常简单,cumsum。使用cumsum获取 intervaled 索引,然后将其索引到数据数组中。

因此,对于1D数据 -

idx = a.cumsum(-1)-1
out = b[idx]

2D数据 -

out = bb[np.arange(bb.shape[0])[:,None],idx]

对于通用n-dim数据,只需使用np.take沿最后一个轴索引,从而覆盖通用n-dim个案例,如此 -

np.take(b_ndarray,idx,axis=-1)

示例运行

In [80]: a  # sparse array that defines the intervals/indices
Out[80]: array([1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1])

In [81]: b # 1D data array
Out[81]: array([1, 5, 2, 3])

In [82]: bb  # 2D data array
Out[82]: 
array([[ 1,  5,  2,  2],
       [ 2, -1,  0,  1]])

In [93]: idx = a.cumsum(-1)-1 # Get the intervaled indices

In [94]: idx
Out[94]: array([0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3])

In [84]: np.take(b,idx,axis=-1) # output for 1D data
Out[84]: array([1, 1, 1, 1, 1, 5, 5, 2, 2, 2, 3])

In [85]: np.take(bb,idx,axis=-1)  # output for 2D data
Out[85]: 
array([[ 1,  1,  1,  1,  1,  5,  5,  2,  2,  2,  2],
       [ 2,  2,  2,  2,  2, -1, -1,  0,  0,  0,  1]])

让我们测试一些随机3D数据 -

In [89]: bbb = np.random.randint(-4,5,(2,3,4))

In [90]: bbb
Out[90]: 
array([[[-1,  0,  0,  4],
        [ 0, -1,  3,  1],
        [ 1, -4, -3,  1]],

       [[-1, -4,  1, -4],
        [-3, -2,  0, -2],
        [-4, -1, -2, -4]]])

In [91]: np.take(bbb,idx,axis=-1)
Out[91]: 
array([[[-1, -1, -1, -1, -1,  0,  0,  0,  0,  0,  4],
        [ 0,  0,  0,  0,  0, -1, -1,  3,  3,  3,  1],
        [ 1,  1,  1,  1,  1, -4, -4, -3, -3, -3,  1]],

       [[-1, -1, -1, -1, -1, -4, -4,  1,  1,  1, -4],
        [-3, -3, -3, -3, -3, -2, -2,  0,  0,  0, -2],
        [-4, -4, -4, -4, -4, -1, -1, -2, -2, -2, -4]]])

运行时测试

其他方法 -

def diff_repeat_1d(a, b): # @Kasramvd's soln for 1D
    inds = np.concatenate((np.where(a)[0], [a.size]))
    durations = np.diff(inds)
    return np.repeat(b, durations)

def diff_repeat_2d(a, b): # @Kasramvd's soln for 2D
    inds = np.concatenate((np.where(a)[0], [a.size]))
    durations = np.diff(inds)
    return np.repeat(bb, durations, axis=1)

关于1D数据的计时 -

In [199]: a = np.array([1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1])
     ...: b = np.array([1, 5, 2, 3])
     ...: 

In [200]: a = np.tile(a,100000)
     ...: b = np.tile(b,100000)
     ...: 

In [201]: %timeit diff_repeat_1d(a, b) # @Kasramvd's soln
100 loops, best of 3: 8.42 ms per loop

In [202]: %timeit np.take(b,a.cumsum()-1,axis=-1)
100 loops, best of 3: 4.53 ms per loop

关于2D数据的计时 -

In [203]: bb = np.array([[1, 5, 2, 2], [2, -1, 0, 1]])

In [204]: bb = np.tile(bb,100000)

In [206]: %timeit diff_repeat_2d(a, bb) # @Kasramvd's soln
100 loops, best of 3: 12.1 ms per loop

In [207]: %timeit np.take(bb,a.cumsum()-1,axis=-1)
100 loops, best of 3: 5.58 ms per loop

答案 1 :(得分:1)

这是一种方式:

In [45]: inds = np.concatenate((np.where(a)[0], [a.size]))

In [46]: durations = np.diff(inds)

In [47]: np.repeat(b, durations)
Out[47]: array([1, 1, 1, 1, 1, 5, 5, 2, 2, 2, 3])

对于2D阵列,您只需将轴传递给repeat函数:

In [49]: np.repeat(bb, durations, axis=1)
Out[49]: 
array([[ 1,  1,  1,  1,  1,  5,  5,  2,  2,  2,  2],
       [ 2,  2,  2,  2,  2, -1, -1,  0,  0,  0,  1]])