2016-11-30 2 views
2

Как эффективно разрезать массив в перекрывающихся подрешеток, так что дляфрагмент массива в отмененных перекрывающихся подмассивов

>>> N = 5 
>>> L = 2 # could be any, less than N 
>>> x = range(N) 

ожидаемый результат

[[1,0],[2,1],[3,2],[4,3]] 

Вот что я пытался:

>>> [ x[i:i-L:-1] for i in range(L-1,len(x)) ] 
[[], [3, 2], [4, 3], [5, 4]] # wrong 

>>> [ x[i:i-L:-1] for i in range(L,len(x)) ] 
[[2, 1], [3, 2], [4, 3]] # wrong 

>>> [ x[i:i-L if i-L >= 0 else None:-1] for i in range(L-1,len(x)) ] 
[[1, 0], [2, 1], [3, 2], [4, 3]] # correct 

Он производит желаемый результат, но лучший способ его достижения?

Есть несколько функций numpy, itertools, которые могут помочь?

+0

Итак, это входной список или массив NumPy? Является ли ожидаемый результат списком или массивом? В названии указано 'array', тогда как образец -' range (N) ', который создает список. – Divakar

+0

Спасибо, я ожидаю, что это будет тот, для которого лучшее решение существует. – tarashypka

ответ

1

Я предполагаю, что вход в виде массива NumPy. Итак, если это еще не так, мы могли бы использовать его как массив с np.asarray(). Таким образом, мы начнем с: x = np.asarray(input_list), если вход представляет собой список. Итак, с этим в качестве настройки давайте попробуем решить проблему.

Вот подход, использующий strides, который использует концепцию views, что позволяет избежать изготовления копий и как таковые должны быть очень эффективными -

L = 2 # Row length 
strided = np.lib.stride_tricks.as_strided 
n = x.strides[0] 
out = strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n)) 

Примеры пробеги -

In [85]: L = 2 

In [86]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n)) 
Out[86]: 
array([[1, 0], 
     [2, 1], 
     [3, 2], 
     [4, 3]]) 

In [87]: L = 3 

In [88]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n)) 
Out[88]: 
array([[2, 1, 0], 
     [3, 2, 1], 
     [4, 3, 2]]) 

In [89]: L = 4 

In [90]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n)) 
Out[90]: 
array([[3, 2, 1, 0], 
     [4, 3, 2, 1]]) 

Вот еще один подход с использованием broadcasting -

L = 2 # Row length 
out = x[np.arange(x.size-L+1)[:,None] + np.arange(L-1,-1,-1)] 
+1

Откуда взялось 'n'? – user2357112

+0

@ user2357112 Ах спасибо! Пропустил это раньше. – Divakar

1

Вы можете использовать простой список понимание

>>> [[x[i+1], x[i]] for i in range(len(x) - 1)] 
[[1, 0], [2, 1], [3, 2], [4, 3]] 

Или используйте itertools.izip:

>>> from itertools import izip 
>>> [list(k) for k in izip(x[1:], x)] 
[[1, 0], [2, 1], [3, 2], [4, 3]] 

Я вижу, что вы обновили вопрос, так вот общий itertools способ с использованием itertools.izip, itertools.islice и itertools.imap

>>> res = imap(lambda i:islice(reversed(x), i, i+L), xrange(N-L,-1,-1)) 
>>> [list(e) for e in res] 
[[1, 0], [2, 1], [3, 2], [4, 3]] 

Или даже чистые генераторы:

>>> res = (reversed(x[i:i+L]) for i in xrange(N-L+1)) 
>>> [list(e) for e in res] 
[[1, 0], [2, 1], [3, 2], [4, 3]] 
+0

Спасибо, вы предоставили простое и изящное решение для небольших подмассивов. Но как насчет случая 10-элементных подмассивов (также сдвинутых на 1 элемент)? Так что для 'x = range (100)' результат будет '[[9,8, .., 0], [10,9, .., 1], .., [99,98, .., 90]] '. – tarashypka

+0

Что-то вроде [[x [i + n-1, i, -1] для i в диапазоне (len (x) - n + 1)] должно работать, но я не могу проверить его atm, проверю, когда я вернусь домой –

1

Или с обычной молнией (производящей список кортежей)

In [158]: x=list(range(5)) 
In [159]: x[1:],x[0:-1] 
Out[159]: ([1, 2, 3, 4], [0, 1, 2, 3]) 
In [160]: list(zip(x[1:],x[0:-1])) 
Out[160]: [(1, 0), (2, 1), (3, 2), (4, 3)] 

или для списков

In [161]: [list(i) for i in zip(x[1:],x[0:-1])] 
Out[161]: [[1, 0], [2, 1], [3, 2], [4, 3]] 

Этого использование почтового индекса является своим родом транспонирования. numpy массивы также переставляет легко:

In [167]: arr=np.array((x[1:],x[:-1])) 
In [168]: arr 
Out[168]: 
array([[1, 2, 3, 4], 
     [0, 1, 2, 3]]) 
In [169]: arr.T.tolist() 
Out[169]: [[1, 0], [2, 1], [3, 2], [4, 3]] 

Обратите внимание, что я должен был сделать две копии списка. Подход Divakar stride_tricks является единственным способом создания перекрывающихся «окон» без копирования. Это более продвинутый метод.

Для небольших списков я предлагаю придерживаться списка подходов. Накладные расходы связаны с созданием массивов.

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