Numpy Array Slicing

У меня есть 1D NumPy массив, и некоторые значения смещения / длины. Я хотел бы извлечь из этого массива все записи, которые находятся в пределах смещения, смещения + длины, которые затем используются для создания нового «уменьшенного». массив из исходного, который состоит только из тех значений, которые выбраны парами смещение / длина.

Для одной пары смещение / длина это тривиально со стандартной нарезкой массива[offset:offset+length], Но как я могу сделать это эффективно (то есть без каких-либо петель) для многих значений смещения / длины?

Спасибо, отметка

 Mark16 июн. 2012 г., 10:50
да, смещение / длина - это массивы. Я не очень хочу разделить, так как я хочу иметь один 1D массив в конце. Поэтому мне понадобится объединение упомянутых вами частичных меньших массивов. но все без петель.
 Henry Gomersall16 июн. 2012 г., 10:40
Итак, в идеале, что бы вы в конечном итоге? 2D массив?
 Mark16 июн. 2012 г., 10:45
Нет, опять же с массивом 1D, который состоит только из значений, выбранных из исходного массива 1D на основе значений смещения / длины.
 Samy Vilar16 июн. 2012 г., 10:47
я беру этоoffset/lentgh values это какой-то массив или вы просто хотите разделить ваш массив на множество меньших массивов.

Ответы на вопрос(2)

>>> import numpy as np
>>> a = np.arange(100)
>>> ind = np.concatenate((np.arange(5),np.arange(10,15),np.arange(20,30,2),np.array([8])))
>>> a[[ind]]
array([ 0,  1,  2,  3,  4, 10, 11, 12, 13, 14, 20, 22, 24, 26, 28,  8])
 16 июн. 2012 г., 15:05
На заметку,np.r_ довольно хорошо для того, что вы делаете сconcatenate, Ваша длинная соединительная линия сокращается доind = np.r_[:5, 10:15, 20:30:2, 8]
Решение Вопроса

Есть наивный метод; просто делаю ломтики:

>>> import numpy as np
>>> a = np.arange(100)
>>> 
>>> offset_length = [(3,10),(50,3),(60,20),(95,1)]
>>>
>>> np.concatenate([a[offset:offset+length] for offset,length in offset_length])
array([ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 50, 51, 52, 60, 61, 62, 63,
       64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 95])

Следующиеmight Быстрее, но вам придется тестировать / тестировать.

Он работает путем составления списка желаемых индексов, который является допустимым методом индексации массива.

>>> indices = [offset + i for offset,length in offset_length for i in xrange(length)]
>>> a[indices]
array([ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 50, 51, 52, 60, 61, 62, 63,
       64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 95])

Не ясно, будет ли это на самом деле быстрее, чем простой метод, но это может быть, если у вас много очень коротких интервалов. Но я не знаю.

(Этот последний метод в основном совпадает с решением @ fraxel, просто использует другой метод создания списка индексов.)

Performance testing

Я тестировал несколько разных случаев: несколько коротких интервалов, несколько длинных интервалов, множество коротких интервалов. Я использовал следующий скрипт:

import timeit

setup = 'import numpy as np; a = np.arange(1000); offset_length = %s'

for title, ol in [('few short', '[(3,10),(50,3),(60,10),(95,1)]'),
                  ('few long', '[(3,100),(200,200),(600,300)]'),
                  ('many short', '[(2*x,1) for x in range(400)]')]:
  print '**',title,'**'
  print 'dbaupp 1st:', timeit.timeit('np.concatenate([a[offset:offset+length] for offset,length in offset_length])', setup % ol, number=10000)
  print 'dbaupp 2nd:', timeit.timeit('a[[offset + i for offset,length in offset_length for i in xrange(length)]]', setup % ol, number=10000)
  print '    fraxel:', timeit.timeit('a[np.concatenate([np.arange(offset,offset+length) for offset,length in offset_length])]', setup % ol, number=10000)

Это выводит:

** few short **
dbaupp 1st: 0.0474979877472
dbaupp 2nd: 0.190793991089
    fraxel: 0.128381967545
** few long **
dbaupp 1st: 0.0416231155396
dbaupp 2nd: 1.58000087738
    fraxel: 0.228138923645
** many short **
dbaupp 1st: 3.97210478783
dbaupp 2nd: 2.73584890366
    fraxel: 7.34302687645

Это говорит о том, что мой первый метод самый быстрый, когда у вас есть несколько интервалов (и он значительно быстрее), а мой второй самый быстрый, когда у вас много интервалов.

 16 июн. 2012 г., 10:58
@MarkVogelsberger, вы пытаетесь удалить цикл for по соображениям производительности? Если это так, вы должны проверить их (и fraxel 's), чтобы увидеть, достаточно ли они быстры, чтобы избежать ненужной микрооптимизации: только если ничего из этого не достаточно быстро, вам следует беспокоиться о полном удалении циклов for.
 Mark16 июн. 2012 г., 10:55
это то, что я ищу, но есть ли способ получить его без цикла for?
 16 июн. 2012 г., 11:30
@MarkVogelsberger, я добавил статистику эффективности в свой ответ.
 Mark16 июн. 2012 г., 11:02
да, это только для производительности.

Ваш ответ на вопрос