Как быстро преобразовать строку типа '001100' в numpy.array([0,0,1,1,0,0])?

У меня строка состоит из 0 и 1, вроде '00101', И я хочу преобразовать его в массив NumPy numpy.array([0,0,1,0,1],

я использую for петля как:

import numpy as np
X = np.zeros((1,5),int)
S = '00101'
for i in xrange(5):
    X[0][i] = int(S[i])

Но так как у меня много строк и длина каждой строки равна 1024, этот путь очень медленный. Есть ли лучший способ сделать это?

5 ответов

Карта должна быть немного быстрее, чем список comp:

import  numpy as np

arr = np.array(map(int,'00101'))

Некоторые тайминги показывают, что это строка из 1024 символов:

In [12]: timeit np.array([int(c) for c in s])
1000 loops, best of 3: 422 µs per loop

In [13]: timeit np.array(map(int,s))
1000 loops, best of 3: 389 µs per loop

Просто вызов списка в s и использование dtype=int быстрее:

In [20]: timeit np.array(list(s), dtype=int)
1000 loops, best of 3: 329 µs per loop

Использование fromiter и передача dtype=int опять быстрее:

In [21]: timeit  np.fromiter(s,dtype=int)
1000 loops, best of 3: 289 µs per loop

Заимствование из этого ответа с использованием fromstring и uint8 в качестве dtype является самым быстрым:

In [54]: timeit  np.fromstring(s, 'int8') - 48
100000 loops, best of 3: 4.54 µs per loop

Даже повторное связывание имени и изменение dtype по-прежнему является самым быстрым:

In [71]: %%timeit
   ....: arr = np.fromstring(s, 'int8') - 48
   ....: arr = arr.astype(int)
   ....: 
100000 loops, best of 3: 6.23 µs per loop

Даже значительно быстрее, чем присоединение Ашвини:

In [76]: timeit  np.fromstring(' '.join(s), sep=' ', dtype=int)
10000 loops, best of 3: 62.6 µs per loop

Как прокомментировал @Unutbu,np.fromstring(s, 'int8') - 48 не ограничивается единицами и нулями, но будет работать для всех строк, состоящих из цифр ASCII.

Использование numpy.fromstring:

>>> s = '00101'
>>> np.fromstring(' '.join(s), sep=' ', dtype=int)
array([0, 0, 1, 0, 1])

>>> s = '00101' * 1000
>>> %timeit np.fromiter(s, dtype=int)
100 loops, best of 3: 2.33 ms per loop
>>> %timeit np.fromstring(' '.join(s), sep=' ', dtype=int)
1000 loops, best of 3: 499 µs per loop

Я думаю, что понимание списка будет быстрее, чем ваш обычный метод цикла -

import numpy as np

s = '00101'

np.array([int(c) for c in s])
array([0, 0, 1, 0, 1])

Сравнение времени с вашим методом (с длиной строки 1024) -

In [41]: S = '0' * 512 + '1' * 512

In [43]: %%timeit
   ....: X = np.zeros((1,len(S)),int)
   ....: for i in range(len(S)):
   ....:     X[0][i] = int(S[i])
   ....:
1000 loops, best of 3: 854 µs per loop

In [45]: %%timeit
   ....: Y = np.array([int(c) for c in S]).reshape((1,len(S)))
   ....:
1000 loops, best of 3: 339 µs per loop

Я сделал изменение формы, просто чтобы оба массива имели одинаковую форму, но я не думаю, что вам действительно нужно изменение формы, с пониманием списка форма массива, которую вы получите (<length of string> ,)

Как насчет использования метода fromstring?

np.fromstring('1, 2', dtype=int, sep=',')

Подробнее здесь

np.array(map(lambda x: int(x), s))

Другие вопросы по тегам