Таблицу из тысячи строк нельзя удержать в голове — её описывают несколькими числами. Какое значение типично?
Насколько остальные от него отличаются? Где крайности? В этом модуле появляется новый набор данных —
data/weather.csv: погода в пяти городах за каждый день 2025 года.
import pandas as pd
weather = pd.read_csv("data/weather.csv", parse_dates=["date"])
moscow = weather[weather["city"] == "Москва"]
moscow.head(3)| date | city | temp_min | temp_max | precip_mm | wind_ms | |
|---|---|---|---|---|---|---|
| 0 | 2025-01-01 | Москва | -9.9 | -3.2 | 0.0 | 1.9 |
| 1 | 2025-01-02 | Москва | -9.7 | -3.2 | 0.0 | 2.3 |
| 2 | 2025-01-03 | Москва | -9.0 | -3.7 | 0.0 | 5.2 |
temp_min и temp_max — наименьшая и наибольшая температура за сутки, precip_mm — осадки в миллиметрах,
wind_ms — ветер в метрах в секунду.
Типичное значение: среднее или медиана
Сколько осадков выпадает в Москве в обычный день?
rain = moscow["precip_mm"]
print(rain.mean())
print(rain.median())
print((rain.dropna() == 0).mean())1.954120879120879 0.0 0.5384615384615384
Среднее — почти 2 мм, а медиана — ноль. Оба числа верны, но отвечают на разные вопросы. Больше половины дней
сухие — поэтому «день посередине» без осадков. А среднее учитывает редкие ливни и «размазывает» их по всем
дням. (Один день в Москве без данных об осадках; в долю сухих дней он не входит — отсюда dropna.)
Медиана устойчива к необычно большим и малым значениям, среднее — нет:
salaries = pd.Series([60, 65, 70, 75, 80])
with_boss = pd.Series([60, 65, 70, 75, 80, 900])
print(salaries.mean(), salaries.median())
print(with_boss.mean(), with_boss.median())70.0 70.0 208.33333333333334 72.5
Одно значение 900 подняло среднее с 70 до 208 — и оно перестало описывать кого-либо из шести человек. Медиана сдвинулась с 70 до 72.5. (Когда значений чётное число, посередине оказываются два — медианой считают их среднее: (70 + 75) / 2 = 72.5.)
Практическое правило: если среднее и медиана близки, подойдёт любое. Если заметно расходятся — в данных перекос, и «типичное» значение честнее описывает медиана.
Что выведет print(pd.Series([1, 2, 100]).median())?
В revenue — выручка каждой строки таблицы продаж. Сохраните в mean_revenue её среднее, в median_revenue —
медиану, а в above_mean — долю строк, где выручка больше средней.
revenue.mean(), revenue.median().revenue > mean_revenue.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
orders = pd.read_csv("data/shop_orders.csv")
revenue = orders["price"] * orders["quantity"]
mean_revenue = ...
median_revenue = ...
above_mean = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
orders = pd.read_csv("data/shop_orders.csv")
revenue = orders["price"] * orders["quantity"]
mean_revenue = revenue.mean()
median_revenue = revenue.median()
above_mean = (revenue > mean_revenue).mean()Среднее — 1349 ₽, медиана — 1080 ₽, и выше среднего всего 39 % строк. Несколько крупных покупок тянут среднее вверх — как директор в примере с зарплатами.
Разброс: стандартное отклонение
Два города могут иметь похожую среднюю температуру и совсем разный климат. Насколько значения разбросаны
вокруг среднего, показывает стандартное отклонение (standard deviation) — метод std:
sochi = weather[weather["city"] == "Сочи"]
print(moscow["temp_max"].mean(), moscow["temp_max"].std())
print(sochi["temp_max"].mean(), sochi["temp_max"].std())9.123013698630135 10.108617078726315 17.724931506849316 6.342617739486737
Грубо говоря, это «типичное расстояние от среднего» (формула сложнее простого среднего расстояния, но смысл тот же). В Сочи дневная температура обычно отличается от средней градусов на шесть, в Москве — на десять. Чем больше число, тем сильнее разброс; ноль — все значения одинаковы:
print(pd.Series([10, 10, 10, 10]).std())
print(pd.Series([9, 10, 10, 11]).std())
print(pd.Series([0, 5, 15, 20]).std())0.0 0.816496580927726 9.128709291752768
Единицы измерения у std те же, что у данных: градусы, рубли, штуки.
Сохраните в novosibirsk строки таблицы weather для Новосибирска. По столбцу temp_max посчитайте:
mean_nsk — среднее, std_nsk — стандартное отклонение, range_nsk — размах: разность наибольшего
и наименьшего значений.
weather[weather["city"] == "Новосибирск"].max() минус min() того же столбца.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
novosibirsk = ...
mean_nsk = ...
std_nsk = ...
range_nsk = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
novosibirsk = weather[weather["city"] == "Новосибирск"]
mean_nsk = novosibirsk["temp_max"].mean()
std_nsk = novosibirsk["temp_max"].std()
range_nsk = novosibirsk["temp_max"].max() - novosibirsk["temp_max"].min()Разброс в Новосибирске — 14 градусов: вдвое больше, чем в Сочи. Это и есть «резко континентальный климат», записанный одним числом.
Квантили
Медиана делит данные пополам. Квантиль обобщает эту идею: квантиль 0.75 — значение, ниже которого лежит 75 % данных. Его ещё называют 75-м процентилем.
print(moscow["temp_max"].quantile(0.5))
print(moscow["temp_max"].quantile(0.75))10.1 18.5
В трёх четвертях дней в Москве было не теплее 18.5 градуса. Если передать список, вернётся Series:
moscow["temp_max"].quantile([0.25, 0.5, 0.75])0.25 -1.2 0.50 10.1 0.75 18.5 Name: temp_max, dtype: float64
Это те же 25%, 50% и 75%, что показывает describe. Их называют квартилями: они делят данные
на четыре равные части.
Сохраните в q90 квантиль 0.9 столбца temp_max таблицы moscow. В hot_days — дни, когда было строго
теплее этого значения, в n_hot — их число.
moscow["temp_max"].quantile(0.9).moscow[moscow["temp_max"] > q90].Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
q90 = ...
hot_days = ...
n_hot = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
q90 = moscow["temp_max"].quantile(0.9)
hot_days = moscow[moscow["temp_max"] > q90]
n_hot = len(hot_days)Где максимум
max отвечает «сколько», но не «когда». Метку строки с наибольшим значением возвращает idxmax
(index of maximum), с наименьшим — idxmin. По метке loc достаёт всю строку:
label = moscow["temp_max"].idxmax()
print(label)
moscow.loc[label]196
date 2025-07-16 00:00:00 city Москва temp_min 21.8 temp_max 27.2 precip_mm 9.5 wind_ms 2.2 Name: 196, dtype: object
Метка 196 — это 16 июля: метки достались таблице moscow от полной таблицы weather. Поэтому нужен именно
loc, а не iloc.
Статистика по нескольким столбцам
Все эти методы есть и у таблицы — считают по каждому столбцу:
moscow[["temp_min", "temp_max", "precip_mm", "wind_ms"]].mean()temp_min 3.603288 temp_max 9.123014 precip_mm 1.954121 wind_ms 3.823836 dtype: float64
Но только если все выбранные столбцы числовые. В таблице moscow есть текстовый столбец city:
moscow.mean()TypeError: Cannot perform reduction 'mean' with string dtype
Сохраните в coldest_label метку строки таблицы moscow с самой низкой температурой temp_min, в coldest_date —
дату этого дня. В windiest сохраните целиком строку самого ветреного дня (наибольший wind_ms).
moscow["temp_min"].idxmin() — метка; дата — moscow.loc[метка, "date"].moscow.loc[moscow["wind_ms"].idxmax()].Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
coldest_label = ...
coldest_date = ...
windiest = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
coldest_label = moscow["temp_min"].idxmin()
coldest_date = moscow.loc[coldest_label, "date"]
windiest = moscow.loc[moscow["wind_ms"].idxmax()]Итоги
- Среднее чувствительно к крайним значениям, медиана — нет; если они расходятся, смотрите на медиану.
std()— стандартное отклонение: насколько значения разбросаны вокруг среднего.quantile(q)— значение, ниже которого лежит доляqданных;quantile(0.5)— медиана.idxmax(),idxmin()— метка строки с наибольшим и наименьшим значением; строку достаётloc.