#python #arrays #numpy #slice #solver
#python #массивы #numpy #срез #решатель
Вопрос:
Я хочу знать, может ли следующая проблема быть обобщена на трехмерный массив и может быть выполнена с помощью нарезки и т. Д.:
Допустим, у меня есть массив x, который имеет размер (n, 2). Я настраиваю систему линейных уравнений, используя значения в массиве, и решаю следующим образом:
import numpy as np
def solve(x):
a_array = np.array([[16, -1], [-2, 1]])
b = np.array([x[-3, 0] - 16*x[-2, 0] 30*x[-1, 0], 1*x[-3, 0] - 2*x[-2, 0] - 0*x[-1, 0]])
u = np.linalg.solve(a_array, b)
c = np.array([x[-3, 1] - 16*x[-2, 1] 30*x[-1, 1], 1*x[-3, 1] - 2*x[-2, 1] - 0*x[-1, 1]])
v = np.linalg.solve(a_array, c)
total_uv = np.column_stack((u, v))
final_x = np.concatenate((x, total_uv))
return final_x
По сути, я решаю систему линейных уравнений (с двумя переменными) на основе значений в моем массиве x, чтобы получить (1,2) массивы u и v. Затем я складываю их вместе, чтобы получить общий массив (2,2) и объединить этот массив с моим исходным x. Теперь я получаю размер массива final_x (n 2, 2) по сравнению с исходным x.
Мой вопрос: допустим, что x, с которого я начинаю, теперь имеет размер (m, n, 2). Для каждого (n,2) массива (которых m) я хочу решить эту систему уравнений, чтобы получить мой массив total_uv. Затем я объединяю каждый массив total_uv с каждым (n,2) массивом (так что теперь вдоль оси = 1), поэтому мой конечный результат имеет размер (m, n 2,2).
Есть ли способ сделать это без использования циклов for (т. Е. перебора всех (n, 2) массивов и выполнения вычислений, их сохранения и последующего объединения)? Например, просто с помощью нотации среза или более элегантным способом в целом?
Похоже, что нарезка массива x (для получения переменных b и c) через x[:, -3, 0] ...
на самом деле не работает, потому что a_array имеет другой размер.
Уточнение решения для (m, n, 2):
def solve(x):
m = x.shape[0]
a_array = np.array([[16, -1], [-2, 1]])
b = np.stack((x[:, -3, 0] - 16*x[:, -2, 0] 30*x[:, -1, 0],
1*x[:, -3, 0] - 2*x[:, -2, 0] - 0*x[:, -1, 0]), axis=1)
u = np.linalg.solve(a_array[None, :, :], b)
c = np.stack((x[:, -3, 0] - 16*x[:, -2, 0] 30*x[:, -1, 0],
1*x[:, -3, 0] - 2*x[:, -2, 0] - 0*x[:, -1, 0]), axis=1)
v = np.linalg.solve(a_array[None, :, :], c)
# Concatenation here:
total_uv = np.column_stack((u, v))
uv_reshaped = total_uv.reshape((m, 2, 2))
final_x = np.concatenate((x, uv_reshaped), axis=1)
return final_x
Ответ №1:
Вы можете использовать нотацию среза для создания b
c
векторов и в виде двумерных массивов:
b = np.stack((x[:, -3, 0] - 16*x[:, -2, 0] 30*x[:, -1, 0],
1*x[:, -3, 0] - 2*x[:, -2, 0] - 0*x[:, -1, 0]), axis=1)
Затем вы можете добавить дополнительное (пакетное) измерение a_array
, чтобы использовать его с np.linalg.solve
:
u = np.linalg.solve(a_array[None, ...], b)
Кстати, поскольку ваши коэффициенты кажутся одинаковыми для b
и c
вы могли бы сделать то же самое здесь, устраняя необходимость в двух вызовах np.linalg.solve
:
bc = np.stack((x[:, -3] - 16*x[:, -2] 30*x[:, -1],
1*x[:, -3] - 2*x[:, -2] - 0*x[:, -1]), axis=2)
uv = np.linalg.solve(a_array[None, None, ...], bc)
Тогда у вас есть два пакетных измерения (n, 2)
, где второе представляет u / v.
Комментарии:
1. Просто чтобы уточнить: отражает ли напечатанное решение в моем отредактированном сообщении то, что вы пытались сказать? То есть,
u=np.linalg.solve(a_array[None, :, :], b)
это то, что вы имели в виду? Кроме того, здесь размер u и v будет (m, 2), где m — исходное измерение m во входном массиве (m, n, 2). Можете ли вы, не выполняя цикл for, получить массив u и v (2,2) для каждого m (например, как в моем исходном решении), а затем объединить его с каждым (n, 2) массивом, как в моем отредактированном решении?2. @user6496380 Я хотел сказать, что вам даже не нужны два отдельных вектора
b
,c
и поэтому вы можете сделать все это за один раз. Смотрите Конец моего ответа, используяbc
иuv
;uv
тогда это ваше решение.