Урок курса
Агрегации по массиву и по оси: sum, mean, min, max, argmin, argmax
NumPy и pandas: практический тренажёрЧто означают axis=0 и axis=1
Для двумерного массива np.sum(a, axis=0) складывает значения вдоль оси строк и оставляет сумму для каждого столбца. axis=1 складывает значения вдоль оси столбцов и оставляет сумму для каждой строки. Без axis суммируются все элементы.
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
print(np.sum(a, axis=0).tolist())
print(np.sum(a, axis=1).tolist())
print(np.sum(a))
print(np.sum(a, axis=1, keepdims=True).shape)Результат:
[5, 7, 9]
[6, 15]
21
(2, 1)У массива формы (2, 3) результат с axis=0 имеет форму (3,), с axis=1 — (2,). Параметр keepdims=True сохраняет свёрнутую ось длины 1. Для mean, min и max выбор оси работает так же.
В прошлом уроке мы научились применять векторные операции к каждому элементу массива — складывать, сравнивать, обрезать значения через np.where и np.clip. Теперь задача другая: не преобразовать каждый элемент по отдельности, а получить из всего массива одно итоговое число — сумму, среднее, минимум или максимум.
Глобальная агрегация: sum, mean, min, max по всему массиву
Агрегация — это сворачивание нескольких значений в одно. Самый простой случай: передать массив целиком в np.sum, np.mean, np.min или np.max без каких-либо дополнительных параметров. NumPy обойдёт все элементы, независимо от формы массива, и вернёт один скаляр.
Посмотрим на конкретном примере:
import numpy as np
arr = np.array([[3, 1, 4],
[1, 5, 9],
[2, 6, 5]])
print(np.sum(arr)) # 36
print(np.mean(arr)) # 4.0
print(np.min(arr)) # 1
print(np.max(arr)) # 9
Массив имеет shape (3, 3) — девять элементов. Каждая из четырёх функций вернёт одно число: np.sum сложит все девять, np.mean поделит сумму на количество, np.min и np.max найдут крайние значения.
Важная деталь: результат — не Python-число, а NumPy-скаляр. Его shape — пустой кортеж (), что буквально означает «ноль измерений».
result = np.sum(arr)
print(type(result)) # <class 'numpy.int64'> или аналогичный
print(result.shape) # ()
Это работает для массивов любой формы: одномерных, двумерных, трёхмерных — не важно. Если axis не указан, NumPy считает, что нужно схлопнуть сразу все оси, и возвращает единственное число. Форма исходного массива влияет только на то, сколько элементов участвует в вычислении, но не на форму результата — она всегда ().
Это полезно, когда нужна одна общая характеристика: суммарная выручка по всей таблице продаж, средняя температура за весь период, глобальный минимум в матрице весов. Когда же нужен результат отдельно по строкам или столбцам — вступает в игру параметр axis, о котором пойдёт речь в следующем разделе.
Параметр axis: какая ось «схлопывается» и как меняется shape
Когда нужна не одна общая цифра, а результат отдельно по каждой строке или по каждому столбцу, в игру вступает параметр axis. Его смысл проще всего описать через одно слово: схлопывание. Указывая axis=k, вы говорите NumPy: «пробегись вдоль оси с номером k и сверни её». Ось исчезает из результата — в этом и есть весь механизм.
Разберём на двумерном массиве shape (3, 3). Оси здесь две: ось 0 — это направление «вниз по строкам», ось 1 — «вправо по столбцам».
import numpy as np
arr = np.array([[3, 1, 4],
[1, 5, 9],
[2, 6, 5]])
# shape: (3, 3)
print(np.sum(arr, axis=0)) # [6, 12, 18] — shape (3,)
print(np.sum(arr, axis=1)) # [8, 15, 13] — shape (3,)
С axis=0 NumPy суммирует вдоль строк: берёт первый столбец [3, 1, 2], складывает в 6; второй [1, 5, 6] → 12; третий [4, 9, 5] → 18. Ось 0 (размерность «три строки») исчезла — остался массив из трёх чисел, по одному на столбец. Shape исходника был (3, 3), вычеркиваем нулевой элемент — получаем (3,).
С axis=1 всё симметрично: суммируем вдоль столбцов, то есть каждую строку сворачиваем в одно число. Ось 1 исчезает, результат тоже (3,) — по одному числу на строку.
Общее правило предсказания shape:
- Запишите shape исходного массива как кортеж.
- Уберите из кортежа элемент с позицией
k. - То, что осталось, и есть shape результата.
Это правило работает для массивов любой размерности. Например, массив shape (2, 3, 4) при axis=1 даёт (2, 4): элемент с позицией 1 (то есть 3) вычеркнут.
arr3d = np.zeros((2, 3, 4))
result = np.mean(arr3d, axis=1)
print(result.shape) # (2, 4)
Практически это означает: если хотите получить среднее по каждому столбцу таблицы — берёте axis=0; среднее по каждой строке — axis=1. Правило «убираем k-й элемент из кортежа» позволяет не держать в голове конкретные числа, а вычислять результат из первых принципов для любого массива.
Обратите внимание: axis работает одинаково для всех агрегирующих функций — np.sum, np.mean, np.min, np.max и, как увидим дальше, np.argmin, np.argmax. Параметр описывает только то, какая ось схлопывается, а не какая операция выполняется.
argmin и argmax: позиция экстремума глобально и по оси
np.argmin и np.argmax — это не агрегации значений, а агрегации индексов. Они не возвращают минимум или максимум — они возвращают позицию, где этот минимум или максимум находится. Это принципиальное отличие от np.min / np.max, и оно важно: тип результата — целое число (или массив целых чисел), а не значение из исходного массива.
Без axis: позиция в «развёрнутом» массиве
Когда вызываете np.argmin(arr) или np.argmax(arr) без параметра axis, NumPy сначала мысленно разворачивает массив в одномерный (как если бы применили .flatten()), а затем находит позицию экстремума в этом одномерном представлении.
import numpy as np
arr = np.array([[3, 1, 4],
[1, 5, 9],
[2, 6, 5]])
# shape (3, 3) → развёрнутый: [3, 1, 4, 1, 5, 9, 2, 6, 5]
print(np.argmin(arr)) # 1 (элемент arr[0,1] = 1, позиция 1 в flatten)
print(np.argmax(arr)) # 5 (элемент arr[1,2] = 9, позиция 5 в flatten)
Развёрнутый массив — это строки, уложенные одна за другой: [3, 1, 4, 1, 5, 9, 2, 6, 5]. Индекс 1 — это второй элемент (значение 1), индекс 5 — шестой (значение 9). Shape результата — пустой кортеж (), то есть скаляр, точно как при глобальной агрегации значений.
С axis=k: индекс вдоль схлопнутой оси
Схема полностью та же, что для np.sum или np.mean с axis: ось k убирается из shape, и для каждого «среза» вдоль оставшихся осей возвращается один целочисленный индекс.
Для массива shape (3, 3):
axis=0схлопывает строки → shape результата(3,), каждое значение — номер строки, в которой максимум данного столбца.axis=1схлопывает столбцы → shape(3,), каждое значение — номер столбца, в котором минимум данной строки.
print(np.argmax(arr, axis=0)) # [0, 2, 1]
# столбец 0: max = 3 → строка 0
# столбец 1: max = 6 → строка 2
# столбец 2: max = 9 → строка 1
print(np.argmin(arr, axis=1)) # [1, 0, 0]
# строка 0: min = 1 → столбец 1
# строка 1: min = 1 → столбец 0
# строка 2: min = 2 → столбец 0
Обратите внимание на смысл: np.argmax(arr, axis=0)[j] отвечает на вопрос «в каком ряду наибольший элемент j-го столбца?». Это не то же самое, что максимальное значение — это адрес.
Ключ к правильному чтению результата: всегда держите в голове, какую ось вы схлопнули. Число в результате — это индекс вдоль именно той оси, которую убрали.
Сквозной пример и процедура проверки shape
Теперь соберём всё вместе на одном массиве и отработаем конкретный алгоритм: сначала предсказать shape результата вручную, потом проверить через .shape.
Возьмём уже знакомый массив:
import numpy as np
arr = np.array([[3, 1, 4],
[1, 5, 9],
[2, 6, 5]])
# shape: (3, 3)
Прежде чем запускать код, разберём предсказания shape для каждого вызова:
np.sum(arr)— axis не указан → все оси схлопываются → скаляр, shape()np.mean(arr, axis=0)— убираем элемент с позицией 0 из(3, 3)→(3,)np.min(arr, axis=1)— убираем элемент с позицией 1 из(3, 3)→(3,)np.argmax(arr)— axis не указан → позиция в flatten → скаляр, shape()np.argmin(arr, axis=1)— убираем элемент с позицией 1 из(3, 3)→(3,)
Теперь проверяем:
# Глобальные агрегации → скаляр
print(np.sum(arr)) # 36
print(np.sum(arr).shape) # ()
print(np.mean(arr)) # 4.0
print(np.min(arr)) # 1
print(np.max(arr)) # 9
# По оси 0 → shape (3,)
res_axis0 = np.mean(arr, axis=0)
print(res_axis0) # [2. 4. 6.]
print(res_axis0.shape) # (3,)
# По оси 1 → shape (3,)
res_axis1 = np.min(arr, axis=1)
print(res_axis1) # [1 1 2]
print(res_axis1.shape) # (3,)
# argmax без axis → скаляр (позиция в flatten)
print(np.argmax(arr)) # 5
print(np.argmax(arr).shape) # ()
# argmin по оси 1 → shape (3,)
res_argmin = np.argmin(arr, axis=1)
print(res_argmin) # [1 0 0]
print(res_argmin.shape) # (3,)
Все предсказания совпадают. Это и есть рабочий алгоритм:
- Запишите shape исходного массива.
- Если
axisне указан — результат всегда скаляр, shape(). - Если указан
axis=k— уберите из кортежа shape элемент на позицииk. Остаток и есть shape результата. - Запустите агрегацию и вызовите
.shape— сверьте с предсказанием.
Алгоритм работает одинаково для sum, mean, min, max, argmin, argmax — и для массивов любой размерности. Например, для трёхмерного:
arr3d = np.ones((2, 3, 4))
# axis=1 → убираем '3' из (2, 3, 4) → предсказание (2, 4)
result = np.sum(arr3d, axis=1)
print(result.shape) # (2, 4) ✓
Привычка проверять .shape сразу после агрегации экономит время: несовпадение с предсказанием сразу указывает, что axis выбран неверно или массив имеет другую форму, чем ожидалось.
Закрепите тему на задачах
Для двумерной таблицы отдельно предскажите shape после sum(axis=0), sum(axis=1) и варианта keepdims=True. Так можно поймать неверную ось до анализа чисел.
Min-max нормализация матрицы NumPy и argmin/argmax
NumPy axis=0, 1, 2: агрегация трёхмерного массива
Откройте условие и решите задачу перед чтением следующей темы. В задачах на код проверяется программа, в тестовых заданиях — выбранный ответ. Для последовательного обучения вернитесь в программу бесплатного курса.
Задача 1
Массив arr имеет shape (5, 7). Чему равен shape результата np.sum(arr, axis=0)?
Задача 2
Дан массив arr = np.array([[2, 8, 1], [5, 3, 9]]). Что возвращает np.argmin(arr) без параметра axis?
Задача 3
Агрегации по оси: sum, mean, argmin, argmax и shape результата
Что уже дано
Проверяющая система запускает вашу программу и подаёт данные через stdin. Никаких заранее созданных переменных нет — вы читаете всё сами.
Что нужно сделать
Напишите программу, которая:
- Читает из
stdinдва целых числаRиC— количество строк и столбцов. - Читает следующие
Rстрок; каждая содержитCцелых чисел через пробел. Создаёт двумерный массивarrчерезnp.array(..., dtype=int)формы(R, C). - Выводит в
stdoutровно восемь блоков в следующем порядке:
Блок 1. Глобальная сумма: значение np.sum(arr), затем на следующей строке — его shape в виде ().
Блок 2. np.sum(arr, axis=0): значения через пробел, затем shape в виде (C,).
Блок 3. np.mean(arr, axis=1): значения через пробел (тип float64, выводите как есть через print), затем shape в виде (R,).
Блок 4. np.min(arr, axis=0): значения через пробел, затем shape.
Блок 5. np.max(arr, axis=1): значения через пробел, затем shape.
Блок 6. Глобальный np.argmin(arr): значение (позиция в развёрнутом массиве), затем shape в виде ().
Блок 7. np.argmax(arr, axis=0): значения через пробел, затем shape.
Блок 8. np.argmin(arr, axis=1): значения через пробел, затем shape.
Каждый блок занимает ровно две строки: первая — значение(я), вторая — shape.
Ввод и вывод
Программа читает stdin и пишет в stdout.
Формат ввода
R C
a00 a01 ... a0(C-1)
...
a(R-1)0 ... a(R-1)(C-1)
Формат вывода
Восемь блоков по две строки каждый (итого 16 строк). Shape выводится строковым представлением кортежа Python, например (3,) или ().
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Задача 4
Найди и исправь: неверные вызовы argmin, argmax и mean по оси
Что уже дано
Проверяющая система запускает вашу программу и подаёт данные через stdin. Никаких заранее созданных переменных нет.
В редакторе уже есть сломанный код. Он пытается выполнить четыре агрегации над двумерным массивом, но в каждой из четырёх строк допущена ровно одна ошибка:
- в
row_argmax— использованnp.argmax(arr)безaxis, хотя нужен номер столбца с максимумом в каждой строке; - в
col_argmin— использованaxis=1, хотя нужен номер строки с минимумом в каждом столбце; - в
row_mean— использованaxis=0, хотя нужно среднее по каждой строке (схлопнуть столбцы); - в
global_min— использованnp.argmin(arr), хотя нужно само минимальное значение черезnp.min.
Что нужно сделать
Найдите и исправьте все четыре ошибки так, чтобы программа:
- Читала из
stdinдва целых числаRиC— размер массива. - Читала следующие
Rстрок, каждая содержитCцелых чисел через пробел. Создавала двумерный массивarrчерезnp.array(..., dtype=int)формы(R, C). - Вычисляла и выводила ровно восемь строк:
- строка 1: элементы
row_argmax = np.argmax(arr, axis=1)через пробел — номера столбцов максимума в каждой строке; - строка 2:
shapeмассиваrow_argmaxв виде(R,); - строка 3: элементы
col_argmin = np.argmin(arr, axis=0)через пробел — номера строк минимума в каждом столбце; - строка 4:
shapeмассиваcol_argminв виде(C,); - строка 5: элементы
row_mean = np.mean(arr, axis=1)через пробел; - строка 6:
shapeмассиваrow_meanв виде(R,); - строка 7: значение
global_min = np.min(arr)— глобальный минимум; - строка 8:
shapeрезультатаglobal_minв виде().
Ввод и вывод
Программа читает stdin и пишет в stdout.
Формат ввода
R C
a00 a01 ... a0(C-1)
...
a(R-1)0 ... a(R-1)(C-1)
Формат вывода
Восемь строк в порядке, описанном выше. Shape выводится строковым представлением кортежа Python, например (3,) или ().
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Задача 5
Min-max нормализация матрицы и позиции глобальных экстремумов
Что уже дано
Проверяющая система запускает вашу программу и подаёт данные через stdin. Никаких заранее созданных переменных нет — вы читаете всё сами.
Что нужно сделать
Напишите программу, которая выполняет глобальную min-max нормализацию двумерного массива:
- Читает из
stdinдва целых числаRиC— количество строк и столбцов. - Читает следующие
Rстрок; каждая содержитCцелых чисел через пробел. Создаёт двумерный массивarrчерезnp.array(..., dtype=float)формы(R, C). - Вычисляет скалярный глобальный минимум
g_min = np.min(arr)и скалярный глобальный максимумg_max = np.max(arr)без параметраaxis. - Вычисляет нормализованный массив
normedпо формуле поэлементной арифметики:
normed = (arr - g_min) / (g_max - g_min)
Гарантируется, что все элементы матрицы не одинаковы, поэтому g_max - g_min > 0.
5. Вычисляет глобальный flat_argmin = np.argmin(arr) и flat_argmax = np.argmax(arr) без параметра axis — позиции в развёрнутом (flattened) массиве.
6. Выводит в stdout ровно три блока:
Блок 1. Нормализованный массив normed: каждая строка массива выводится на отдельной строке, значения через пробел, округлённые до 4 знаков после запятой (round(x, 4) для каждого элемента).
Блок 2. Одна строка: g_min g_max — глобальный минимум и максимум исходного массива (целые числа, без дробной части).
Блок 3. Одна строка: flat_argmin flat_argmax — позиции экстремумов в развёрнутом массиве.
Ввод и вывод
Программа читает stdin и пишет в stdout.
Формат ввода
R C
a00 a01 ... a0(C-1)
...
a(R-1)0 ... a(R-1)(C-1)
Формат вывода
normed[0][0] normed[0][1] ... normed[0][C-1]
...
normed[R-1][0] ... normed[R-1][C-1]
g_min g_max
flat_argmin flat_argmax
Всего R + 2 строк. Значения normed округлены до 4 знаков после запятой. g_min и g_max — целые числа (без дробной части). flat_argmin и flat_argmax — целые числа.
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Задача 6
Трёхмерный массив: агрегации по axis=0, axis=1, axis=2 и shape результата
Что уже дано
Проверяющая система запускает вашу программу и подаёт данные через stdin. Никаких заранее созданных переменных нет — вы читаете всё сами.
Что нужно сделать
Напишите программу, которая:
- Читает из
stdinтри целых числаD,R,C— количество «слоёв», строк и столбцов трёхмерного массива. - Читает следующие
D * Rстрок; каждая содержитCцелых чисел через пробел. Из них создаёт трёхмерный массивcubeчерезnp.array(..., dtype=int).reshape(D, R, C)— shape(D, R, C). - Вычисляет пять агрегаций и выводит результат каждой в два строки: первая — значения через пробел (или одно значение), вторая — shape кортежем Python:
Агрегация 1. np.sum(cube, axis=0) — сумма по «слоям» (ось 0 схлопывается). Shape результата (R, C).
Агрегация 2. np.mean(cube, axis=2) — среднее по столбцам (ось 2 схлопывается). Shape результата (D, R).
Агрегация 3. np.argmax(cube, axis=1) — номер строки с максимумом в каждом (слой, столбец). Shape результата (D, C).
Агрегация 4. np.min(cube, axis=0) — минимум по «слоям». Shape результата (R, C).
Агрегация 5. np.argmin(cube) без параметра axis — позиция минимума в развёрнутом массиве. Shape результата ().
Для многоэлементных результатов выводите значения через пробел в порядке обхода по умолчанию (flatten()). Для скаляра — одно число.
Ввод и вывод
Программа читает stdin и пишет в stdout.
Формат ввода
D R C
строка_0_слоя_0: c0 c1 ... c(C-1)
...
строка_(R-1)_слоя_0: c0 c1 ... c(C-1)
строка_0_слоя_1: c0 c1 ... c(C-1)
...
строка_(R-1)_слоя_(D-1): c0 c1 ... c(C-1)
Всего D * R строк с данными, каждая содержит C целых чисел.
Формат вывода
Десять строк — по две на каждую из пяти агрегаций. Нечётная строка блока — значения через пробел или одно число. Чётная строка блока — shape в виде кортежа Python, например (3, 4) или ().
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Задачи к уроку
- Min-max нормализация матрицы NumPy и argmin/argmax
Нормализуйте матрицу по минимуму и максимуму, затем найдите позиции глобальных экстремумов в NumPy.
- NumPy axis=0, 1, 2: пример агрегации и задача
Как axis влияет на sum и форму результата NumPy? Короткий пример и задача на агрегацию трёхмерного массива с проверкой кода.
Продолжить с сохранением прогресса
Перейдите к уроку в учебном кабинете.
