2015-12-14 2 views
0

У меня есть функция gen_data, которая сделает один проход через список и построит трехмерный массив. Затем я перебираю список списка, применяя функцию gen_data, а затем объединяю результаты вместе.Удалить numpy concat из algo

fst = lambda x: x[0] 
snd = lambda x: x[1] 

def gen_data(data,p=0, batch_size = BATCH_SIZE, n_session = N_SESSION, 
    x = np.zeros((batch_size,SEQ_LENGTH,vocab_size)) 
    y = np.zeros(batch_size) 

    for n in range(batch_size): 
     ptr = n 
     for i in range(SEQ_LENGTH): 
      x[n,i,char_to_ix[data[p+ptr+i]]] = 1. 
     if(return_target): 
      y[n] = char_to_ix[data[p+ptr+SEQ_LENGTH]] 
    return x, np.array(y,dtype='int32') 

def batch_data(data): 
    nest = [gen_data(datum) for datum in data] 
    x = np.concatenate(map(fst,nest)) 
    y = np.concatenate(map(snd,nest)) 
    return (x,y) 

Каков наилучший способ объединить эти функции, так что я не нужно, чтобы сделать несколько проходов назад через данные конкатенировать результаты?

Чтобы уточнить, цель была бы исключить необходимость в zip/concat/splat/list comp в целом. Чтобы иметь возможность инициализировать тензор x до правильных размеров, а затем перебирать каждую точку привязки/SEQ_LENGTH, batch_size за один проход.

+0

ли вы имеете в виду что-то вроде 'х, у = почтовый индекс (* гнездо) '? –

+0

Чтобы уточнить, целью было бы удалить необходимость в zip/concat/splat/list comp в целом. Чтобы иметь возможность инициализировать тензор x до правильных размеров, а затем перебирать каждую точку привязки/SEQ_LENGTH, batch_size за один проход. – user2726995

+0

Вы можете передавать представления глобальных массивов в 'gen_data'. – hpaulj

ответ

0

Без тестирования вещей, вот несколько быстрых решений:

def gen_data(data,p=0, batch_size = BATCH_SIZE, n_session = N_SESSION, 
    x = np.zeros((batch_size,SEQ_LENGTH,vocab_size)) 
    y = np.zeros(batch_size, dtype=int) # initial to desired type 

    for n in range(batch_size): 
     ptr = n 
     for i in range(SEQ_LENGTH): 
      x[n,i,char_to_ix[data[p+ptr+i]]] = 1. 
     if(return_target): 
      y[n] = char_to_ix[data[p+ptr+SEQ_LENGTH]] 
    return x, y 
    # y is already an array; don't need this: np.array(y,dtype='int32') 

nest = [gen_data(datum) for datum in data] производит, я думаю,

[(x0,y0), (x1,y1),...] где x является 3d (п, т, у), и y является 1d (n)

x = np.concatenate([n[0] for n in nest]) (Мне нравится этот формат для сопоставления). По сравнению со всеми операциями по составлению списка, concatenate относительно дешево. Посмотрите на кишки np.vstack и т. Д., Чтобы увидеть, как они используют понимание вместе с конкатенацией.

Небольшой пример:

In [515]: def gen(): 
    return np.arange(8).reshape(2,4),np.arange(1,3) 
    .....: 

In [516]: gen() 
Out[516]: 
(array([[0, 1, 2, 3], 
     [4, 5, 6, 7]]), array([1, 2])) 

In [517]: nest=[gen() for _ in range(3)] 

In [518]: nest 
Out[518]: 
[(array([[0, 1, 2, 3], 
     [4, 5, 6, 7]]), array([1, 2])), 
(array([[0, 1, 2, 3], 
     [4, 5, 6, 7]]), array([1, 2])), 
(array([[0, 1, 2, 3], 
     [4, 5, 6, 7]]), array([1, 2]))] 

In [519]: np.concatenate([x[0] for x in nest]) 
Out[519]: 
array([[0, 1, 2, 3], 
     [4, 5, 6, 7], 
     [0, 1, 2, 3], 
     [4, 5, 6, 7], 
     [0, 1, 2, 3], 
     [4, 5, 6, 7]]) 

In [520]: np.concatenate([x[1] for x in nest]) 
Out[520]: array([1, 2, 1, 2, 1, 2]) 

zip* эффективно делает 'tanspose' на вложенном списке, поэтому массивы могут быть построены с:

In [532]: nest1=zip(*nest) 

In [533]: np.concatenate(nest1[0]) 
Out[533]: 
array([[0, 1, 2, 3], 
     [4, 5, 6, 7], 
     [0, 1, 2, 3], 
     [4, 5, 6, 7], 
     [0, 1, 2, 3], 
     [4, 5, 6, 7]]) 

In [534]: np.concatenate(nest1[1]) 
Out[534]: array([1, 2, 1, 2, 1, 2]) 

Тем не менее требует Сцепляет.

Поскольку nest список кортежей, он может служить в качестве входных данных для структурированного массива:

In [524]: arr=np.array(nest,dtype=[('x','(2,4)int'),('y','(2,)int')]) 

In [525]: arr['x'] 
Out[525]: 
array([[[0, 1, 2, 3], 
     [4, 5, 6, 7]], 

     [[0, 1, 2, 3], 
     [4, 5, 6, 7]], 

     [[0, 1, 2, 3], 
     [4, 5, 6, 7]]]) 

In [526]: arr['y'] 
Out[526]: 
array([[1, 2], 
     [1, 2], 
     [1, 2]]) 

Другая возможность заключается в начальной x и y и итерацию. Но вы уже делаете это в gen_data. Единственное, что нового, это то, что я буду назначать большие блоки.

x = ... 
y = ... 
for i in range(...): 
    x[i,...], y[i] = gen(data[i]) 

Мне больше нравятся осмысленные решения, но я не буду спекулировать на скорости.

С точки зрения скорости, я думаю, что это итерация низкого уровня в gen_data, которая является потребителем времени. Конкатенирование больших блоков относительно быстро.


Еще одна идея - так как вы итерацию над рядами решеток в gen_data, как о переходе взгляды на эту функцию, и перебирать их.

def gen_data(data,x=None,y=None): 
    # accept array or make own 
    if x is None: 
     x = np.zeros((3,4),int) 
    if y is None: 
     y = np.zeros(3,int) 
    for n in range(3): 
     x[n,...] = np.arange(4)+n 
     y[n] = n 
    return x,y 

без каких-либо ресурсов, создавать массивы, как и раньше:

In [543]: gen_data(None) 
Out[543]: 
(array([[0, 1, 2, 3], 
     [1, 2, 3, 4], 
     [2, 3, 4, 5]]), 
array([0, 1, 2])) 

или парафировать пару, и перебирать просмотров:

In [544]: x,y = np.zeros((9,4),int),np.zeros(9,int) 

In [546]: for i in range(0,9,3): 
    .....:  gen_data(None,x[i:i+3,...],y[i:i+3]) 

In [547]: x 
Out[547]: 
array([[0, 1, 2, 3], 
     [1, 2, 3, 4], 
     [2, 3, 4, 5], 
     [0, 1, 2, 3], 
     [1, 2, 3, 4], 
     [2, 3, 4, 5], 
     [0, 1, 2, 3], 
     [1, 2, 3, 4], 
     [2, 3, 4, 5]]) 
In [548]: y 
Out[548]: array([0, 1, 2, 0, 1, 2, 0, 1, 2]) 
+0

Можно ли вообще отказаться от списка comp/concat и инициализировать x до np.zeros (batch_size * len (data))? – user2726995

+0

Предполагая, что 'gen_data' должен произвести этот набор массивов, я не вижу другого способа переупаковки получаемого списка кортежей. – hpaulj

+0

Я изложил альтернативу, в которой 'gen_data' присваивает значения непосредственно представлениям глобальных массивов. – hpaulj

Смежные вопросы