Это вдохновляет сообщение this.numpy расширенное индексирование: прозрачная оптимизация диапазонов?
Рассмотрим функцию f
, которая возвращает 1d np.ndarray
idx
индексов, которые пользователь обычно будет использовать для индексации других массивов. Предположим далее, что частый результат для f
, чтобы вернуть весь спектр юридических показателей. В связанном сообщении предлагается, чтобы это было обжаловано по f
, возвращая slice(None)
вместо np.arange(maxind)
.
Поскольку расширенная индексация поставляется по цене
>>> a = np.arange(1_000_000)
>>> direct = lambda: np.sum(a[:])
>>> indirect = lambda: np.sum(a[a])
>>> timeit(direct, number=100)
0.07656216900795698
>>> timeit(indirect, number=100)
0.2885982050211169
это выглядит разумную оптимизация на первый взгляд.
К сожалению, это неправда. Представьте себе, например, что пользователь хочет создать одноразовое представление idx
. Один простой способ идти об это
result = np.zeros((k, maxind), dtype=int)
result[np.arange(k), idx] = 1
Это ломает, если np.arange(maxind)
замещен slice(None)
(Он заполнит весь result
с них).
Так что мой вопрос: Можно ли иметь свою торт и съесть его здесь, т.е .:
Есть ли что-нибудь f
может вернуться, что точно имитирует семантику np.arange(maxind)
, избегая при этом передовые индексации, где это возможно?
Поскольку я почти смирился с ответом является №:
Что следующая лучшая вещь?
Возможно, возвращен «улучшенный np.s_
», то есть объект с инженерным __getitem__
?
class smart_idx:
def __init__(self, n):
self.n = n
def __getitem__(self, idx):
idx = idx if isinstance(idx, tuple) else (idx,)
if idx:
count = idx.count('X')
need_adv = count > 1
if count == 1:
for i in idx:
if not isinstance(i, slice) and i != Ellipsis:
need_adv = True
break
repl = np.arange(self.n) if need_adv else slice(None)
return tuple(repl if i == 'X' else i for i in idx)
return slice(None)
Пользователь должен использовать его как
data[idx[3, 4:9, 'X', [1,3,2,6]]]
data[idx['X', ..., :4:-1]]
data[idx[]]
и __getitem__
, обнаруживая расширенный индекс будет принять решение о замене «X» с np.arange(4)
в первом и slice(None)
в двух других примерах.
Но это довольно неуклюжий, не говоря уже о том, что дополнительные накладные расходы могут съесть любую скорость, которую мы получили.
Существуют ли более простые стратегии?
Если 'idx' это список/массив вы собираетесь получить передовые индексации, независимо от того, используете ли вы срез или изменение для другого индекса. В индексировании '[arange ..., idx]' он выбирает один элемент из каждой строки. Индексирование на сплющенном массиве происходит быстрее, но уравновешивается стоимостью вычисления плоского индекса. – hpaulj
@hpaulj «Если idx - это список/массив, вы получите расширенную индексацию, независимо от». Вот почему мы пытаемся заменить «idx» на «slice (None)» в особых случаях, когда это имеет смысл (в основном «idx == np.arange (maxind)» + никаких других расширенных индексов). –
Что @hpaulj пытался сказать, что независимо от того, что такое 'idx', когда вы индексируете произвольные позиции в> 1D (2D в вашем примере), например. '[something ..., idx]' это расширенная индексация, независимо от того, что может быть idx, если только 'something' и' idx' являются объектами 'slice', но этот случай никогда не будет имитировать ваше желаемое поведение. –