вычитание среднего значения каждой строки в numpy с трансляцией
Я пытаюсь вычесть среднее значение каждой строки матрицы в numpy с помощью широковещания, но я получаю ошибку. Есть идеи почему?
вот код:
from numpy import *
X = random.rand(5, 10)
Y = X - X.mean(axis = 1)
ошибка:
ValueError: operands could not be broadcast together with shapes (5,10) (5,)
спасибо!
2 ответов
на mean
метод сокращение операция, то есть она преобразует 1-d коллекцию чисел в одно число. Когда вы применяете уменьшение к N-мерному массиву вдоль оси, numpy сворачивает это измерение до уменьшенного значения, в результате чего получается (n-1)-мерный массив. В вашем случае, так как X
имеет форму (5, 10), и вы выполнили уменьшение вдоль оси 1, Вы получаете массив с формой (5,):
In [8]: m = X.mean(axis=1)
In [9]: m.shape
Out[9]: (5,)
при попытке вычитать этот результат от X
, вы пытаетесь вычесть массив с формой (5,) из массива с формой (5, 10). Эти формы не совместимы для вещания. (Взгляните на описание вещания в руководстве пользователя.)
для вещания работать так, как вы хотите, результат mean
операция должна быть массивом с формой (5, 1) (чтобы быть совместимой с формой (5, 10)). В последних версиях numpy сокращение операции, в том числе mean
, есть аргумент под названием keepdims
это говорит функции, чтобы не свернуть уменьшенное измерение. Вместо этого сохраняется тривиальное измерение с длиной 1:
In [10]: m = X.mean(axis=1, keepdims=True)
In [11]: m.shape
Out[11]: (5, 1)
С более старыми версиями numpy вы можете использовать reshape
для восстановления свернутого измерения:
In [12]: m = X.mean(axis=1).reshape(-1, 1)
In [13]: m.shape
Out[13]: (5, 1)
Итак, в зависимости от вашей версии numpy вы можете сделать следующее:
Y = X - X.mean(axis=1, keepdims=True)
или такой:
Y = X - X.mean(axis=1).reshape(-1, 1)
если вы ищете производительность, вы можете также использовать np.einsum
это предположительно быстрее, чем на самом деле с помощью np.sum
или np.mean
. Таким образом, желаемый результат может быть получен так -
X - np.einsum('ij->i',X)[:,None]/X.shape[1]
обратите внимание:[:,None]
часть похожа на keepdims
чтобы сохранить его размеры такими же, как у входного массива. Это может также использоваться в радиовещании.
во время выполнения тестов
1) Сравнение просто the mean
расчет -
In [47]: X = np.random.rand(500, 1000)
In [48]: %timeit X.mean(axis=1, keepdims=True)
1000 loops, best of 3: 1.5 ms per loop
In [49]: %timeit X.mean(axis=1).reshape(-1, 1)
1000 loops, best of 3: 1.52 ms per loop
In [50]: %timeit np.einsum('ij->i',X)[:,None]/X.shape[1]
1000 loops, best of 3: 832 µs per loop
2) Сравнение всего расчета -
In [52]: X = np.random.rand(500, 1000)
In [53]: %timeit X - X.mean(axis=1, keepdims=True)
100 loops, best of 3: 6.56 ms per loop
In [54]: %timeit X - X.mean(axis=1).reshape(-1, 1)
100 loops, best of 3: 6.54 ms per loop
In [55]: %timeit X - np.einsum('ij->i',X)[:,None]/X.shape[1]
100 loops, best of 3: 6.18 ms per loop