#python #numpy
#питон #numpy #python
Вопрос:
Допустим, у меня есть массив 3×3 a
и я хотел бы увеличить его до массива 30×30 b
с интерполяцией ближайшего соседа.
Можно ли использовать метод, который на самом деле не хранит повторяющиеся значения? Что-то похожее на то, как broadcasting
работает в numpy
.
например, я хотел бы иметь такой объект, чтобы при вызове b[x, x]
с 0 < x < 10
я получал a[0, 0]
.
Комментарии:
1. Я не думаю, что это возможно. У вас может быть массив (3,10,3,10), который является постоянным вдоль осей 1 и 3 и хранит только 9 значений.
Ответ №1:
Я не верю, что есть какой-либо способ сделать это с помощью numpy. Способ работы широковещательной передачи в numpy заключается в том, что каждая ось имеет параметр «stride», который управляет вычислением следующего элемента вдоль оси. Так, например:
In [1]: a = np.arange(10)
In [2]: a
Out[2]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [3]: b = a[::2]
In [4]: b
Out[4]: array([0, 2, 4, 6, 8])
In [5]: b.strides
Out[5]: (16,)
In [6]: a.strides
Out[6]: (8,)
В этом случае вы можете видеть, что b
— это просто вид a, полученный путем удвоения шага по первому измерению. Итак, при доступе b[1]
смещение вычисляется как b.__array_interface__['data'][0] b.strides[0]
.
В вашем случае вам, по сути, нужен нелинейный шаг, который не поддерживается.
Вы, конечно, могли бы добиться этого самостоятельно, самостоятельно вычисляя индексы, т. Е.:
a[x//10,x//10]
Комментарии:
1. Спасибо, я не знал о
strides
представлении. Считаете ли вы, что реализацияC
процедуры для выполнения разделения между двумя массивами разной формы, зацикливания на каждом элементе и последующего вызоваa[x//10, x//10]
может привести к аналогичной производительности по сравнению с простым разделением между двумя массивами одинаковой формы большего массива? например, сэкономит ли это память и время масштабирования?
Ответ №2:
Вы могли бы получить объект, подобный тому, который вы описываете, создав класс, который обертывает массив numpy и реализует пользовательский __getitem__
метод. Это может выглядеть примерно так, как показано ниже, где factor
— коэффициент, с которым вы хотите увеличить выборку.
class UpSampled:
__slots__ = ('arr', 'factor')
def __init__(self, arr, factor):
self.arr = arr
self.factor = factor
def __getitem__(self, key):
return self.arr[key // self.factor]
Затем вы бы использовали его, как показано ниже:
o = UpSampled(np.array([
UpSampled(np.array([0, 1, 2]), 10),
UpSampled(np.array([3, 4, 5]), 10),
UpSampled(np.array([6, 7, 8]), 10),
]), 10)
print(o[23][13]) # prints 7
Если вам нужно, чтобы объект был итерируемым, вы бы также реализовали __next__
и __iter__
:
class UpSampled:
__slots__ = ('arr', 'factor', '__index')
def __init__(self, arr, factor):
self.arr = arr
self.factor = factor
self.__index = 0
def __getitem__(self, key):
return self.arr[key // self.factor]
def __iter__(self):
self.__index = 0
return self
def __next__(self):
try:
result = self[self.__index]
except IndexError:
raise StopIteration
self.__index = 1
return result
Хотя я не уверен, что это будет хорошо работать с библиотеками, которые специально ожидают numpy-массив.
Комментарии:
1. Большое спасибо за предоставление этой хорошей реализации. Проблема в том, что в принципе то, что я хочу сделать, это то,
b/a
гдеa
shape фактически выполняется с увеличенной дискретизацией по требованию без сохранения, а затем с использованием векторизации numpy для математической операции. Что-то, что здесь не сработает. Мне нужно будет выполнить такую операцию с изображениями размером 10k x 10k, поэтому для повышения дискретизации и сохранения требуется время и память.