Нашли ошибку?
Скачать чистый
мини-проект≈ 20 минупражнения: 0 из 5

Итоговый проект: динамика

Как менялись продажи «Кофейной лавки» в течение 2025 года — выручка по месяцам и кварталам, лучший и худший месяц, рост к прошлому месяцу, накопленный итог и доли каналов продаж по месяцам.

Python запустится при первом выполнении

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

[ ]Выручка строк — как в прошлой части
import numpy as np

path = "data/shop_orders.csv"
nums = np.loadtxt(path, delimiter=",", skiprows=1, usecols=(7, 8))
revenue = nums[:, 0] * nums[:, 1]
total = revenue.sum()
print(revenue.shape, total)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
(2448,) 3301420.0

Шаг 1. Выручка по месяцам

Дата в файле — текст вида 2025-03-14. Месяц — символы с 5-го по 6-й, считая с нуля: срез строки d[5:7], а int делает из него число. Для 2448 строк это обычный генератор списка из Python — NumPy не обязан уметь всё. (Полноценную работу с датами вы освоите в курсе pandas.)

[ ]Номер месяца из даты
dates = np.loadtxt(path, delimiter=",", skiprows=1, usecols=1, dtype=str)
month = np.array([int(d[5:7]) for d in dates])
print(dates[:3], dates[-3:])
print(month[:3], month[-3:])
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
['2025-01-01' '2025-01-01' '2025-01-01'] ['2025-12-31' '2025-12-31' '2025-12-31']
[1 1 1] [12 12 12]

Месяц — целое от 1 до 12, то есть готовый код группы: суммы по месяцам даёт np.bincount с весами, как в прошлой части. Код 0 не встречается — его сумма будет нулём, как у нулевой грани кубика.

[ ]Упражнение 1Двенадцать месяцев решено

Сохраните в monthly выручку каждого месяца — 12 чисел, январь первым. В best_month и worst_month — номера (1–12) месяцев с наибольшей и наименьшей выручкой.

monthly = ...
best_month = ...
worst_month = ...

Шаг 2. Рост к прошлому месяцу

Изменение к прошлому месяцу — разность соседей: monthly[1:] - monthly[:-1], два среза со сдвигом на один, как в парадоксе дней рождения. Первый элемент разностей — февраль минус январь.

[ ]Упражнение 2Самый большой рост решено

Сохраните в change изменение выручки каждого месяца к предыдущему (11 чисел, начиная с февраля), а в rise_month — номер месяца (1–12), в котором выручка выросла сильнее всего.

change = ...
rise_month = ...

Шаг 3. Накопленный итог и кварталы

[ ]Упражнение 3Половина года решено

Сохраните в running накопленную выручку с начала года по месяцам, а в half_month — номер месяца, к концу которого магазин заработал хотя бы половину годовой выручки.

running = ...
half_month = ...

[ ]Упражнение 4Кварталы решено

Сохраните в quarters выручку каждого квартала (4 числа), а в weak_quarter — номер (1–4) самого слабого квартала.

quarters = ...
weak_quarter = ...

Лето — самый слабый сезон: в жару горячий кофе и чай покупают меньше, а в декабре выручку поднимают подарки к Новому году.

Пояснение с ответом появится, когда решите упражнение «Кварталы».

Шаг 4. Каналы продаж по месяцам

Теперь хотим таблицу 12 × 3: месяц × канал (маркетплейс, приложение, сайт). Это группы по двум признакам сразу. Приём: склеить два кода в один. Если у канала коды 0–2, то (month - 1) * 3 + канал даёт каждой паре «месяц, канал» свой номер от 0 до 35: январь — 0, 1, 2, февраль — 3, 4, 5 и так далее. bincount по такому коду даёт 36 сумм, а reshape(12, 3) раскладывает их в таблицу:

[ ]Две группы в одном коде
m_demo = np.array([1, 1, 2, 2, 2])        # месяц
c_demo = np.array([0, 2, 1, 2, 2])        # канал
amount = np.array([10, 20, 30, 40, 50])
pair = (m_demo - 1) * 3 + c_demo
print(pair)
print(np.bincount(pair, weights=amount).reshape(2, 3))
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
[0 2 4 5 5]
[[10.  0. 20.]
 [ 0. 30. 90.]]
[ ]Упражнение 5Доли каналов решено

Загрузите столбец каналов (4) и сохраните в by_channel таблицу 12 × 3 — выручку каждого канала в каждом месяце, в shares — долю каждого канала в выручке своего месяца (строки в сумме дают 1), а в site_peak — номер месяца (1–12), когда доля сайта была наибольшей.

by_channel = ...
shares = ...
site_peak = ...

[ ]Год в цифрах
print("лучший месяц:", best_month, "худший:", worst_month)
print("кварталы, тыс. ₽:", np.round(quarters / 1000))
year_share = by_channel.sum(axis=0) / total
for name, share in zip(["маркетплейс", "приложение", "сайт"], year_share * 100):
    print(f"  {name}: {share:.0f} % за год")
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
лучший месяц: 12 худший: 7
кварталы, тыс. ₽: [867. 864. 652. 918.]
  маркетплейс: 27 % за год
  приложение: 27 % за год
  сайт: 46 % за год
Итог появится, когда решите все упражнения урока, — в нём ответы. Ячейку можно и выполнить.

Выводы

Выручка «Кофейной лавки» — сезонная: лучший месяц — декабрь, худший — июль, третий квартал заметно слабее остальных, а половину годовой выручки магазин набрал к концу июня. Сайт — главный канал (46 % за год), а в октябре его доля доходила до двух третей.

Выводы с ответами появятся, когда решите все упражнения урока.

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

Подробнее в справочнике

Практика по модулю

Задачи по NumPy для самостоятельной практики появятся в разделе «Задачи → NumPy».

Нашли ошибку?