- Вычислять среднее, медиану, стандартное отклонение и IQR, находить выбросы
- Находить вероятности и квантили нормального распределения с помощью
scipy.stats.norm - Строить доверительный интервал для среднего и правильно толковать p-значение t-теста
- Вычислять корреляцию Пирсона и Спирмена и отличать корреляцию от причинности
Служба доставки еды в Баку обещает привезти заказ «в среднем за 15 минут». Мурад засёк время 10 заказов. Достаточно ли этого, чтобы проверить обещание? И как повлияет на вывод один заказ, который ехал 45 минут? Статистика отвечает в три шага: описать данные, смоделировать их распределением и сделать вывод от выборки ко всей генеральной совокупности. В Python для этого хватает NumPy и scipy.stats.
Описательная статистика и выбросы
Меры центра дают «типичное» значение: среднее (среднее арифметическое), медиана (середина отсортированных данных) и мода (самое частое значение). Меры разброса показывают, насколько рассеяны значения: дисперсия, стандартное отклонение и межквартильный размах IQR = Q3 − Q1. Для выборки дисперсию делят на n − 1 (поправка Бесселя) — так оценка получается несмещённой.
- nобъём выборки
- s²выборочная дисперсия (единица — квадрат единицы данных)
- sвыборочное стандартное отклонение (в единицах данных); в NumPy
std(ddof=1)
import numpy as np
from scipy import stats
minutes = np.array([12, 15, 11, 14, 13, 45, 13, 16, 14, 13])
print('mean :', minutes.mean())
print('median:', np.median(minutes))
print('mode :', stats.mode(minutes, keepdims=False).mode)
print('var :', round(minutes.var(ddof=1), 2))
print('std :', round(minutes.std(ddof=1), 2))
q1, q3 = np.percentile(minutes, [25, 75])
iqr = q3 - q1
print('Q1, Q3, IQR:', q1, q3, iqr)
low, high = q1 - 1.5 * iqr, q3 + 1.5 * iqr
print('outliers:', minutes[(minutes < low) | (minutes > high)])▸ Ожидаемый результат
mean : 16.6 median: 13.5 mode : 13 var : 101.6 std : 10.08 Q1, Q3, IQR: 13.0 14.75 1.75 outliers: [45]
- Q1, Q3первый и третий квартиль (25% и 75%)
- IQRQ3 − Q1, ширина средней половины данных
Правило Тьюки: значения вне этого интервала считаются выбросами. Здесь: 14,75 + 1,5 · 1,75 = 17,375, значит, 45 — выброс.
Нормальное распределение
Величины, складывающиеся из множества мелких независимых влияний (ошибки измерений, баллы за тест, рост), часто близки к нормальному распределению: колоколообразная кривая, симметричная относительно среднего. Её задают два параметра: среднее μ и стандартное отклонение σ. Любое значение можно стандартизировать z-оценкой — она показывает, на сколько σ значение удалено от среднего.
- μсреднее распределения
- σстандартное отклонение (σ > 0)
- f(x)плотность вероятности; P(a < X < b) — площадь под кривой между a и b
- zz-оценка: положение в стандартном нормальном распределении (μ = 0, σ = 1)
scipy.stats.norm создаёт объект распределения: cdf(x) = P(X ≤ x) (функция распределения), sf(x) = P(X > x) = 1 − cdf, а ppf(q) — обратная операция, квантиль для заданной вероятности. Если баллы за тест распределены нормально с μ = 70 и σ = 10:
from scipy import stats
scores = stats.norm(loc=70, scale=10)
print(round(scores.cdf(85), 4))
print(round(scores.sf(85), 4))
print(round(scores.cdf(80) - scores.cdf(60), 4))
print(round(scores.ppf(0.90), 2))
z = (85 - 70) / 10
print(z, round(stats.norm.cdf(z), 4))▸ Ожидаемый результат
0.9332 0.0668 0.6827 82.82 1.5 0.9332
Баллы за тест распределены как N(70; 10²). а) Какова вероятность, что случайный студент наберёт больше 85? б) Сколько баллов нужно, чтобы попасть в лучшие 10%? Φ(1,5) = 0,9332, z₀,₉₀ = 1,2816.
Показать решениеСкрыть решение
P(X > 85) = 1 − Φ(1,5) = 1 − 0,9332 = 0,0668, то есть около 6,7%.
б) x = μ + z₀,₉₀ · σ = 70 + 1,2816 · 10 ≈ 82,8 балла.
Оба ответа совпадают с кодом (
sf(85) и ppf(0.90)).Выборки, центральная предельная теорема и стандартная ошибка
Обычно мы видим не всю генеральную совокупность (все заказы), а лишь выборку. У каждой новой выборки среднее немного другое. Центральная предельная теорема гласит: при достаточно большом n распределение выборочных средних приближается к нормальному, даже если исходное распределение скошено, а его стандартное отклонение — стандартная ошибка — равно σ/√n. Ниже из скошенного экспоненциального распределения берутся 5000 выборок по 30:
- SEстандартная ошибка среднего
- σ, sстандартное отклонение генеральной совокупности и выборки
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(1)
population = rng.exponential(scale=10, size=100_000)
means = rng.choice(population, size=(5000, 30)).mean(axis=1)
print(f'population: mean {population.mean():.2f}, std {population.std():.2f}')
print(f'sample means: mean {means.mean():.2f}, std {means.std():.2f}')
print(f'sigma / sqrt(n) = {population.std() / np.sqrt(30):.2f}')
fig, (a, b) = plt.subplots(1, 2, figsize=(8, 3), layout='constrained')
a.hist(population, bins=50)
a.set_title('Population (skewed)')
b.hist(means, bins=40)
b.set_title('Means of samples, n = 30')
plt.show()▸ Ожидаемый результат
population: mean 9.96, std 9.92 sample means: mean 9.94, std 1.81 sigma / sqrt(n) = 1.81
Доверительный интервал и t-тест
Когда σ неизвестна, её заменяют на s и вместо нормального используют t-распределение Стьюдента с n − 1 степенями свободы — при малых выборках у него более «тяжёлые хвосты». С фабричной линии взвесили 10 пачек чая по 100 граммов:
- t*критическое значение t-распределения; для 95% α = 0,05
- n − 1число степеней свободы
95%-й доверительный интервал для среднего. stats.t.ppf(0.975, df=n - 1) возвращает t*, а stats.t.interval — весь интервал.
import numpy as np
from scipy import stats
packs = np.array([99.2, 100.4, 98.7, 100.9, 99.5, 100.1, 99.8, 98.9, 100.6, 99.4])
n = packs.size
mean = packs.mean()
s = packs.std(ddof=1)
se = s / np.sqrt(n)
t_crit = stats.t.ppf(0.975, df=n - 1)
print(f'mean = {mean:.2f} g, s = {s:.3f} g, SE = {se:.3f} g')
print(f't* = {t_crit:.3f}')
print(f'95% CI: [{mean - t_crit * se:.2f}; {mean + t_crit * se:.2f}] g')
low, high = stats.t.interval(0.95, df=n - 1, loc=mean, scale=se)
print(round(low, 2), round(high, 2))▸ Ожидаемый результат
mean = 99.75 g, s = 0.738 g, SE = 0.233 g t* = 2.262 95% CI: [99.22; 100.28] g 99.22 100.28
Время подготовки к экзамену у 16 студентов: x̄ = 52 часа, s = 8 часов. Найди 95%-й доверительный интервал для среднего. t₀,₉₇₅(15) = 2,131.
Показать решениеСкрыть решение
Предельная ошибка = t* · SE = 2,131 · 2 = 4,262.
Интервал: 52 ± 4,26 → [47,74; 56,26] часа.
Если увеличить выборку до 64 студентов, SE упадёт до 1, и интервал станет примерно вдвое уже (закон √n).
Проверка гипотезы ставит вопрос так: если бы нулевая гипотеза H₀ («различий нет») была верна, насколько вероятно было бы получить различие такое же или ещё больше, чем наблюдаемое? Эта вероятность — p-значение. Если p < α (обычно 0,05), H₀ отвергают. Одновыборочный t-тест сравнивает среднее с заданным числом, двухвыборочный — средние двух групп; поскольку дисперсии групп могут различаться, выбираем вариант Уэлча (equal_var=False).
- x̄₁, x̄₂средние групп
- s₁², s₂²выборочные дисперсии групп
- n₁, n₂объёмы групп
t-статистика Уэлча: разность средних, делённая на её стандартную ошибку. Чем больше |t|, тем меньше p.
import numpy as np
from scipy import stats
packs = np.array([99.2, 100.4, 98.7, 100.9, 99.5, 100.1, 99.8, 98.9, 100.6, 99.4])
res1 = stats.ttest_1samp(packs, popmean=100)
print(f'one-sample: t = {res1.statistic:.3f}, p = {res1.pvalue:.3f}')
group_a = np.array([72, 85, 78, 90, 66, 81, 77, 88, 74, 83])
group_b = np.array([80, 91, 86, 94, 79, 88, 85, 97, 82, 90])
print(group_a.mean(), group_b.mean())
res2 = stats.ttest_ind(group_b, group_a, equal_var=False)
print(f'Welch: t = {res2.statistic:.3f}, p = {res2.pvalue:.4f}')▸ Ожидаемый результат
one-sample: t = -1.071, p = 0.312 79.4 87.2 Welch: t = 2.581, p = 0.0194
Корреляция
Коэффициент корреляции Пирсона r измеряет силу и направление линейной связи между двумя переменными, от −1 до 1; r² показывает, какую долю вариации y линейно объясняет x. Коэффициент Спирмена ρ делает то же вычисление на рангах, поэтому устойчив к выбросам и улавливает любую монотонную связь.
- r−1 ≤ r ≤ 1; знак показывает направление, |r| — силу
- x̄, ȳсреднее каждой переменной
import numpy as np
from scipy import stats
hours = np.array([1, 2, 2, 3, 4, 5, 5, 6, 7, 8])
score = np.array([52, 55, 61, 60, 68, 70, 75, 74, 82, 88])
r, p = stats.pearsonr(hours, score)
rho, _ = stats.spearmanr(hours, score)
print(f'Pearson r = {r:.3f}, p = {p:.1e}')
print(f'Spearman rho = {rho:.3f}')
print(f'r squared = {r ** 2:.3f}')
print(np.corrcoef(hours, score).round(3))▸ Ожидаемый результат
Pearson r = 0.980, p = 6.5e-07 Spearman rho = 0.957 r squared = 0.961 [[1. 0.98] [0.98 1. ]]
np.corrcoef возвращает корреляционную матрицу.x = (1, 2, 3, 4, 5), y = (2, 4, 5, 4, 5). Найди коэффициент корреляции Пирсона.
Показать решениеСкрыть решение
xᵢ − x̄: −2, −1, 0, 1, 2; yᵢ − ȳ: −2, 0, 1, 0, 1.
Сумма произведений: 4 + 0 + 0 + 0 + 2 = 6.
∑ (xᵢ − x̄)² = 10, ∑ (yᵢ − ȳ)² = 4 + 0 + 1 + 0 + 1 = 6.
r = 6 / √(10 · 6) = 6 / √60 ≈ 0,775; r² ≈ 0,6.
Проверка:
np.corrcoef(x, y)[0, 1] → 0,7746.Для массива data выведи в первой строке через пробел среднее (1 знак после запятой), медиану и выборочное стандартное отклонение (ddof=1, 2 знака). Во второй строке выведи список выбросов по правилу Тьюки 1,5 · IQR.
import numpy as np
data = np.array([48, 52, 50, 47, 53, 51, 49, 95, 50, 52])
# line 1: mean (1 decimal), median, sample std (2 decimals)
# line 2: outliers as a list▸ Ожидаемый результат
54.7 50.5 14.28 [95]
В лаборатории сделали 8 измерений. В первой строке выведи выборочное среднее, во второй — нижнюю и верхнюю границы 95%-го доверительного интервала для среднего (через пробел); всё округли до 2 знаков после запятой. t* найди через stats.t.ppf.
import numpy as np
from scipy import stats
sample = np.array([23.1, 24.5, 22.8, 25.0, 23.9, 24.2, 23.5, 24.8])
# mean, then the 95% confidence interval▸ Ожидаемый результат
23.98 23.31 24.64
Главное
- Выборочная дисперсия делится на n − 1 (
ddof=1); для скошенных данных надёжнее медиана и IQR. - Правило Тьюки: значения вне [Q1 − 1,5 · IQR; Q3 + 1,5 · IQR] — выбросы.
- z = (x − μ) / σ;
norm.cdf,norm.sf,norm.ppfдают вероятности и квантили; правило 68–95–99,7. - Стандартная ошибка SE = s / √n; интервал для среднего — x̄ ± t* · SE.
- При p < α H₀ отвергают, но p — не вероятность H₀ и не величина эффекта.
- r Пирсона измеряет линейную связь, ρ Спирмена работает с рангами; корреляция не доказывает причинность.
Проверь себя
Вопросов: 10. Каждый правильный ответ приносит XP.