填充 numpy 数组的向量方式

Vector way of populating numpy array

我有一些二进制字符串 s,例如 001010。我想将其转换为 numpy 数组 a,其中 a[i] = np.array([[1], [0]]) 如果 s[i] == '0',否则为 np.array([[0], [1]])

所以我写了这样的代码:

a = np.empty([len(s), 2, 1])
for i, char in enumerate(s):
    if char == '0':
        a[i] = np.array([[1], [0]])
    elif char == '1':
        a[i] = np.array([[0], [1]])

能否以更麻木的方式将其重写为没有 for 循环的矢量化形式?

我的预期输出如下:

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

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

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

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

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

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

一个简单的方法是从字符串创建一个 list,然后通过指定 dtype=int:[=19= 将此列表转换为整数的 np.array ]

s = '001010'

a = np.array(list(s), dtype=int)
# array([0, 0, 1, 0, 1, 0])

然后用np.where根据a中的值在np.array([[1], [0]])np.array([[0], [1]])中select:

np.where(a==0, np.array([[1], [0]]), np.array([[0], [1]])).T[:,:,None]
array([[[1],
        [0]],

       [[1],
        [0]],

       [[0],
        [1]],

       [[1],
        [0]],

       [[0],
        [1]],

       [[1],
        [0]]])

方法 #1: 这是一个带有 NumPy 字符数组的方法 -

sa = np.frombuffer(s,dtype='S1')
out = np.where(sa[:,None,None]=='0',[[1],[0]],[[0],[1]])

方法 #2 : 多一个作为一行 -

((np.frombuffer(s,dtype=np.uint8)[:,None]==[48,49])[...,None]).astype(float)

方法 #3: 最后一个完全关注性能 -

a = np.zeros([len(s), 2, 1])
idx = np.frombuffer(s,dtype=np.uint8)-48
a[np.arange(len(idx)),idx] = 1

100000 个字符的字符串的计时 -

In [2]: np.random.seed(0)

In [3]: s = ''.join(map(str,np.random.randint(0,2,(100000)).tolist()))

# @yatu's soln
In [4]: %%timeit
     ...: a = np.array(list(s), dtype=int)
     ...: np.where(a==0, np.array([[1], [0]]), np.array([[0], [1]])).T[:,:,None]
10 loops, best of 3: 36.3 ms per loop

# App#1 from this post    
In [5]: %%timeit
     ...: sa = np.frombuffer(s,dtype='S1')
     ...: out = np.where(sa[:,None,None]=='0',[[1],[0]],[[0],[1]])
100 loops, best of 3: 3.56 ms per loop

# App#2 from this post    
In [6]: %timeit ((np.frombuffer(s,dtype=np.uint8)[:,None]==[48,49])[...,None]).astype(float)
1000 loops, best of 3: 1.81 ms per loop

# App#3 from this post    
In [7]: %%timeit
     ...: a = np.zeros([len(s), 2, 1])
     ...: idx = np.frombuffer(s,dtype=np.uint8)-48
     ...: a[np.arange(len(idx)),idx] = 1
1000 loops, best of 3: 1.81 ms per loop