我正在尝试使用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。我有更快的方法吗?
答案 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.]])