Skip to content

20. Объединение тензоров и сборка финальных датасетов ​

Инструменты конкатенации и стекинга ​

Механика работы numpy.concatenate() ​

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

Главной универсальной функцией для этой задачи является numpy.concatenate((arr1, arr2, ...), axis=0). Она принимает на вход кортеж или список массивов и жестко склеивает их вдоль уже существующей оси, указанной в параметре axis.

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

При склеивании массивов через numpy.concatenate геометрия всех объединяемых фрагментов должна быть абсолютно идентичной по всем осям, кроме той, вдоль которой происходит склейка. Если вы попытаетесь объединить матрицы по столбцам (axis=1), но у них будет разное количество строк, NumPy выбросит критическую ошибку ValueError.

python
import numpy

matrix_A = numpy.array([[1, 2], [3, 4]])
matrix_B = numpy.array([[5, 6]])

# Combining arrays vertically (along rows) -> Shape changes from (2,2) and (1,2) to (3,2)
combined_vertical = numpy.concatenate((matrix_A, matrix_B), axis=0)
print(combined_vertical)
# Outputs:
# [[1 2]
#  [3 4]
#  [5 6]]

Быстрые обертки: vstack и hstack ​

Для удобства и сокращения кода в NumPy реализованы интуитивные обертки над базовой конкатенацией:

  • numpy.vstack((arr1, arr2)) (vertical stack) — принудительно склеивает массивы по вертикали (строка к строке). Автоматически преобразует 1D-векторы в 2D-матрицы строки перед объединением. Эквивалентен concatenate на axis=0.
  • numpy.hstack((arr1, arr2)) (horizontal stack) — принудительно склеивает массивы по горизонтали (столбец к столбцу). Эквивалентен concatenate на axis=1.

Концепция стекинга через numpy.stack() ​

В отличие от конкатенации, функция numpy.stack((arr1, arr2, ...), axis=0) объединяет массивы вдоль совершенно новой оси, которой до этого не существовало в структуре.

Представьте, что у вас есть две независимые матрицы картинок формы (224, 224).

  • Если применить к ним numpy.concatenate(..., axis=0), они склеятся в одну длинную ленту-матрицу формы (448, 224).
  • Если же применить к ним numpy.stack(..., axis=0), NumPy создаст новую ось батча и упакует их в 3D-тензор формы (2, 224, 224).

В ИИ-инженерии это фундаментальная параллель с функциями torch.cat (конкатенация) и torch.stack (стекинг) в PyTorch.

python
import numpy

vector_1 = numpy.array([10, 20])
vector_2 = numpy.array([30, 40])

# Stacking creates a completely new axis -> Form shifts from (2,) and (2,) to (2, 2)
stacked_tensor = numpy.stack((vector_1, vector_2), axis=0)
print(stacked_tensor)
# Outputs:
# [[10 20]
#  [30 40]]

Пайплайн сборки итогового тензора ​

На практике финальный цикл подготовки данных перед отправкой в нейросеть выглядит как конвейер: генерация или чтение отдельных батчей, выравнивание их геометрии с помощью reshape или newaxis, фильтрация аномалий и последующая сборка через stack или concatenate в единый обучающий тензор. Любая склейка на C-уровне всегда выполняет выделение нового непрерывного буфера памяти в RAM/VRAM.

Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию) ​

1. Вертикальная склейка матриц объектов ​

Задача: Даны две матрицы данных: matrix_1 = numpy.array([[1, 2], [3, 4]]) и matrix_2 = numpy.array([[5, 6], [7, 8]]). Объедините их вертикально с помощью numpy.concatenate() на нужной оси. Выведите полученный массив.

Посмотреть решение
python
import numpy

matrix_1 = numpy.array([[1, 2], [3, 4]])
matrix_2 = numpy.array([[5, 6], [7, 8]])

# Concatenating along the rows axis (axis=0)
dataset_block = numpy.concatenate((matrix_1, matrix_2), axis=0)
print(dataset_block)
# Outputs:
# [[1 2]
#  [3 4]
#  [5 6]
#  [7 8]]

2. Сборка матрицы признаков через hstack ​

Задача: У вас есть матрица основных признаков X_main = numpy.array([[10], [20]]) и матрица дополнительных признаков X_add = numpy.array([[99], [88]]). Склейте их по горизонтали (столбец к столбцу) с помощью функции numpy.hstack(). Выведите результат.

Посмотреть решение
python
import numpy

X_main = numpy.array([[10], [20]])
X_add = numpy.array([[99], [88]])

# Horizontal stacking to attach new column features
extended_features = numpy.hstack((X_main, X_add))
print(extended_features)
# Outputs:
# [[10 99]
#  [20 88]]

3. Объединение одномерных векторов логов ​

Задача: Даны два одномерных массива: log_A = numpy.array([1, 2]) и log_B = numpy.array([3, 4, 5]). Склейте их в один общий длинный 1D-вектор. Выведите итоговый результат.

Посмотреть решение
python
import numpy

log_A = numpy.array([1, 2])
log_B = numpy.array([3, 4, 5])

# Concatenating 1D arrays doesn't require multi-axis matching
global_log = numpy.concatenate((log_A, log_B))
print(global_log)  # Outputs: [1 2 3 4 5]

4. Создание оси батча через numpy.stack() ​

Задача: Даны две матрицы, имитирующие два независимых слоя скрытых признаков объектов: layer_1 = numpy.zeros((2, 2)) и layer_2 = numpy.ones((2, 2)). Объедините их с помощью numpy.stack() вдоль новой нулевой оси (axis=0). Выведите форму .shape полученного 3D-тензора.

Посмотреть решение
python
import numpy

layer_1 = numpy.zeros((2, 2))
layer_2 = numpy.ones((2, 2))

# Stacking introduces a new batch dimension axis
batched_tensor = numpy.stack((layer_1, layer_2), axis=0)
print("Resulting 3D tensor shape configuration:", batched_tensor.shape)  # Outputs: (2, 2, 2)

5. Вертикальное наслоение векторов через vstack ​

Задача: Даны два простых плоских одномерных вектора: v1 = numpy.array([1, 2, 3]) и v2 = numpy.array([4, 5, 6]). Объедините их с помощью numpy.vstack(). Убедитесь по выводу на экран, что результат автоматически превратился в двумерную матрицу.

Посмотреть решение
python
import numpy

v1 = numpy.array([1, 2, 3])
v2 = numpy.array([4, 5, 6])

# vstack converts 1D arrays to 2D row matrices before merging them vertically
matrix_grid = numpy.vstack((v1, v2))
print(matrix_grid)
# Outputs:
# [[1 2 3]
#  [4 5 6]]

Упражнения смешанные (5 шт) (включают материал прошлых уроков) ​

6. Сборка датасета из случайно сгенерированных батчей признаков ​

Задача: С помощью rng.normal() сгенерируйте первый случайный батч признаков batch_A размером (2, 3) (Урок 17 / Урок 11). С помощью rng.uniform() сгенерируйте второй случайный батч batch_B размером (3, 3). Склейте их вертикально в единую матрицу с помощью numpy.concatenate() (Урок 20). Выведите на экран форму .shape итоговой матрицы и её физический объем в байтах через .nbytes (Урок 2).

Посмотреть решение
python
import numpy

rng = numpy.random.default_rng(seed=42)

# Generating data pieces with matching features size (Lesson 11 & Lesson 17)
batch_A = rng.normal(loc=0.0, scale=1.0, size=(2, 3))
batch_B = rng.uniform(low=-1.0, high=1.0, size=(3, 3))

# Merging along the sample axis=0 (Lesson 20)
full_dataset = numpy.concatenate((batch_A, batch_B), axis=0)

print("Combined matrix geometry shape layout:", full_dataset.shape)  # Outputs: (5, 3)
print("Physical size footprint in bytes:", full_dataset.nbytes)     # 15 elements * 8 bytes = 120 bytes (Lesson 2)

7. Склейка матрицы признаков X и вектора ответов y с изменением формы ​

Задача: Дана матрица признаков X = numpy.array([[1.5, 2.5], [3.5, 4.5]]) (Урок 11). Дан плоский одномерный вектор ответов y = numpy.array([0, 1]) (Урок 4). Превратите вектор y в вертикальную матрицу-столбец формы (2, 1) с помощью метода .reshape(-1, 1) (Урок 18). Присоедините полученный столбец к матрице X по горизонтали с помощью numpy.hstack(), собрав финальный целостный датасет (Урок 20). Выведите результат.

Посмотреть решение
python
import numpy

X = numpy.array([[1.5, 2.5], [3.5, 4.5]])
y = numpy.array([0, 1])

# Transforming 1D vector into a vertical column matrix space (Lesson 18)
column_y = y.reshape(-1, 1)  # Shape becomes (2, 1)

# Horizontal concatenation to bind features and targets (Lesson 20)
complete_table = numpy.hstack((X, column_y))
print("Assembled complete dataset matrix:\n", complete_table)
# Outputs:
# [[1.5 2.5 0. ]
#  [3.5 4.5 1. ]]

8. Стекинг извлеченных многомерных каналов батча изображений ​

Задача: Дан 4D-тензор батча изображений batch_tensor = numpy.ones((4, 32, 32, 3)) (Урок 16). Используя многомерные срезы, извлеките плоскую 2D-матрицу Красного канала (индекс 0) для первой картинки, и матрицу Синего канала (индекс 2) для второй картинки (Урок 13 / Урок 16). Объедините эти две матрицы с помощью numpy.stack() вдоль новой нулевой оси, создав из них отдельный мини-батч формы (2, 32, 32) (Урок 20). Выведите итоговую форму.

Посмотреть решение
python
import numpy

batch_tensor = numpy.ones((4, 32, 32, 3))

# Extracting spatial matrix channels slices (Lesson 13 & Lesson 16)
first_red_channel = batch_tensor[0, :, :, 0]   # Shape: (32, 32)
second_blue_channel = batch_tensor[1, :, :, 2] # Shape: (32, 32)

# Packing separate channels into a brand new 3D tensor sequence (Lesson 20)
new_channels_batch = numpy.stack((first_red_channel, second_blue_channel), axis=0)
print("New stacked tensor geometry shape configuration:", new_channels_batch.shape)  # Outputs: (2, 32, 32)

9. Сборка и очистка батча от аномалий (NaN) перед агрегацией ​

Задача: Дана чистая матрица признаков matrix_valid = numpy.array([[0.5, 0.8]]) (Урок 11). Дана поврежденная матрица matrix_corrupted = numpy.array([[0.1, numpy.nan]]) типа numpy.float32 (Урок 4). Объедините их по вертикали с помощью numpy.vstack() (Урок 20). В полученной общей матрице найдите значение NaN с помощью numpy.isnan() и замените его на месте на константу 0.0 (Урок 9 / Урок 13). После очистки посчитайте среднее арифметическое всей матрицы с помощью метода .mean() (Урок 15). Выведите среднее.

Посмотреть решение
python
import numpy

matrix_valid = numpy.array([[0.5, 0.8]])
matrix_corrupted = numpy.array([[0.1, numpy.nan]], dtype=numpy.float32)

# Merging records vertically (Lesson 20)
combined_matrix = numpy.vstack((matrix_valid, matrix_corrupted))

# Spotting and patching NaN anomalies (Lesson 9 & Lesson 13)
combined_matrix[numpy.isnan(combined_matrix)] = 0.0

# Computing global scalar statistical reduction mean (Lesson 15)
global_mean = combined_matrix.mean()
print(f"Sanitized global mean: {global_mean:.2f}")  # (0.5 + 0.8 + 0.1 + 0.0) / 4 = 0.35

10. Прямой проход слоя (XW) для сконкатенированного батча с Broadcasting ​

Задача: У вас есть два независимых вектора входных сигналов объектов: x1 = numpy.array([1.0, 2.0]) и x2 = numpy.array([3.0, 4.0]). Объедините их по вертикали с помощью numpy.vstack(), сформировав полноценную матрицу батча X формы (2, 2) (Урок 20). Выполните матричное умножение X на матрицу весов W = numpy.array([[0.5], [1.0]]) формы (2, 1) (Урок 14). К результату прибавьте вектор смещений bias = numpy.array([0.1]) с помощью правил механизма Broadcasting (Урок 19). Выведите финальный вектор-столбец активаций слоя.

Посмотреть решение
python
import numpy

x1 = numpy.array([1.0, 2.0])
x2 = numpy.array([3.0, 4.0])
W = numpy.array([[0.5], [1.0]])
bias = numpy.array([0.1])

# Step 1: Combine input instances vectors into a 2D batch layout matrix (Lesson 20)
X_batch = numpy.vstack((x1, x2))  # Shape becomes: (2, 2)

# Step 2: Running linear algebra product (Lesson 14)
logits_vector = X_batch @ W  # (2, 2) @ (2, 1) -> (2, 1). Yields: [[2.5], [5.5]]

# Step 3: Accumulating bias translations scaling (Lesson 19)
final_activations = logits_vector + bias
print("Final layer columns activation outputs:\n", final_activations)
# Outputs:
# [[2.6]
#  [5.6]]