Numpy: разделить каждую строку на векторный элемент

119

Предположим, у меня есть массив numpy:

data = np.array([[1,1,1],[2,2,2],[3,3,3]])

и у меня есть соответствующий "вектор:"

vector = np.array([1,2,3])

Как мне действовать в dataкаждой строке, чтобы вычесть или разделить, чтобы результат был таким:

sub_result = [[0,0,0], [0,0,0], [0,0,0]]
div_result = [[1,1,1], [1,1,1], [1,1,1]]

Короче говоря: как мне выполнить операцию с каждой строкой 2D-массива с 1D-массивом скаляров, соответствующих каждой строке?

BFTM
источник

Ответы:

181

Ну вот. Вам просто нужно использовать None(или альтернативно np.newaxis) в сочетании с трансляцией:

In [6]: data - vector[:,None]
Out[6]:
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])

In [7]: data / vector[:,None]
Out[7]:
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]])
JoshAdel
источник
13
вот документ.
sazary 08
@ user108569 с использованием последней версии numpy (1.18.1) по- Noneпрежнему работает аналогично np.newaxis. Я не уверен, что это за настройка или какая именно проблема у вас возникла, но ответ все еще действителен.
ДжошАдель
11

Как уже упоминалось, нарезка с помощью Noneили с помощью np.newaxes- отличный способ сделать это. Другой альтернативой является использование транспонирования и трансляции, как в

(data.T - vector).T

и

(data.T / vector).T

Для массивов более высокой размерности вы можете использовать swapaxesметод массивов NumPy или rollaxisфункцию NumPy . Для этого действительно есть много способов.

Более полное объяснение вещания см. На http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html.

IanH
источник
4

Решение JoshAdel использует np.newaxis для добавления измерения. Альтернативой является использование reshape () для выравнивания размеров при подготовке к трансляции .

data = np.array([[1,1,1],[2,2,2],[3,3,3]])
vector = np.array([1,2,3])

data
# array([[1, 1, 1],
#        [2, 2, 2],
#        [3, 3, 3]])
vector
# array([1, 2, 3])

data.shape
# (3, 3)
vector.shape
# (3,)

data / vector.reshape((3,1))
# array([[1, 1, 1],
#        [1, 1, 1],
#        [1, 1, 1]])

Выполнение reshape () позволяет выровнять размеры для трансляции:

data:            3 x 3
vector:              3
vector reshaped: 3 x 1

Обратите внимание, что data/vectorэто нормально, но вы не получите того ответа, который вам нужен. Он делит каждый столбец из array(вместо каждой строки ) каждого соответствующего элемента vector. Это то , что вы получите , если вы явно изменили vectorбыть1x3 вместо 3x1.

data / vector
# array([[1, 0, 0],
#        [2, 1, 0],
#        [3, 1, 1]])
data / vector.reshape((1,3))
# array([[1, 0, 0],
#        [2, 1, 0],
#        [3, 1, 1]])
stackoverflowuser2010
источник
2

Питонический способ сделать это ...

np.divide(data.T,vector).T

Это позаботится о изменении формы, а также результаты будут в формате с плавающей запятой. В других ответах результаты представлены в формате округленных целых чисел.

# ПРИМЕЧАНИЕ: ни один столбец в данных и векторе не должен совпадать.

шантану патхак
источник
Примечание: это не делает то, что запрашивает OP. Конечным результатом является массив ([[1., 0.5, 0.33333333], [2., 1., 0.66666667], [3., 1.5, 1.]]). Это может быть «Pythonic», но это неверно.
Марк Крамер
1
@MarkCramer Спасибо. Я исправил свой ответ, чтобы получить правильный результат.
shantanu pathak
1

Добавляя к ответу stackoverflowuser2010, в общем случае вы можете просто использовать

data = np.array([[1,1,1],[2,2,2],[3,3,3]])

vector = np.array([1,2,3])

data / vector.reshape(-1,1)

Это превратит ваш вектор в column matrix/vector. Позволяет вам выполнять поэлементные операции по своему усмотрению. По крайней мере, для меня это наиболее интуитивно понятный способ решения этой проблемы, и поскольку (в большинстве случаев) numpy будет просто использовать представление той же внутренней памяти для изменения ее формы.

мяу
источник
Это должен быть принятый ответ. Создание вектора-столбца с помощью .reshape(-1,1) является наиболее интуитивно понятным способом использования широковещательной передачи.
Поль Руже,