Numpy温度计编码

时间:2018-03-03 04:21:15

标签: python numpy

我正在尝试使用numpy优化的内置函数来生成温度计编码。如果给定长度为1,则温度计编码基本上生成 n 量。例如,在8长度中,3将被编码为:

1 1 1 0 0 0 0 0

使用numpy基于整数输入生成该向量基本上是切片并设置1.

stream[:num_ones] = 1

所以我的问题是 vector 作为输入,例如,生成矩阵输出的最佳方法是:

[2 3 4 1]

作为输入应该产生:

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

我目前的解决方案是迭代所需大小的零矩阵,并使用我上面写的切片方法将所需的元素数设置为1。我有更快的方法吗?

4 个答案:

答案 0 :(得分:4)

之前我从未听说过“温度计编码”,但是当你意识到它与单热编码如此相似时,很明显你可以使用位移操作来实现:

>>> a = np.array([2, 3, 4, 1], dtype=np.uint8)
>>> print(np.fliplr(np.unpackbits((1 << a) - 1).reshape(-1,8)))
[[1 1 0 0 0 0 0 0]
 [1 1 1 0 0 0 0 0]
 [1 1 1 1 0 0 0 0]
 [1 0 0 0 0 0 0 0]]

编辑:您可以通过处理8个列块来将该想法概括为任意大小的整数:

a = np.array([2, 13, 4, 0, 1, 17], dtype=np.uint8)
out = np.empty((len(a), 0), dtype=np.uint8)
while a.any():
    block = np.fliplr(np.unpackbits((1 << a) - 1).reshape(-1,8))
    out = np.concatenate([out, block], axis=1)
    a = np.where(a<8, 0, a-8)

print(out)
[[1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0]
 [1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0]]

答案 1 :(得分:2)

In [22]: x = [2, 3, 4, 1, 0, 8]

In [23]: length = 8

In [24]: (np.arange(length) < np.array(x).reshape(-1, 1)).astype(int)
Out[24]:
array([[1, 1, 0, 0, 0, 0, 0, 0],
       [1, 1, 1, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 1, 1, 1, 1]])

或者,创建一系列不同长度的&#34;栏&#34;:

In [46]: k = np.arange(length + 1)

In [47]: bars = (k[:-1] < k.reshape(-1, 1)).astype(int)

In [48]: bars

Out[48]: 
array([[0, 0, 0, 0, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0],
       [1, 1, 0, 0, 0, 0, 0, 0],
       [1, 1, 1, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0, 0, 0],
       [1, 1, 1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 1, 1, 0],
       [1, 1, 1, 1, 1, 1, 1, 1]])

并将其用作查找表:

In [49]: bars[x]
Out[49]:
array([[1, 1, 0, 0, 0, 0, 0, 0],
       [1, 1, 1, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 1, 1, 1, 1]])

在上面的代码中,预分配的数组bars的形状为(length+1, length)。可以使用以下命令创建bars的更高内存效率的表示:

In [61]: from numpy.lib.stride_tricks import as_strided

In [62]: u = np.zeros(2*length, dtype=int)

In [63]: u[length:] = 1

In [64]: bars = as_strided(u[length-1:], shape=(length+1, length), strides=(u.strides[0], -u.strides[0]))

In [65]: bars
Out[65]: 
array([[0, 0, 0, 0, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0],
       [1, 1, 0, 0, 0, 0, 0, 0],
       [1, 1, 1, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0, 0, 0],
       [1, 1, 1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 1, 1, 0],
       [1, 1, 1, 1, 1, 1, 1, 1]])

然后bars是一维数组u的视图,它只使用2*length个整数。

答案 2 :(得分:1)

Wim的回答令人难以置信。我也从未听说温度计编码,但如果我这样做,我会选择地图。如果没有循环解决方案,它会更短。表现非常相似。

>>> def setValue(val):
      return np.append(np.ones(val), np.zeros(8-val))
>>> np.array(list(map(setValue, [2,3,4,5])))

array([[ 1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.],
   [ 1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.],
   [ 1.,  1.,  1.,  1.,  1.,  0.,  0.,  0.]])

或具有lambda函数的单行

>>> np.array(list(map(lambda v: np.append(np.ones(v), np.zeros(8-v)), [1,6,3,8])))

array([[ 1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 1.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
   [ 1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.],
   [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.]])

答案 3 :(得分:0)

在数组创建函数中没有太大的不同,listcomp

temps = [1,2,4,1]
tlen = 8
np.stack([np.pad(np.ones(t), (0, tlen-t), 'constant') for t in temps])

Out[66]: 
array([[ 1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.],
       [ 1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]])