Объяснение различий между dim, shape, rank, размерностью и осью в numpy

Я новичок в python и numpy в целом. Я прочитал несколько руководств и все еще так запутался между различиями в тусклом, рядах, форме, аксиях и измерениях. Мой взгляд, похоже, застрял в матричном представлении. Поэтому, если вы говорите, что A – это матрица, которая выглядит так:

A = 1 2 3 4 5 6 

то все, что я могу представить, это матрица 2×3 (две строки и три столбца). Здесь я понимаю, что форма 2×3. Но я действительно не могу выходить за рамки двухмерных матриц. Я не понимаю, например, документацию dot (), когда он говорит: «Для N измерений это продукт суммы по последней оси а и второй-последний из b». Я так смущен и не могу это понять. Я не понимаю, что если V – вектор N: 1, а M – матрица N: N, то, как работают точка (V, M) или точка (M, V), и разница между ними.

Может ли кто-нибудь, пожалуйста, объяснить мне, что такое N мерный массив, какова форма, какая ось и как она связана с документацией функции dot ()? Было бы здорово, если бы объяснение визуализировало идеи.

Размерность массивов NumPy должна пониматься в смысле структуры данных , а не в математическом смысле, т. Е. Это число скалярных индексов, необходимое для получения скалярного значения. (*)

Например, это 3-й массив:

 >>> X = np.arange(24).reshape(2, 3, 4) >>> X array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]) 

Индексирование однажды дает 2-й массив (матрицу):

 >>> X[0] array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) 

Индексирование дважды дает 1-й массив (вектор), а индексирование три раза дает скаляр.

Рангом X является его число измерений:

 >>> X.ndim 3 >>> np.rank(X) 3 

Оси примерно синонимична размерности; он используется в вещательных операциях:

 >>> X.sum(axis=0) array([[12, 14, 16, 18], [20, 22, 24, 26], [28, 30, 32, 34]]) >>> X.sum(axis=1) array([[12, 15, 18, 21], [48, 51, 54, 57]]) >>> X.sum(axis=2) array([[ 6, 22, 38], [54, 70, 86]]) 

Честно говоря, я нахожу это определение «ранга» путаным, так как оно не соответствует ни имени атрибута ndim ни определению линейной алгебры ранга .

Теперь, касаясь np.dot , вы должны понимать, что существует три способа представления вектора в массиве NumPy: 1-d, вектор-столбец формы (n, 1) или вектор-строка формы (1, n) , (На самом деле, существует больше способов, например, как (1, n, 1) -образный массив, но они довольно редки.) np.dot выполняет векторное умножение, когда оба аргумента являются 1-d, умножением матрицы-вектора, когда один аргумент 1-й, а второй – 2-й, и в противном случае он выполняет (обобщенное) матричное умножение:

 >>> A = np.random.randn(2, 3) >>> v1d = np.random.randn(2) >>> np.dot(v1d, A) array([-0.29269547, -0.52215117, 0.478753 ]) >>> vrow = np.atleast_2d(v1d) >>> np.dot(vrow, A) array([[-0.29269547, -0.52215117, 0.478753 ]]) >>> vcol = vrow.T >>> np.dot(vcol, A) Traceback (most recent call last): File "<ipython-input-36-98949c6de990>", line 1, in <module> np.dot(vcol, A) ValueError: matrices are not aligned 

Правило «сумма продукта над последней осью a и второе-последнее из b » соответствует и обобщает общее определение матричного умножения.

(*) Массивы dtype=object являются немного исключением, так как они обрабатывают любой объект Python как скаляр.

np.dot является обобщением матричного умножения. При регулярном матричном умножении матрица (N, M) -образная матрица, умноженная на (M, P) -образную матрицу, приводит к (N, P) -образной матрице. Результирующую форму можно представить как образующуюся путем склеивания двух форм вместе ( (N,M,M,P) ), а затем удаления средних чисел, M (для получения (N,P) ). Это свойство, которое np.dot сохраняет при обобщении на массивы более высокой размерности.

Когда документы говорят,

«Для N измерений это суммирующий продукт по последней оси а и второй по последнему из Ь».

он говорит с этой точки зрения. Массив формы (u,v,M) усеянный массивом формы (w,x,y,M,z) приведет к массиву формы (u,v,w,x,y,z) .


Посмотрим, как выглядит это правило при применении к

 In [25]: V = np.arange(2); V Out[25]: array([0, 1]) In [26]: M = np.arange(4).reshape(2,2); M Out[26]: array([[0, 1], [2, 3]]) 

Во-первых, легкая часть:

 In [27]: np.dot(M, V) Out[27]: array([1, 3]) 

Здесь нет ничего удивительного; это просто умножение матрицы-вектора.

Теперь рассмотрим

 In [28]: np.dot(V, M) Out[28]: array([2, 3]) 

Посмотрите на форму V и M:

 In [29]: V.shape Out[29]: (2,) In [30]: M.shape Out[30]: (2, 2) 

Таким образом, np.dot(V,M) аналогично матричному умножению (2,) -образной матрицы с (2,2) -образной матрицей, что должно привести к (2,) -образной матрице.

Последняя (и единственная) ось V и вторая-вторая ось M (aka первая ось M ) умножаются и суммируются, оставляя только последнюю ось M

Если вы хотите визуализировать это: np.dot(V, M) выглядит так, как будто V имеет 1 строку и 2 столбца:

 [[0, 1]] * [[0, 1], [2, 3]] 

и поэтому, когда V умножается на M, np.dot(V, M) равно

 [[0*0 + 1*2], [2, [0*1 + 1*3]] = 3] 

Тем не менее, я действительно не рекомендую визуализировать массивы NumPy таким образом – по крайней мере, я никогда этого не делаю. Я сосредоточен почти исключительно на форме.

 (2,) * (2,2) \ / \ / (2,) 

Вы просто думаете о том, что «средние» оси пунктированы и исчезают из результирующей формы.


np.sum(arr, axis=0) сообщает NumPy суммировать элементы в arr исключающие 0-ю ось. Если arr является двумерным, 0-я ось – это строки. Так, например, если arr выглядит так:

 In [1]: arr = np.arange(6).reshape(2,3); arr Out[1]: array([[0, 1, 2], [3, 4, 5]]) 

то np.sum(arr, axis=0) будет суммировать вдоль столбцов, тем самым исключая 0-ю ось (т. е. строки).

 In [2]: np.sum(arr, axis=0) Out[2]: array([3, 5, 7]) 

3 – результат 0 + 3, 5 равно 1 + 4, 7 равно 2 + 5.

Обратите внимание, что arr имеет форму (2,3), и после суммирования 0-я ось удаляется, поэтому результат имеет форму (3). 0-я ось имела длину 2, и каждая сумма складывалась из добавления этих двух элементов. Форма (2,3) «становится» (3,). Вы можете знать результирующую форму заранее! Это может помочь вашему мышлению.

Чтобы проверить ваше понимание, рассмотрите np.sum(arr, axis=1) . Теперь ось 1 удалена. Таким образом, результирующая форма будет (2,) , а элементом в результате будет сумма 3 значений.

 In [3]: np.sum(arr, axis=1) Out[3]: array([ 3, 12]) 

3 равно 0 + 1 + 2, а 12 равно 3 + 4 + 5.


Таким образом, мы видим, что суммирование оси исключает эту ось из результата. Это имеет отношение к np.dot , так как вычисление, выполняемое np.dot является суммой произведений. Поскольку np.dot выполняет операцию суммирования вдоль определенных осей, эта ось удаляется из результата. Поэтому применение np.dot к массивам формы (2,) и (2,2) приводит к массиву формы (2). Первые 2 в обоих массивах суммируются, устраняя оба, оставляя только второй второй во втором массиве.

В твоем случае,

  1. A представляет собой 2D-массив, а именно матрицу, ее форма которой (2, 3). Из docstring numpy.matrix :

    Матрица представляет собой специализированный двухмерный массив, который сохраняет свою двумерную природу посредством операций.

  2. numpy.rank возвращает количество измерений массива, которое сильно отличается от понятия ранга в линейной алгебре , например, A является массивом размерности / ранга 2.

  3. np.dot(V, M) или V.dot(M) умножает матрицу V на M Обратите внимание, что numpy.dot делает умножение, насколько это возможно. Если V – N: 1, а M – N: N , то V.dot(M) повысит значение ValueError .

например:

 In [125]: a Out[125]: array([[1], [2]]) In [126]: b Out[126]: array([[2, 3], [1, 2]]) In [127]: a.dot(b) --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-127-9a1f5761fa9d> in <module>() ----> 1 a.dot(b) ValueError: objects are not aligned 

РЕДАКТИРОВАТЬ:

Я не понимаю разницы между Shape of (N,) и (N, 1) и относится к документации dot ().

V формы (N,) подразумевает 1D массив длины N, в то время как форма (N, 1) подразумевает 2D-массив с N строками, 1 столбец:

 In [2]: V = np.arange(2) In [3]: V.shape Out[3]: (2,) In [4]: Q = V[:, np.newaxis] In [5]: Q.shape Out[5]: (2, 1) In [6]: Q Out[6]: array([[0], [1]]) 

Как указано в docstring np.dot :

Для двумерных массивов это эквивалентно матричному умножению, а для 1-D массивов – скалярному произведению векторов (без комплексного сопряжения).

Он также выполняет векторно-матричное умножение, если один из параметров является вектором. Скажем V.shape==(2,); M.shape==(2,2) V.shape==(2,); M.shape==(2,2) :

 In [17]: V Out[17]: array([0, 1]) In [18]: M Out[18]: array([[2, 3], [4, 5]]) In [19]: np.dot(V, M) #treats V as a 1*N 2D array Out[19]: array([4, 5]) #note the result is a 1D array of shape (2,), not (1, 2) In [20]: np.dot(M, V) #treats V as a N*1 2D array Out[20]: array([3, 5]) #result is still a 1D array of shape (2,), not (2, 1) In [21]: Q #a 2D array of shape (2, 1) Out[21]: array([[0], [1]]) In [22]: np.dot(M, Q) #matrix multiplication Out[22]: array([[3], #gets a result of shape (2, 1) [5]])