Объединение и разделение массивов

На предыдущем занятии мы познакомились со способами изменения форм массивов. Здесь мы узнаем как реализуются операции объединения и разделения массивов. Для этой задачи в NumPy реализованы специальные функции, которые мы сейчас и рассмотрим.

Функции hstack и vstack

Предположим у нас есть два двумерных массива:

a = np.array([(1, 2), (3, 4)])
b = np.array([(5, 6), (7, 8)])

Их можно объединить как по горизонтали, так и по вертикали, с помощью функций:

np.hstack([a, b])  # объединение по оси axis1 (размерность 2x4)
np.vstack([a, b])  # объединение по оси axis0 (размерность 4x2)

Примеры работы этих двух функций представлены на рисунке ниже:

Эти же операции можно выполнять и с многомерными массивами. Например, определим два трехмерных массива:

a = np.fromiter(range(18), dtype='int32')
b = np.fromiter(range(18, 36), dtype='int32')
a.resize(3, 3, 2)
b.resize(3, 3, 2)

И выполним функции:

c = np.hstack([a, b])  # размерность 3x6x2
d = np.vstack([a, b])  # размерность 6x3x2

Как видите, здесь произошло формальное объединение по оси axis1 в функции hstack и по оси axis0 в функции vstack.

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

Аналогичным образом происходит объединение и одномерных массивов:

a = np.fromstring('1 2 3 4', sep = ' ')
b = np.fromstring('5 6 7 8', sep = ' ')

И при выполнении:

np.hstack([a, b])

получим:

array([1., 2., 3., 4., 5., 6., 7., 8.])

А во втором случае:

np.vstack([a, b])

результатом будет двумерный массив:

array([[1., 2., 3., 4.],

       [5., 6., 7., 8.]])

Функции column_stack и row_stack

Давайте теперь зададимся вопросом: как объединить наши два одномерных массива столбцами? Чтобы результат выглядел вот так:

Для этого хорошо подходит функция column_stack():

np.column_stack([a, b]) # формирование массива 4x2

Если с ее помощью объединять двумерные и многомерные массивы, то она будет давать тот же результат, что и функция hstack().

Другая аналогичная функция row_stack(), в принципе, делает то же самое, что и функция vstack() заметных отличий здесь нет. Ее можно использовать так:

np.row_stack([a, b]) # матрица 2x4

Функция concatenate

Для объединения массивов вдоль строго определенной оси можно воспользоваться функцией concatenate(). Например, возьмем два трехмерных массива:

a = np.arange(1, 13)
b = np.arange(13, 26)
a.resize(3, 3, 2)
b.resize(3, 3, 2)

И объединим их по каждой из осей:

c0 = np.concatenate([a, b], axis=0) # размерность 6x3x2
c1 = np.concatenate([a, b], axis=1) # размерность 3x6x2
c2 = np.concatenate([a, b], axis=2) # размерность 3x3x4

Объекты r_ и c_

Еще один способ объединения и создания массивов – это использование специальных объектов r_ и c_. Например, объект r_ создает копии массивов, следующими способами:

np.r_[ [1, 2, 3], 4, 5]  # список + дополнительные элементы
np.r_[ 1:9, 90, 100] # срез + два элемента
np.r_[ np.array([1,2,3]), np.array([4,5,6])] # объединение двух массивов
np.r_[ [(1,2,3), (4,5,6)], [(7,8,9)] ]  # объединение двумерного и одномерного списков

По аналогии работает и второй объект c_, только объединение выполняется по второй оси axis1:

np.c_[1:5]
np.c_[ [1, 2, 3], [4, 5, 6]]
np.c_[ [(1,2,3), (4,5,6)], [[7],[8]] ]

Разделение массивов

Массивы в NumPy можно не только объединять, но и разделять. Для этого существуют специальные функции hsplit и vsplit. Рассмотрим их работу на простых примерах. Пусть имеется одномерный массив из 10 элементов:

a = np.arange(10)

И мы хотим разделить его на две равные части. Это реализуется с помощью функции hsplit:

np.hsplit(a, 2)

которая возвращает список из двух массивов. Второй параметр 2 указывает число частей, на которые делится исходный массив. Причем, деление выполняется по горизонтали. Если в нашем примере указать 3 части, то возникнет ошибка:

np.hsplit(a, 3) # ошибка 10 на 3 нацело не делится

так как 10 элементов нельзя равномерно разбить на 3 части.

Также ошибка будет и при разбиении этого массива по вертикали:

np.vsplit(a, 2) # ошибка: нет вертикальной оси

так как массив имеет одну горизонтальную ось. Чтобы вторая функция сработала, преобразуем массив a в вектор столбец:

a.shape = 10, -1 # вектор-столбец

а, затем, разобьем по вертикали:

np.vsplit(a, 2)

На выходе получим два одномерных массива длиной 5 элементов.

Эти же функции можно использовать и с многомерными массивами, например, так:

a = np.arange(12)
a.resize(2, 6) # двумерный массив 2x6
 
np.hsplit(a, 2) # разбиение по горизонтали
np.vsplit(a, 2) # разбиение по вертикали

Функция array_split

Рассмотренные функции выполняют разбиение или по первой оси axis0 или по второй оси axis1. Но что если нам нужно выполнить разбиение по произвольной оси многомерного массива? Для этого существует функция array_split(). Ее работа аналогична рассмотренным выше функциям, только дополнительно указывается ось разбиения. Например:

a = np.arange(18)
a.resize(3, 3, 2)
 
np.array_split(a, 2, axis=2)
np.array_split(a, 3, axis=0)
np.array_split(a, 3, axis=1)