2015-12-21 2 views
5

Показатели среза slice(start, stop[, step]) часто могут быть представлены range(start, stop, step) (или range(*slice(start, stop, step).indices(length)) при учете основных размеров).Ломтик, представляющий собой конкатенированные срезы

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

Пример:

import numpy as np 
data = np.random.rand(*(100, 100, 100)) 
a = data[::2, 7, :] # slice 1, a.shape = (50,100) 
b = a[1, ::-1] # slice 2, b.shape = (100,) 

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

c = data[2, 7, ::-1] # same as b 
np.array_equal(b, c) # True 

Таким образом, в получении от [::2, 7, :] и [1, ::-1] к [2, 7, ::-1] в этом примере я должен был бы такую ​​функцию:

def concatenate_slices(shape, outer_slice, inner_slice): 
    ... 
    return combined_slice 

где outer_slice и inner_slice бы оба кортежа ломтиков. В примере shape=(100, 100, 100) и outer_slice=(slice(None, None, 2), 7, slice(None, None, None)) и inner_slice=(1, slice(None, None, -1)).

Я не уверен, как это сделать эффективно.

Мои объекты что-то делают, когда __getitem__(slice) вызывается (нет промежуточных видов), и я хочу сделать это только один раз, но у вас есть возможность иметь кусочки срезов.

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

+2

только для справки: 'range (start, stop, step)' не всегда производит правильные индексы, так как он также может создавать индексы вне диапазона, чтобы создать допустимый диапазон ['slice.indices()'] (https://docs.python.org/3/reference/datamodel.html?highlight=slice.indices#slice.indices): 'range (* slice (start, stop, step) .indices (length)) '. Я не уверен, что можно комбинировать срезы, не принимая во внимание структуру базовой структуры. – mata

+0

@mata Спасибо. Ты прав. Также в моем случае я бы знал форму базовой структуры. Я немного отредактировал. – Trilarion

+0

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

ответ

1

Начнем с простого случая: 1-d массивов. Мы должны следить за start, stop и step значения для конечного среза, которую мы можем обновить следующим образом:

def update_1d(a, b, length): 
    a_start, a_stop, a_step = a.indices(length) 
    a_length = len(xrange(a_start, a_stop, a_step)) 
    if a_length == 0: 
    # doesn't matter what b is if data[a] is [] 
    return a 
    b_start, b_stop, b_step = b.indices(a_length) 
    b_length = len(xrange(b_start, b_stop, b_step)) 
    if b_length == 0: 
    # result will be empty, so we can exit early 
    return slice(0, 0, 1) 
    # convert b's start into a's coordinates, without wrapping around 
    start = max(0, a_start + b_start * a_step) 
    # steps are multiplicative, which makes things easy 
    step = a_step * b_step 
    # the stop index is the hard part because it depends on the sign of both steps 
    x = a_start + b_stop * a_step 
    if step < 0: 
    # indexing backwards, so truncate if b's converted step goes below zero 
    stop = x if x >= 0 else None 
    elif a_step > 0: 
    # both steps are positive, so take the smallest stop index 
    stop = min(a_stop, x) 
    else: 
    # both steps are negative, so take the largest stop index 
    stop = max(a_stop, x) 
    return slice(start, stop, step) 

Обратите внимание, что это ожидает a и b, чтобы быть ломтиками. Однако вы можете преобразовать другие формы в объекты среза. Это даже включает в себя объекты Ellipsis, предполагая, что вы знаете, сколько у вас размеров.

Чтобы распространить это на многомерный случай, нам нужно будет сделать некоторую бухгалтерскую отчетность, чтобы отслеживать, какое из исходных измерений нарезается. Например, если у вас есть data[::2, 7, :][:, 2:-2], вам нужно будет отобразить второе измерение второго фрагмента в третьем измерении первого фрагмента.

+0

Проверьте этот случай: 'a = slice (-1, 1, -2)', 'b = slice (0, -1, 1)', 'length = 16'. –

+0

Спасибо. Это уже хорошее начало. len (xrange()) должно быть неэффективным. Можно ли использовать пол ((стоп-старт)/шаг)? – Trilarion

+0

'len (xrange (...))' на самом деле довольно быстро, потому что объект 'xrange' делает по существу то же самое, что вы предложили, но в C-коде. Кроме того, Уоррен прав, код, который я написал, не работает для всех случаев. Оставайтесь с нами для лучшей версии в ближайшее время. – perimosocordiae

1

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

Для иллюстрации взять пример:

In [77]: shape=(100,100,100) 
In [78]: outer_slice=(slice(None, None, 2), 7, slice(None, None, None)) 
In [79]: inner_slice=(1, slice(None, None, -1)) 

Мишень является (правильно?):

(2, 7, slice(None,None,-1)) 

Первое измерение - сделать массив целого ряда показателей, и их нарезают последовательно:

In [80]: idx=np.arange(shape[0]) 
In [81]: idx[outer_slice[0]][inner_slice[0]] 
Out[81]: 2 

Могу ли я сделать вывод, что из [:: 2] и [1]? Я должен думать, что он начинается с 0, форма достаточно велика, чтобы получить второе значение и т. Д.

Теперь для второго измерения. Это скаляр, поэтому нет соответствующего inner фрагмента.

In [82]: outer_slice[1] 
Out[82]: 7 

Для третьего, давайте сделаем это так же, как с 1-го, но, принимая во внимание смещение между внешними и внутренними списками:

In [83]: idx=np.arange(shape[2]) 
In [84]: idx[outer_slice[2]][inner_slice[1]] 
Out[84]: 
array([99, 98, 97, 96, 95, 94, 93, 92, 91, ....7, 6, 5, 4, 3, 2, 1, 0]) 

Или я мог бы сделать вывод, что outer_slice[2] ничего не делает, поэтому я может использовать непосредственно inner_slice[1].

Конечно, было бы так же просто и эффективно применять два набора фрагментов к фактическому массиву.

X[outer_slice][inner_slice] 

Пока outer_slice производит вид, объединяя их в составной ломтик не так много улучшение.

С формой и кусочками кортежей достаточно информации для создания нового кортежа. Но, по-видимому, требуемая логика будет в полной мере задействована и потребует глубокого знания разрезания и множества тестов.

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