Урок курса

Объединение массивов: concatenate и stack

NumPy и pandas: практический тренажёр

Чем stack отличается от concatenate

np.concatenate соединяет массивы вдоль существующей оси. np.stack создаёт новую ось; входные массивы должны иметь одинаковую форму. Вот результат для двух векторов длины 2:

import numpy as np
a = np.array([1, 2])
b = np.array([3, 4])
print(np.concatenate([a, b]).tolist())
print(np.stack([a, b], axis=0).tolist())
print(np.stack([a, b], axis=1).tolist())

Результат:

[1, 2, 3, 4]
[[1, 2], [3, 4]]
[[1, 3], [2, 4]]

Формы результатов: (4,), (2, 2), (2, 2). При concatenate размеры должны совпадать по всем осям, кроме оси соединения. У одномерного массива есть только ось 0: для столбцов сначала создайте вторую ось либо используйте stack.

В предыдущих уроках мы работали с отдельными массивами: считали агрегаты, обнаруживали NaN, управляли формой. Теперь встаёт другой вопрос — как склеить несколько массивов в один. Именно здесь начинается работа с np.concatenate и np.stack.

np.concatenate: объединение по существующей оси

Когда нужно склеить несколько массивов в один, первый инструмент — np.concatenate. Его сигнатура выглядит так:

np.concatenate([arr1, arr2, ...], axis=k)

Параметр axis=k указывает, вдоль какой из уже существующих осей происходит «склейка». Ключевое слово здесь — существующей: concatenate не добавляет новых измерений, он только удлиняет массив по одной из тех осей, которые уже есть.

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

  • одинаковое число осей (одинаковый ndim);
  • совпадающие размеры по всем осям, кроме той, вдоль которой идёт склейка.

Правило для shape результата простое. Пусть все входные массивы имеют ndim=2, и мы склеиваем по оси 0. Тогда по оси 0 берём сумму размеров всех входных массивов; по оси 1 — размер остаётся тем же, что у каждого входного (они обязаны совпадать).

В общем виде: если склеиваем по оси k, то размер результата по оси k равен сумме соответствующих размеров входных массивов, а по всем остальным осям размер совпадает с размером входных.

Конкретно: два массива shape (2, 3) при axis=0 дают (4, 3), при axis=1 дают (2, 6). Это можно проверить ещё до запуска кода — сложить нужные цифры вручную.

Нарушение условий совместимости NumPy сразу сообщит ошибкой ValueError: all the input array dimensions except for the concatenation axis must match exactly. Это сигнал: посмотри на shape всех входных массивов и найди несовпадение.

Практика np.concatenate по осям 0 и 1

Посмотрим, как работает concatenate на конкретном коде. Возьмём два двумерных массива одинаковой формы:

import numpy as np

a = np.array([[1, 2, 3], [4, 5, 6]])    # shape (2, 3)
b = np.array([[7, 8, 9], [10, 11, 12]]) # shape (2, 3)

# Склеиваем по оси 0 — добавляем строки
r0 = np.concatenate([a, b], axis=0)
print(r0.shape)  # (4, 3)
print(r0)
# [[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]]

# Склеиваем по оси 1 — добавляем столбцы
r1 = np.concatenate([a, b], axis=1)
print(r1.shape)  # (2, 6)
print(r1)
# [[ 1  2  3  7  8  9]
#  [ 4  5  6 10 11 12]]

При axis=0 массивы встают друг под другом: строк стало 2+2=4, а три столбца остались. При axis=1 — встают рядом: строки те же две, а столбцов стало 3+3=6.

Одномерный случай немного отличается — у вектора только одна ось, поэтому axis=0 единственный вариант:

x = np.array([1, 2, 3])  # shape (3,)
y = np.array([4, 5])     # shape (2,)

result = np.concatenate([x, y], axis=0)
print(result.shape)  # (5,)
print(result)        # [1 2 3 4 5]

Обратите внимание: здесь x и y имеют разные длины, и это нормально — по единственной оси размеры суммируются, никаких дополнительных ограничений нет.

Главное, что стоит закрепить из этих примеров: shape результата всегда можно посчитать вручную ещё до запуска. Берёте shape входных массивов, в позиции оси k складываете числа, по остальным позициям оставляете как есть. Если цифры не сходятся — NumPy выдаст ValueError ещё до того, как что-то пойдёт не так в логике программы.

np.stack: создание новой оси и практика по разным позициям

np.stack решает другую задачу: он не удлиняет массив вдоль существующей оси, а создаёт новую ось и складывает массивы вдоль неё. Это единственное, но принципиальное отличие от concatenate.

Сигнатура:

np.stack([arr1, arr2, ...], axis=k)

Параметр axis=k теперь означает: на какую позицию в кортеже shape вставить новое измерение. После вставки размер по этой позиции будет равен числу сложенных массивов.

Жёсткое требование: все входные массивы должны иметь строго одинаковую shape. Не просто совпадать по одной оси — а быть идентичными по всем осям. Если хотя бы один массив отличается, NumPy выбросит ValueError.

Одномерный случай

Возьмём два вектора shape (3,):

import numpy as np

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

# Новая ось в позиции 0 — массивы становятся строками
s0 = np.stack([a, b], axis=0)
print(s0.shape)  # (2, 3)
print(s0)
# [[1, 2, 3],
#  [4, 5, 6]]

# Новая ось в позиции 1 — массивы становятся столбцами
s1 = np.stack([a, b], axis=1)
print(s1.shape)  # (3, 2)
print(s1)
# [[1, 4],
#  [2, 5],
#  [3, 6]]

При axis=0 два вектора длиной 3 превращаются в матрицу (2, 3): два — это число массивов, 3 — исходная длина. При axis=1 новая ось вставляется между существующей длиной и ничем: получаем (3, 2). Можно представить это как «каждый элемент вектора теперь имеет два значения — из a и из b».

Двумерный случай

Когда входные массивы двумерные, результат np.stack будет трёхмерным — новое измерение добавляется к уже существующим двум:

A = np.ones((3, 4))        # shape (3, 4)
B = np.ones((3, 4)) * 2   # shape (3, 4)

print(np.stack([A, B], axis=0).shape)  # (2, 3, 4)
print(np.stack([A, B], axis=1).shape)  # (3, 2, 4)
print(np.stack([A, B], axis=2).shape)  # (3, 4, 2)

Логика прямая: берёте исходный кортеж (3, 4) и вставляете 2 (число массивов) на позицию axis:

  • axis=0 → вставляем 2 перед 3, 4 → (2, 3, 4)
  • axis=1 → вставляем 2 между 3 и 4 → (3, 2, 4)
  • axis=2 → вставляем 2 после 3, 4 → (3, 4, 2)

Эта операция вставки — ключ к тому, как читать shape результата np.stack без запуска кода. Нужно знать: сколько массивов складываете и куда вставляете новое измерение.

Разница между concatenate и stack: алгоритм проверки shape

Оба инструмента объединяют массивы, но делают это принципиально по-разному. np.concatenate работает с уже существующими осями: число измерений результата совпадает с числом измерений входных массивов, а один из размеров увеличивается. np.stack создаёт новую ось: результат всегда имеет на одно измерение больше, чем входные.

Это различие хорошо видно на одномерных векторах:

  • np.concatenate([a, b], axis=0) для двух векторов shape (n,) даёт shape (2n,) — один длинный вектор.
  • np.stack([a, b], axis=0) для тех же векторов даёт shape (2, n) — матрицу из двух строк.

Результаты морфологически разные, хотя данные «те же самые».

Алгоритм предсказания shape для concatenate

Чтобы узнать shape результата до запуска кода, достаточно трёх шагов:

  1. Выпишите shape каждого входного массива.
  2. Убедитесь, что по всем осям, кроме k, размеры совпадают — иначе будет ValueError.
  3. По оси k сложите соответствующие размеры всех входных массивов; по остальным осям оставьте размер как есть.

Пример: массивы (2, 3) и (2, 3) при axis=0 → складываем первые числа: 2+2=4, второе остаётся 3 → результат (4, 3).

Алгоритм предсказания shape для stack

  1. Убедитесь, что все входные массивы имеют строго одинаковую shape.
  2. Возьмите исходный кортеж shape.
  3. Вставьте число массивов n в позицию k этого кортежа.

Пример: два массива (3, 4) при axis=1 → берём (3, 4), вставляем 2 на позицию 1 → (3, 2, 4).

Этот алгоритм работает для любого числа осей и любого числа складываемых массивов. Если складываете пять массивов shape (6, 7) через np.stack(axis=0), результат — (5, 6, 7): число массивов на нулевую позицию, исходная форма следом.

Главный практический вопрос при выборе между двумя функциями: нужно ли сохранить число осей или добавить новое измерение? Если нужно просто удлинить — concatenate. Если нужно «сложить в стопку» с сохранением структуры каждого массива — stack.

Закрепите тему на задачах

Сначала решите, нужна ли новая ось. concatenate объединяет вдоль существующей, stack создаёт новую. Выпишите итоговую shape до запуска.

NumPy stack: axis=0, 1 и 2 и форма результата

NumPy concatenate и stack: сравните ndim и shape

Откройте условие и решите задачу перед чтением следующей темы. В задачах на код проверяется программа, в тестовых заданиях — выбранный ответ. Для последовательного обучения вернитесь в программу бесплатного курса.

Задача 1

Даны два массива shape (3, 4). Какой shape будет у результата np.concatenate([a, b], axis=1)?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 2

Даны два массива shape (5,). Что вернёт np.stack([a, b], axis=0)?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 3

Даны массивы a и b одинаковой формы (2, 3). Какое выражение объединит их по оси 0 и добавит строки?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 4

np.concatenate по двум осям: предсказание и проверка shape

Что уже дано

Проверяющая система запускает вашу программу и подаёт данные через stdin. Никаких заранее созданных переменных нет — вы читаете всё сами.

Что нужно сделать

Напишите программу, которая:

  1. Читает из stdin четыре целых числа в одной строке: R, C, R2, C2.
  2. Создаёт два двумерных массива:
  • a = np.arange(R * C).reshape(R, C) — shape (R, C);
  • b = np.arange(R2 * C2).reshape(R2, C2) — shape (R2, C2).
  1. Если C == C2 — выполняет r0 = np.concatenate([a, b], axis=0) и выводит shape r0 в одну строку.
  2. Если R == R2 — выполняет r1 = np.concatenate([a, b], axis=1) и выводит shape r1 в следующую строку.
  3. Гарантируется, что выполнимо хотя бы одно условие; оба могут быть выполнимы одновременно — тогда выводятся обе строки в указанном порядке.

Каждую строку выводите в виде Python-кортежа, например (4, 3).

Ввод и вывод

Программа читает stdin и пишет в stdout.

Формат ввода

Одна строка: четыре целых числа R C R2 C2, разделённых пробелами.

Формат вывода

Одна или две строки. Если C == C2 — первой строкой shape результата np.concatenate([a, b], axis=0). Если R == R2 — следующей строкой shape результата np.concatenate([a, b], axis=1). Каждый shape — в виде Python-кортежа.

РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задача 5

np.stack по трём позициям оси: предсказание и проверка shape

Что уже дано

Проверяющая система запускает вашу программу и подаёт данные через stdin. Никаких заранее созданных переменных нет — вы читаете всё сами.

Что нужно сделать

Напишите программу, которая:

  1. Читает из stdin три целых числа в одной строке: R, C, n — число строк, столбцов и количество одинаковых двумерных массивов.
  2. Создаёт n двумерных массивов одинаковой формы (R, C), где i-й массив равен np.arange(i * R * C, (i + 1) * R * C).reshape(R, C) для i от 0 до n-1.
  3. Складывает все n массивов через np.stack с axis=0, затем с axis=1, затем с axis=2. Сохраняет результаты в переменные s0, s1, s2.
  4. Выводит в stdout три строки — shape каждого результата в виде Python-кортежа:
  • строка 1: shape s0;
  • строка 2: shape s1;
  • строка 3: shape s2.

Ввод и вывод

Программа читает stdin и пишет в stdout.

Формат ввода

Одна строка: три целых числа R C n, разделённых пробелами. Гарантируется R >= 2, C >= 2, n >= 2.

Формат вывода

Три строки. Каждая — shape соответствующего результата np.stack в виде Python-кортежа, например (3, 2, 4).

РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задача 6

concatenate vs stack на одномерных векторах: разница в ndim и shape

Что уже дано

Проверяющая система запускает вашу программу и подаёт данные через stdin. Никаких заранее созданных переменных нет — вы читаете всё сами.

Что нужно сделать

Напишите программу, которая наглядно показывает разницу между np.concatenate и np.stack на одномерных массивах:

  1. Читает из stdin одну строку с двумя целыми числами: n и k — длина каждого из k одномерных векторов.
  2. Создаёт k одномерных массивов: i-й массив (i от 0 до k-1) равен np.arange(i * n, (i + 1) * n) — shape (n,).
  3. Объединяет все k массивов через np.concatenate(..., axis=0) → cat. Выводит строку: cat shape=<shape> ndim=<ndim>.
  4. Складывает все k массивов через np.stack(..., axis=0) → st0. Выводит строку: st0 shape=<shape> ndim=<ndim>.
  5. Складывает все k массивов через np.stack(..., axis=1) → st1. Выводит строку: st1 shape=<shape> ndim=<ndim>.
  6. Выводит строку ndim_diff=<d>, где <d> — разница st0.ndim - cat.ndim.

Shape выводите в виде Python-кортежа, например (6,) или (2, 3).

Ввод и вывод

Программа читает stdin и пишет в stdout.

Формат ввода

Одна строка: два целых числа n k, разделённых пробелом. Гарантируется n >= 2, k >= 2.

Формат вывода

Четыре строки:

cat shape=<shape> ndim=<ndim>
st0 shape=<shape> ndim=<ndim>
st1 shape=<shape> ndim=<ndim>
ndim_diff=<d>
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задача 7

Найди и исправь: неверные axis в concatenate и stack

Что уже дано

Проверяющая система запускает вашу программу и подаёт данные через stdin. Никаких заранее созданных переменных нет.

В редакторе уже есть сломанный код. Он пытается выполнить четыре операции объединения массивов, но в каждой из четырёх допущена ошибка: либо перепутан axis в np.concatenate, либо неверна позиция новой оси в np.stack, либо массивы переданы в неправильном порядке.

Что нужно сделать

Найдите и исправьте все четыре ошибки так, чтобы программа:

  1. Читала из stdin четыре целых числа в одной строке: R, C, R2, n.
  2. Создавала:
  • a = np.arange(R * C).reshape(R, C) — shape (R, C);
  • b = np.arange(R2 * C).reshape(R2, C) — shape (R2, C);
  • список из n одномерных массивов vecs, где i-й равен np.arange(i * C, (i + 1) * C) — shape (C,) каждый.
  1. Выполняла четыре операции и выводила shape каждого результата в отдельной строке:
  • op1 = np.concatenate([a, b], axis=0) — склейка по строкам; shape (R + R2, C);
  • op2 = np.concatenate([a, a], axis=1) — склейка по столбцам; shape (R, 2 * C);
  • op3 = np.stack(vecs, axis=0) — новая ось в позиции 0; shape (n, C);
  • op4 = np.stack(vecs, axis=1) — новая ось в позиции 1; shape (C, n).

Каждый shape выводите в виде Python-кортежа, например (4, 3).

Ввод и вывод

Программа читает stdin и пишет в stdout.

Формат ввода

Одна строка: четыре целых числа R C R2 n, разделённых пробелами. Гарантируется R >= 2, C >= 2, R2 >= 1, n >= 2.

Формат вывода

Четыре строки — shape каждой операции в виде Python-кортежа.

РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задачи к уроку

Все задачи курса →

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку