#python #numpy
#python #numpy
Вопрос:
Допустим, у меня есть массив:
x = np.array([7., 5., 4., 1., 9., 2., 3., 6.,])
Для каждого индекса я хочу найти argmin
справа от этого индекса, а также argmin слева от этого индекса. Конечные точки будут иметь значение argmin -1
, когда значение индекса недоступно, поэтому выходные данные будут:
left_argmins = [-1, 0, 1, 2, 3, 3, 3, 3]
right_argmins = [3, 3, 3, 5, 5, 6, 7, -1]
Наивный подход (но медленный подход) был бы:
right_argmins = np.full(len(x), -1)
for i in range(len(x)):
min_val = np.inf
idx = -1
for j in range(i 1, len(x)):
if x[j] < min_val:
min_val = x[j]
idx = j
right_argmins[i] = idx
left_argmins = np.full(len(x), -1)
for i in range(len(x)):
min_val = np.inf
idx = -1
for j in range(i):
if x[j] < min_val:
min_val = x[j]
idx = j
left_argmins[i] = idx
Каков наилучший способ добиться этого в NumPy?
Кроме того, что бы я сделал, если бы мне нужно было сделать это для 2D-массива?
Ответ №1:
Создайте матрицу с нижним треугольником бесконечности, затем используйте широковещательную передачу, чтобы она занимала по одному элементу вашего массива за раз. После этого простой argmin выполнит работу:
lower_tri = np.ones((len(x), len(x)))
lower_tri[np.tril(lower_tri, -1)==1] = float('inf')
lower_tri = lower_tri * x
np.argmin(lower_tri, axis=1)
приводит к
array([3, 3, 3, 3, 5, 5, 6, 7])
Для другого направления просто используйте вместо этого верхний треугольник:
upper_tri = np.ones((len(x), len(x)))
upper_tri[np.triu(upper_tri, 1)==1] = float('inf')
upper_tri = upper_tri * x
np.argmin(upper_tri, axis=1)
# array([0, 1, 2, 3, 3, 3, 3, 3])
затем вы можете добавлять или дополнять -1
по желанию.
но имейте в виду, что при этом используется O (n ^ 2) памяти, которая может иметь значение, x
является большой.
Ответ №2:
Вы можете накапливать индексы, которые приводят к уникальному массиву argsort
индексов, применяя оператор minimum:
argidx = np.argsort(x)
u, idx = np.unique(argidx, return_index=True)
left_argmins = argidx[np.minimum.accumulate(idx)]
right_argmins = argidx[np.minimum.accumulate(idx[::-1])][::-1]
Вывод:
left_argmins: [0, 1, 2, 3, 3, 3, 3, 3]
right_argmins: [3, 3, 3, 3, 5, 5, 6, 7]
Ответ №3:
Вы можете использовать индексацию, чтобы получить массивы только значений слева и справа от индекса, затем вызвать argmin
метод для этих массивов.
x = np.array([7., 5., 4., 1., 9., 2., 3., 6.,])
left_argmins = []
right_argmins = []
for i in range(len(x)):
to_left = x[:i]
if to_left.any():
left_argmins.append(to_left.argmin())
else:
left_argmins.append(-1)
to_right = x[i 1:]
if to_right.any():
right_argmins.append(to_right.argmin() (i 1))
else:
right_argmins.append(-1)