Первый шаг построения модели: основа NumPy, которую вам нужно просмотреть, находится здесь.

искусственный интеллект Python PyTorch NumPy

из Нампи,Составлено Heart of the Machine.

NumPy — это библиотека для научных вычислений, предоставляющая высокопроизводительные векторные, матричные и многомерные структуры данных для Python. Он реализован на C и Fortran, поэтому очень быстро строит уравнения с векторами и матрицами и выполняет численные вычисления. NumPy в основном является основой всех фреймворков и пакетов, использующих Python для числовых вычислений, таких как TensorFlow и PyTorch.Самое основное содержание создания моделей машинного обучения — научиться использовать NumPy для построения вычислительных процессов.


Базовые знания

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

Например, координатная точка [1, 2, 1] имеет ось. На этой оси 3 точки, поэтому мы говорим, что ее длина равна 3. Следующий массив (массив) имеет 2 оси, а длина тоже 3.

[[ 1., 0., 0.],
[ 0., 1., 2.]]

Класс массива NumPy называется ndarray, и мы часто называем его массивом. Обратите внимание, что numpy.array отличается от класса array.array в стандартной библиотеке Python. Класс array.array в стандартной библиотеке Python обрабатывает только одномерные массивы и предоставляет небольшую функциональность. ndarray также имеет много важных свойств:

  • ndarray.ndim: отображает количество осей (или измерений) массива.
  • ndarray.shape: отображает размер массива в каждом измерении. Например, матрица с n строками и m столбцами имеет форму (n,m).
>>> b = np.array([[1,2,3],[4,5,6]])
>>> b.shape
(2, 3)
  • ndarray.size: общее количество всех элементов в массиве, что эквивалентно произведению всех элементов в форме массива.Например, общее количество элементов в матрице является произведением строк и столбцов .
>>> b = np.array([[1,2,3],[4,5,6]])
>>> b.size
6
  • ndarray.dtype: отображает тип элементов массива. Стандартная функция типа в Python также может использоваться для отображения типа массивов.NumPy имеет свои собственные типы, такие как: numpy.int32, numpy.int16 и numpy.float64, где «int» и «float» представляют тип массива. данные представляют собой целые числа или числа с плавающей запятой, «32» и «16» представляют количество байтов (размер хранилища) этого массива.
  • ndarray.itemsize: Размер хранения каждого элемента массива в байтах. Например, массив с типом элемента float64 имеет размер элемента 8 (= 64/8).
>>> import numpy as np
>>> a = np.arange(15).reshape(3, 5)
>>> a
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
>>> a.shape
(3, 5)
>>> a.ndim
2
>>> a.dtype.name
'int64'
>>> a.itemsize
8
>>> a.size
15
>>> type(a)
<type 'numpy.ndarray'>
>>> b = np.array([6, 7, 8])
>>> b
array([6, 7, 8])
>>> type(b)
<type 'numpy.ndarray'>


создать массив

У NumPy есть много способов создания массивов. Например, вы можете использовать список Python (список) для создания массива NumPy, где результирующие элементы массива имеют тот же тип, что и исходная последовательность.

>>> import numpy as np
>>> a = np.array([2,3,4])
>>> a
array([2, 3, 4])
>>> a.dtype
dtype('int64')
>>> b = np.array([1.2, 3.5, 5.1])
>>> b.dtype
dtype('float64')

Распространенной ошибкой является вызов массива с несколькими числовыми аргументами, и правильный способ — использовать «[]» для определения списка значений в качестве аргумента массива.

>>> a = np.array(1,2,3,4)    # WRONG
>>> a = np.array([1,2,3,4])  # RIGHT

array преобразует последовательность последовательностей в двумерный массив, последовательность последовательностей последовательностей в трехмерный массив и так далее.

>>> b = np.array([(1.5,2,3), (4,5,6)])
>>> b
array([[ 1.5,  2. ,  3. ],
       [ 4. ,  5. ,  6. ]])

Тип массива также можно указать во время создания:

>>> b = np.array([(1.5,2,3), (4,5,6)])
>>> c = np.array( [ [1,2], [3,4] ], dtype=complex )
>>> c
array([[ 1.+0.j,  2.+0.j],
       [ 3.+0.j,  4.+0.j]])

Внутренний элемент общего массива изначально неизвестен, но известен его размер. Поэтому NumPy предоставляет некоторые функции для создания массивов-заполнителей с начальными значениями, которые могут уменьшить ненужный рост массива и вычислительные затраты.

Нули функции могут создать массив со всеми 0 внутри, функциональные единицы могут создать массив со всеми 1 внутри, а функция empty может создать массив с начальными элементами случайных чисел, в зависимости от состояния памяти. По умолчанию тип данных (dtype) создаваемого массива обычно float64.

>>> np.zeros( (3,4) )
array([[ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])
>>> np.ones( (2,3,4), dtype=np.int16 )   # dtype can also be specified
array([[[ 1, 1, 1, 1],
        [ 1, 1, 1, 1],
        [ 1, 1, 1, 1]],
       [[ 1, 1, 1, 1],
        [ 1, 1, 1, 1],
        [ 1, 1, 1, 1]]], dtype=int16)
>>> np.empty( (2,3) )                    # uninitialized, output may vary
array([[  3.73603959e-262,   6.02658058e-154,   6.55490914e-260],
       [  5.30498948e-313,   3.14673309e-307,   1.00000000e+000]])

Для создания массивов NumPy предоставляет функцию, аналогичную диапазону для создания массивов: arange.

>>> np.arange( 10, 30, 5 )
array([10, 15, 20, 25])
>>> np.arange( 0, 2, 0.3 )                 # it accepts float arguments
array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8])

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

>>> from numpy import pi
>>> np.linspace( 0, 2, 9 )                 # 9 numbers from 0 to 2
array([ 0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,  1.5 ,  1.75,  2.  ])
>>> x = np.linspace( 0, 2*pi, 100 )        # useful to evaluate function at lots of points
>>> f = np.sin(x)

массив, нули, нули_подобные, единицы, единицы_подобные, пустые, пустые_подобные, arange, linspace, numpy.random.rand, numpy.random.randn, fromfunction, fromfile (эти функции также могут создавать массивы, попробуйте объяснить, когда у вас будет время)


выходной массив

Когда вы выводите массив, NumPy отображает массив аналогично вложенным спискам. Но вывод массива на экран должен соответствовать следующему макету:

  • Последняя ось печатается слева направо
  • Предпоследняя ось печатается сверху вниз
  • Остальные оси печатаются сверху вниз, при этом каждый блок отделяется пустой строкой.

Как показано ниже, результатом одномерного массива является строка, двумерного массива — матрица, а трехмерного массива — список матриц.

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

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

>>> print(np.arange(10000))
[   0    1    2 ..., 9997 9998 9999]
>>>
>>> print(np.arange(10000).reshape(100,100))
[[   0    1    2 ...,   97   98   99]
 [ 100  101  102 ...,  197  198  199]
 [ 200  201  202 ...,  297  298  299]
 ...,
 [9700 9701 9702 ..., 9797 9798 9799]
 [9800 9801 9802 ..., 9897 9898 9899]
 [9900 9901 9902 ..., 9997 9998 9999]]

Если вы хотите, чтобы NumPy выводил весь массив, вы можете использовать set_printoptions для изменения настроек вывода.

>>> np.set_printoptions(threshold=np.nan)


Основные операции

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

>>> a = np.array( [20,30,40,50] )
>>> b = np.arange( 4 )
>>> b
array([0, 1, 2, 3])
>>> c = a-b
>>> c
array([20, 29, 38, 47])
>>> b**2
array([0, 1, 4, 9])
>>> 10*np.sin(a)
array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])
>>> a<35
array([ True, True, False, False])

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

>>> A = np.array( [[1,1],
...             [0,1]] )
>>> B = np.array( [[2,0],
...             [3,4]] )
>>> A*B                         # elementwise product
array([[2, 0],
       [0, 4]])
>>> A.dot(B)                    # matrix product
array([[5, 4],
       [3, 4]])
>>> np.dot(A, B)                # another matrix product
array([[5, 4],
       [3, 4]])

Есть некоторые операции, такие как += и *=, выходные данные которых изменяют существующий массив, а не создают новый массив, как описано выше.

>>> a = np.ones((2,3), dtype=int)
>>> b = np.random.random((2,3))
>>> a *= 3
>>> a
array([[3, 3, 3],
       [3, 3, 3]])
>>> b += a
>>> b
array([[ 3.417022  ,  3.72032449,  3.00011437],
       [ 3.30233257,  3.14675589,  3.09233859]])
>>> a += b                  # b is not automatically converted to integer type
Traceback (most recent call last):
  ...
TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind'

При манипулировании массивами данных разных типов окончательный тип выходного массива обычно совпадает с более общим или точным массивом (такое поведение называется Upcasting).

>>> a = np.ones(3, dtype=np.int32)
>>> b = np.linspace(0,pi,3)
>>> b.dtype.name
'float64'
>>> c = a+b
>>> c
array([ 1.        ,  2.57079633,  4.14159265])
>>> c.dtype.name
'float64'
>>> d = np.exp(c*1j)
>>> d
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
       -0.54030231-0.84147098j])
>>> d.dtype.name
'complex128'

Многие унарные операции, такие как вычисление суммы всех элементов массива, являются методами класса ndarray.

>>> a = np.random.random((2,3))
>>> a
array([[ 0.18626021,  0.34556073,  0.39676747],
       [ 0.53881673,  0.41919451,  0.6852195 ]])
>>> a.sum()
2.5718191614547998
>>> a.min()
0.1862602113776709
>>> a.max()
0.6852195003967595

По умолчанию эти операции обрабатывают массив как последовательность независимо от его формы. Однако, если вы укажете параметр оси, вы можете указать, с каким измерением работать. Следующая ось = 0 будет работать с каждым столбцом, например, b.sum (ось = 0) добавит все элементы каждого столбца в матрицу b в виде скаляра.

>>> b = np.arange(12).reshape(3,4)
>>> b
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> b.sum(axis=0)                            # sum of each column
array([12, 15, 18, 21])
>>>
>>> b.min(axis=1)                            # min of each row
array([0, 4, 8])
>>>
>>> b.cumsum(axis=1)                         # cumulative sum along each row
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])


Индексация, усечение и итерация

Одномерные массивы можно индексировать, нарезать и повторять, как списки и кортежи Python. Обратите внимание, что a[0:6:2] представляет элементы с 1-го по 6-й и работает со вторым элементом каждых двух.

>>> a = np.arange(10)**3
>>> a
array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])
>>> a[2]
8
>>> a[2:5]
array([ 8, 27, 64])
>>> a[:6:2] = -1000    # equivalent to a[0:6:2] = -1000; from start to position 6, exclusive, set every 2nd element to -1000
>>> a
array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   729])
>>> a[ : :-1]                                 # reversed a
array([  729,   512,   343,   216,   125, -1000,    27, -1000,     1, -1000])
>>> for i in a:
...     print(i**(1/3.))
...
nan
1.0
nan
3.0
nan
5.0
6.0
7.0
8.0
9.0

Многомерные массивы могут иметь один индекс на ось. Эти индексы разделены запятыми в кортеже:

>>> def f(x,y):
...     return 10*x+y
...
>>> b = np.fromfunction(f,(5,4),dtype=int)
>>> b
array([[ 0,  1,  2,  3],
       [10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33],
       [40, 41, 42, 43]])
>>> b[2,3]
23
>>> b[0:5, 1]                       # each row in the second column of b
array([ 1, 11, 21, 31, 41])
>>> b[ : ,1]                        # equivalent to the previous example
array([ 1, 11, 21, 31, 41])
>>> b[1:3, : ]                      # each column in the second and third row of b
array([[10, 11, 12, 13],
       [20, 21, 22, 23]])

Если в некоторых измерениях не указан индекс, пустое измерение по умолчанию принимает все элементы.

>>> b[-1]                                  # the last row. Equivalent to b[-1,:]
array([40, 41, 42, 43])

Как и выше, поскольку второе измерение опущено, b[i] означает вывод i-й строки. Конечно, мы также можем использовать «:» для обозначения пропущенных размеров, например, b[i] эквивалентно b[i, :]. Кроме того, NumPy позволяет точкам (...) представлять достаточное количество двоеточий для построения полного кортежа индекса.

Например, если x представляет собой 5-мерный массив:

  • х[1,2,...] равно х[1,2,:,:,:],
  • х[...,3] равно х[:,:,:,:,3]
  • x[4,...,5,:] равно x[4,:,:,5,:]
>>> c = np.array( [[[  0,  1,  2],               # a 3D array (two stacked 2D arrays)
...                 [ 10, 12, 13]],
...                [[100,101,102],
...                 [110,112,113]]])
>>> c.shape
(2, 2, 3)
>>> c[1,...]                                   # same as c[1,:,:] or c[1]
array([[100, 101, 102],
       [110, 112, 113]])
>>> c[...,2]                                   # same as c[:,:,2]
array([[  2,  13],
       [102, 113]])

Итерация в многомерном массиве выполняется со ссылкой на первую ось, и каждый цикл выводит b[i] следующим образом:

>>> for row in b:
...     print(row)
...
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]

Однако, если вы хотите работать с каждым элементом массива, вы можете использовать плоский метод. flat — это итератор, который работает со всеми элементами массива, следующий будет работать с элементом массива поэлементно.

>>> for element in b.flat:
...     print(element)
...
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43

Преобразование формы

изменить форму массива

Форма массива определяется осью и количеством элементов.Обычно он представляется кортежем целых чисел, а целые числа в кортеже представляют количество элементов в соответствующем измерении.

>>> a = np.floor(10*np.random.random((3,4)))
>>> a
array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]])
>>> a.shape
(3, 4)

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

>>> a.ravel()  # returns the array, flattened
array([ 2.,  8.,  0.,  6.,  4.,  5.,  1.,  1.,  8.,  9.,  3.,  6.])
>>> a.reshape(6,2)  # returns the array with a modified shape
array([[ 2.,  8.],
       [ 0.,  6.],
       [ 4.,  5.],
       [ 1.,  1.],
       [ 8.,  9.],
       [ 3.,  6.]])
>>> a.T  # returns the array, transposed
array([[ 2.,  4.,  8.],
       [ 8.,  5.,  9.],
       [ 0.,  1.,  3.],
       [ 6.,  1.,  6.]])
>>> a.T.shape
(4, 3)
>>> a.shape
(3, 4)

И ravel(), и flatten() сводят многомерный массив к одному измерению, flatten() возвращает новый массив, и внесенные в него изменения не повлияют на исходный массив, а ravel() возвращает представление, которое повлияет на исходный массив. оригинальная матрица.

При транспонировании матрицы размеры строк и столбцов меняются местами, а каждый элемент матрицы трансформируется симметрично по главной диагонали. Кроме того, reshape возвращает новый массив с измененными размерами, как показано ниже, а метод resize напрямую изменит размеры самого исходного массива.

>>> a
array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]])
>>> a.resize((2,6))
>>> a
array([[ 2.,  8.,  0.,  6.,  4.,  5.],
       [ 1.,  1.,  8.,  9.,  3.,  6.]])

Если при преобразовании формы для измерения задано значение -1, то количество элементов, содержащихся в этом измерении, будет рассчитано автоматически. Как показано ниже, всего элементов a 12. Определив, что всего строк 3, -1 автоматически рассчитает, что для размещения всех элементов требуется 4 столбца.

>>> a.reshape(3,-1)
array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]])


укладка массива

Массивы могут быть сложены по разным осям. Как показано ниже, vstack объединит два массива вместе во втором измерении (по вертикали), а hstack объединит массивы вместе в первом измерении (по горизонтали).

>>> a = np.floor(10*np.random.random((2,2)))
>>> a
array([[ 8.,  8.],
       [ 0.,  0.]])
>>> b = np.floor(10*np.random.random((2,2)))
>>> b
array([[ 1.,  8.],
       [ 0.,  4.]])
>>> np.vstack((a,b))
array([[ 8.,  8.],
       [ 0.,  0.],
       [ 1.,  8.],
       [ 0.,  4.]])
>>> np.hstack((a,b))
array([[ 8.,  8.,  1.,  8.],
       [ 0.,  0.,  0.,  4.]])

Функция column_stack объединяет столбцы одномерного массива в двумерный массив и эквивалентна функции hstack для двумерного массива.

>>> from numpy import newaxis
>>> np.column_stack((a,b))     # with 2D arrays
array([[ 8.,  8.,  1.,  8.],
       [ 0.,  0.,  0.,  4.]])
>>> a = np.array([4.,2.])
>>> b = np.array([3.,8.])
>>> np.column_stack((a,b))     # returns a 2D array
array([[ 4., 3.],
       [ 2., 8.]])
>>> np.hstack((a,b))           # the result is different
array([ 4., 2., 3., 8.])
>>> a[:,newaxis]               # this allows to have a 2D columns vector
array([[ 4.],
       [ 2.]])
>>> np.column_stack((a[:,newaxis],b[:,newaxis]))
array([[ 4.,  3.],
       [ 2.,  8.]])
>>> np.hstack((a[:,newaxis],b[:,newaxis]))   # the result is the same
array([[ 4.,  3.],
       [ 2.,  8.]])

Как и функция column_stack, функция row_stack эквивалентна функции vstack в двумерном массиве. Как правило, в случае более двух измерений hstack складывается по второму измерению, vstack складывается по первому измерению, а конкатенация идет дальше и может складывать два массива в любом заданном измерении, конечно, для этого требуется, чтобы длина других измерений была равна . Concatenate применяется во многих глубоких моделях, таких как наложение весовых матриц или наложение карт объектов DenseNet.

В сложных случаях r_ и c_ могут эффективно помочь складывать значения вдоль оси при создании массивов, а также позволяют использовать итерацию диапазона «:» для генерации массивов.

>>> np.r_[1:4,0,4]
array([1, 2, 3, 0, 4])

Когда массив используется в качестве аргумента, r_ и c_ по умолчанию ведут себя как vstack и hstack, но, как и конкатенация, они позволяют задавать размеры, которые должны быть сложены.


разделенный массив

Используйте hsplit для разделения массива по горизонтальной оси, мы указываем количество массивов для вывода после разделения или указываем, по какому столбцу разделить массив:

>>> a = np.floor(10*np.random.random((2,12)))
>>> a
array([[ 9.,  5.,  6.,  3.,  6.,  8.,  0.,  7.,  9.,  7.,  2.,  7.],
       [ 1.,  4.,  9.,  2.,  2.,  1.,  0.,  6.,  2.,  2.,  4.,  0.]])
>>> np.hsplit(a,3)   # Split a into 3
[array([[ 9.,  5.,  6.,  3.],
       [ 1.,  4.,  9.,  2.]]), array([[ 6.,  8.,  0.,  7.],
       [ 2.,  1.,  0.,  6.]]), array([[ 9.,  7.,  2.,  7.],
       [ 2.,  2.,  4.,  0.]])]
>>> np.hsplit(a,(3,4))   # Split a after the third and the fourth column
[array([[ 9.,  5.,  6.],
       [ 1.,  4.,  9.]]), array([[ 3.],
       [ 2.]]), array([[ 6.,  8.,  0.,  7.,  9.,  7.,  2.,  7.],
       [ 2.,  1.,  0.,  6.,  2.,  2.,  4.,  0.]])]

vsplit разбивается по вертикальной оси, array_split указывает, по какой оси разбиваться.

Копировать и просматривать

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

на самом деле не копирует

Простые задачи не копируют объекты массива или их данные. Сначала присвойте переменную a переменной b следующим образом, а затем измените переменную b, чтобы одновременно изменить переменную a. Этот общий метод присваивания сделает переменные связанными.

>>> a = np.arange(12)
>>> b = a            # no new object is created
>>> b is a           # a and b are two names for the same ndarray object
True
>>> b.shape = 3,4    # changes the shape of a
>>> a.shape
(3, 4)

Python передает неопределенные объекты в качестве ссылок, поэтому вызов функции не изменяет целевой идентификатор и не происходит фактического копирования содержимого.

>>> def f(x):
...     print(id(x))
...
>>> id(a)                           # id is a unique identifier of an object
148293216
>>> f(a)
148293216

Просмотр или поверхностное копирование

Различные объекты массива могут совместно использовать одни и те же данные, а метод представления может создать новый объект массива для просмотра тех же данных. Целевые идентификаторы c и a ниже не согласованы, и изменение формы одной переменной не соответствует изменению другой. Но эти два массива имеют общие элементы, поэтому изменение элемента одного массива также изменит соответствующий элемент другого массива.

>>> c = a.view()
>>> c is a
False
>>> c.base is a                        # c is a view of the data owned by a
True
>>> c.flags.owndata
False
>>>
>>> c.shape = 2,6                      # a's shape doesn't change
>>> a.shape
(3, 4)
>>> c[0,4] = 1234                      # a's data changes
>>> a
array([[   0,    1,    2,    3],
       [1234,    5,    6,    7],
       [   8,    9,   10,   11]])

Результатом разделенного массива является одно из его представлений.Следующее делит массив a на подмассивы s, затем s является представлением a, и изменение элементов в s также изменит соответствующие элементы в a.

>>> s = a[ : , 1:3]     # spaces added for clarity; could also be written "s = a[:,1:3]"
>>> s[:] = 10           # s[:] is a view of s. Note the difference between s=10 and s[:]=10
>>> a
array([[   0,   10,   10,    3],
       [1234,   10,   10,    7],
       [   8,   10,   10,   11]])


глубокая копия

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

>>> d = a.copy()                          # a new array object with new data is created
>>> d is a
False
>>> d.base is a                           # d doesn't share anything with a
False
>>> d[0,0] = 9999
>>> a
array([[   0,   10,   10,    3],
       [1234,   10,   10,    7],
       [   8,   10,   10,   11]])

Глубокое понимание NumPy

широковещательный механизм

Широковещательные операции — очень важная функция NumPy, позволяющая NumPy расширять операции между матрицами. Например, он неявно корректирует аномальную размерность массива, чтобы она соответствовала размерности другого оператора для совместимости измерений. Например, допустимо добавить матрицу размерности [3,2] к другой матрице размерности [3,1], и NumPy автоматически расширит вторую матрицу до того же размера.

Чтобы определить, совместимы ли две фигуры, NumPy сравнивает их размеры одну за другой, начиная с конца и продвигаясь вперед. Во время этого процесса, если соответствующие размеры двух одинаковы или один (или оба) равен 1, сравнение продолжается до самого переднего измерения. Если эти два условия не выполняются, программа сообщит об ошибке.

Ниже показана широковещательная операция:

>>>a = np.array([1.0,2.0,3.0,4.0, 5.0, 6.0]).reshape(3,2)
>>>b = np.array([3.0])
>>>a * b

array([[  3.,   6.],
       [  9.,  12.],
       [ 15.,  18.]])


Расширенный указатель

NumPy предлагает больше способов индексации, чем обычные последовательности Python. В дополнение к ранее замеченной индексации с целыми числами и усечениями, массивы могут быть проиндексированы целочисленными массивами и булевыми массивами.


индексировать по массиву

Мы можем проиндексировать элементы в середине массива a в соответствии с массивами i и j следующим образом, где выходной массив содержит форму индекса.

>>> a = np.arange(12)**2                       # the first 12 square numbers
>>> i = np.array( [ 1,1,3,8,5 ] )              # an array of indices
>>> a[i]                                       # the elements of a at the positions i
array([ 1,  1,  9, 64, 25])

>>> j = np.array( [ [ 3, 4], [ 9, 7 ] ] )      # a bidimensional array of indices
>>> a[j]                                       # the same shape as j
array([[ 9, 16],
       [81, 49]])

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

>>> palette = np.array( [ [0,0,0],                # black
...                       [255,0,0],              # red
...                       [0,255,0],              # green
...                       [0,0,255],              # blue
...                       [255,255,255] ] )       # white
>>> image = np.array( [ [ 0, 1, 2, 0 ],           # each value corresponds to a color in the palette
...                     [ 0, 3, 4, 0 ]  ] )
>>> palette[image]                            # the (2,4,3) color image
array([[[  0,   0,   0],
        [255,   0,   0],
        [  0, 255,   0],
        [  0,   0,   0]],
       [[  0,   0,   0],
        [  0,   0, 255],
        [255, 255, 255],
        [  0,   0,   0]]])
       [81, 49]])

Мы также можем получить элементы в массиве, используя многомерное индексирование, каждое измерение многомерного индексирования должно иметь одинаковую форму. Следующие многомерные массивы i и j могут использоваться как параметры первого измерения и второго измерения в индексе a соответственно, например, a[i, j] извлекает элемент из i и j соответственно в качестве параметра элемента в индексе а.

>>> a = np.arange(12).reshape(3,4)
>>> a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> i = np.array( [ [0,1],                        # indices for the first dim of a
...                 [1,2] ] )
>>> j = np.array( [ [2,1],                        # indices for the second dim
...                 [3,3] ] )
>>>
>>> a[i,j]                                     # i and j must have equal shape
array([[ 2,  5],
       [ 7, 11]])
>>>
>>> a[i,2]
array([[ 2,  6],
       [ 6, 10]])
>>>
>>> a[:,j]                                     # i.e., a[ : , j]
array([[[ 2,  1],
        [ 3,  3]],
       [[ 6,  5],
        [ 7,  7]],
       [[10,  9],
        [11, 11]]])

Точно так же мы помещаем i и j в последовательность и используем ее как индекс:

>>> l = [i,j]
>>> a[l]                                       # equivalent to a[i,j]
array([[ 2,  5],
       [ 7, 11]])

Однако мы не можем поместить i и j в массив в качестве индекса, как указано выше, потому что массив будет интерпретироваться как индексирующий первое измерение a .

>>> s = np.array( [i,j] )
>>> a[s]                                       # not what we want
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IndexError: index (3) out of range (0<=index<=2) in dimension 0
>>>
>>> a[tuple(s)]                                # same as a[i,j]
array([[ 2,  5],
       [ 7, 11]])

Другой распространенный способ использования массива в качестве индекса — поиск максимального значения временного ряда:

>>> time = np.linspace(20, 145, 5)                 # time scale
>>> data = np.sin(np.arange(20)).reshape(5,4)      # 4 time-dependent series
>>> time
array([  20.  ,   51.25,   82.5 ,  113.75,  145.  ])
>>> data
array([[ 0.        ,  0.84147098,  0.90929743,  0.14112001],
       [-0.7568025 , -0.95892427, -0.2794155 ,  0.6569866 ],
       [ 0.98935825,  0.41211849, -0.54402111, -0.99999021],
       [-0.53657292,  0.42016704,  0.99060736,  0.65028784],
       [-0.28790332, -0.96139749, -0.75098725,  0.14987721]])
>>>
>>> ind = data.argmax(axis=0)                  # index of the maxima for each series
>>> ind
array([2, 0, 3, 1])
>>>
>>> time_max = time[ind]                       # times corresponding to the maxima
>>>
>>> data_max = data[ind, range(data.shape[1])] # => data[ind[0],0], data[ind[1],1]...
>>>
>>> time_max
array([  82.5 ,   20.  ,  113.75,   51.25])
>>> data_max
array([ 0.98935825,  0.84147098,  0.99060736,  0.6569866 ])
>>>
>>> np.all(data_max == data.max(axis=0))
True

Вы также можете использовать индекс массива в качестве цели распределения:

>>> a = np.arange(5)
>>> a
array([0, 1, 2, 3, 4])
>>> a[[1,3,4]] = 0
>>> a
array([0, 0, 2, 0, 0])

Однако если в списке индексов есть дубликаты, присваивание выполняется несколько раз и сохраняется последний результат.

>>> a = np.arange(5)
>>> a[[0,0,2]]=[1,2,3]
>>> a
array([2, 1, 3, 3, 4])

Это разумно, но обратите внимание, что если вы используете создание Python +=, это может не дать ожидаемого результата:

>>> a = np.arange(5)
>>> a[[0,0,2]]+=1
>>> a
array([1, 1, 3, 3, 4])

Хотя 0 встречается в списке индексов дважды, 0-й элемент увеличивается только один раз. Это потому, что «a+=1» в Python эквивалентно «a = a + 1».


индекс с логическим массивом

Когда мы индексируем элемент массива, мы предоставляем список индексов. Но булева индексация отличается, нам нужно четко выбрать, какой элемент в проиндексированном массиве нам нужен, а какой нет.

Логический индекс должен использовать массив логических значений той же формы, что и исходный массив.Следующее выводит True, только если оно больше 4, и полученный массив логических значений можно использовать в качестве индекса.

>>> a = np.arange(12).reshape(3,4)
>>> b = a > 4
>>> b                                          # b is a boolean with a's shape
array([[False, False, False, False],
       [False,  True,  True,  True],
       [ True,  True,  True,  True]])
>>> a[b]                                       # 1d array with the selected elements
array([ 5,  6,  7,  8,  9, 10, 11])

Это свойство очень полезно в задачах, например, в функции активации ReLu значение активации выводится только в том случае, если оно больше 0, поэтому мы можем использовать этот способ для реализации функции активации ReLU.

>>> a[b] = 0                                   # All elements of 'a' higher than 4 become 0
>>> a
array([[0, 1, 2, 3],
       [4, 0, 0, 0],
       [0, 0, 0, 0]])

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

>>> a = np.arange(12).reshape(3,4)
>>> b1 = np.array([False,True,True])             # first dim selection
>>> b2 = np.array([True,False,True,False])       # second dim selection
>>>
>>> a[b1,:]                                   # selecting rows
array([[ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> a[b1]                                     # same thing
array([[ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> a[:,b2]                                   # selecting columns
array([[ 0,  2],
       [ 4,  6],
       [ 8, 10]])
>>>
>>> a[b1,b2]                                  # a weird thing to do
array([ 4, 10])

Обратите внимание, что длина одномерного логического массива должна быть такой же, как длина оси, которую вы хотите перехватить. В приведенном выше примере b1 имеет длину 3, а b2 имеет длину 4, что соответствует первому и второму размеру a соответственно.


Линейная алгебра

простые операции с массивами

Ниже показаны только простые матричные операции, более подробные методы можно найти на практике при поиске API. Ниже показаны основные операции, такие как транспонирование матриц, инверсия, единичная матрица, умножение матриц, трассировка матрицы, решение линейных уравнений и нахождение собственных векторов:

>>> import numpy as np
>>> a = np.array([[1.0, 2.0], [3.0, 4.0]])
>>> print(a)
[[ 1.  2.]
 [ 3.  4.]]

>>> a.transpose()
array([[ 1.,  3.],
       [ 2.,  4.]])

>>> np.linalg.inv(a)
array([[-2. ,  1. ],
       [ 1.5, -0.5]])

>>> u = np.eye(2) # unit 2x2 matrix; "eye" represents "I"
>>> u
array([[ 1.,  0.],
       [ 0.,  1.]])
>>> j = np.array([[0.0, -1.0], [1.0, 0.0]])

>>> np.dot (j, j) # matrix product
array([[-1.,  0.],
       [ 0., -1.]])

>>> np.trace(u)  # trace
2.0

>>> y = np.array([[5.], [7.]])
>>> np.linalg.solve(a, y)
array([[-3.],
       [ 4.]])

>>> np.linalg.eig(j)
(array([ 0.+1.j,  0.-1.j]), array([[ 0.70710678+0.j        ,  0.70710678-0.j        ],
       [ 0.00000000-0.70710678j,  0.00000000+0.70710678j]]))

Parameters:
    square matrix
Returns
    The eigenvalues, each repeated according to its multiplicity.
    The normalized (unit "length") eigenvectors, such that the
    column ``v[:,i]`` is the eigenvector corresponding to the
    eigenvalue ``w[i]`` .

Ссылка на оригинальный документ:docs.last friend.org/doc/num py/U…