library(tidyverse)
8 Основы статистического анализа
8.1 О статистике
Статистика имеет большое значение в науке, и все чаще она позволяет принимать решения правительствам, корпорациям и т. п. В области принятия решений статистику сейчас теснят методы машинного обучения, однако в науке все же статистика продолжает занимать важное место, помогая подтвердить обнаруженные факты, принимать решения на основе данных и делать предсказания.
Важно подчеркнуть разницу между статистикой и машинным обучением: она заключается в основных целях. Статистика в основном занимается выводами и моделированием процессов, которые генерируют наблюдаемые данные, в то время как машинное обучение фокусируется на поиске обобщаемых предиктивных закономерностей в данных. Несмотря на то, что некоторые методы используются как в статистике, так и в машинном обучении, все же эти две области имеют разные цели и подходы.
Важно помнить, что статистика позволяет лишь моделировать процессы, которые стоят за генерацией данных. В связи с этим не стоит считать, что статистический вывод позволяет узнать правду или сделать правильный выбор: правильность и истинность любого конкретного случая зависит от научных установок исследователя, ответственного применения методов с соблюдением всех ограничений на их применение, качества сбора данных и теоретического обоснования процедуры анализа. Я призываю смотреть на статистику как на инструмент, который помогает в принятии решений, предсказании и моделировании: если вы забили шуруп молотком, то, вероятно, вашу задачу вы решили, но молоток сам по себе не несет ответственности за результат.
Сейчас широко распространены две школы статистического анализа: фреквентисткий (еще можно встретить термин частотный) и байесовский. Разница между этими подходами заключается в их основных принципах. Частотный подход основан на оценке статистического параметра на основе частоты его появления в выборке, в то время как байесовский подход позволяет представить оценку статистического параметра как распределение вероятностей, соединяя априорные знания о предметной области и новые данные. Фреквентистские методы получили широкое распространение в XX веке, а байесовские методы применялись задолго до фреквентистских, однако с развитием вычислительных мощностей в XXI веке популярность байесовских методов растет. В данной главе мы будем опираться на фреквентистские методы, так как погружение в байесовские методы требует значительной подготовки.
8.2 Тест Стьюдента (t-тест)
Первый статистический метод, который обычно обсуждают в фреквентистской статистике — это тест Стьюдента. Основное его применение заключается в сравнении средних значений двух групп (двухвыборочный тест) или среднего одной группы с некоторым значением (одновыборочный тест). Среди возможных задач, которые можно решить при помощи теста Стьюдента:
- оценить эффект нового лекарства по сравнению со старым;
- оценить эффект нового метода обучения на результатах тестов групп студентов;
- оценить отличие какого-нибудь параметра популяции (например, избыточного веса) по сравнению с нормой.
Теперь мы обсудим стандартную процедуру фреквентистской статистики. Допустим мы сравниваем средние двух групп А и B. Принято создавать две гипотезы:
- \(H_0\) — (нулевая гипотеза) разница между группами не является статистически значимой, т. е. наблюдаемые данные происходят из одного ожидаемого распределения.
- \(H_1\) — (альтернативная гипотеза) разница является статистически значимой, т. е. наблюдаемые данные не происходят из одного ожидаемого распределения.
Нулевая гипотеза — это гипотеза, которую каждый исследователь в случае успеха отвергнет и примет альтернативную. После применения статистического критерия (каждый критерий зависит от конкретного статистического теста, а выбор теста зависит от типа данных) исследователь считает вероятность наблюдения такого или более экстремального результат, если верна нулевая гипотеза (p-value, p-уровень значимости).
В тесте Стьюдента таким распределением является t-распредление. Распределение, которое напоминает нормальное распределение, но имеет более широкие края:
T-распределение имеет один параметр, который принято называть степенями свободы (degree of freedom, df). Чем больше степеней свободы, тем больше t-распределение похоже на нормальное распределение. Обычно этот параметр напрямую связывают с количеством наблюдений.
tibble(x = rep(seq(-7, 7, by = 0.01), 4),
df = rep(c(5, 15, 30, 75), 1401),
y = dt(x, df =df)) |>
ggplot(aes(x, y, color = as.factor(df)))+
geom_line() +
labs(color = "")
Давайте разберем на примере. Из статьи (Stepanova 2011) мы знаем, что носители русского языка в среднем говорят 5.31 слога в секунду со стандартным отклонением 1,93 (мужчины 5.46 слога в секунду со средним отклонением 2.02, женщины 5.23 слога в секунду со средним отклонением 1.84, дети 3.86 слога в секунду со средним отклонением 1.67). Мы опросили 30 носителей деревни N и выяснили, что среднее равно 7, а стандартное отклонение равно 2. Является ли данная разница статистически значимой? Рассмотрим данные
set.seed(42)
<- rnorm(n = 30, mean = 7, sd = 2)
data
data
[1] 9.741917 5.870604 7.726257 8.265725 7.808537 6.787751 10.023044
[8] 6.810682 11.036847 6.874572 9.609739 11.573291 4.222279 6.442422
[15] 6.733357 8.271901 6.431494 1.687089 2.119066 9.640227 6.386723
[22] 3.437383 6.656165 9.429349 10.790387 6.139062 6.485461 3.473674
[29] 7.920195 5.720010
Вот так можно визуализировать наш вопрос:
tibble(data) |>
ggplot(aes(data))+
geom_dotplot()+
geom_vline(xintercept = mean(data), size = 2, linetype = 2)+
geom_vline(xintercept = 5.31, size = 2, linetype = 2, color = "red")+
annotate(geom = "text", x = 3, color = "red", y = 0.75, label = "среднее согласно\n[Stepanova 2011]", size = 5)
Применяем тест Стьюдента. Так как мы сравниваем нашу выборку с некоторым эталонным значением, мы применяем одновыборочный тест Стьюдента, а эталонное значение записываем в аргумент mu
:
t.test(data, mu = 5.31)
One Sample t-test
data: data
t = 3.9871, df = 29, p-value = 0.0004143
alternative hypothesis: true mean is not equal to 5.31
95 percent confidence interval:
6.199903 8.074444
sample estimates:
mean of x
7.137174
Если мы хотим визуализировать t-статистику, которую мы получили на t-распределении, получится вот такой график:
tibble(x = seq(-7, 7, by = 0.01),
y = dt(x, df = 29)) |>
ggplot(aes(x, y))+
geom_line()+
geom_vline(linetype = 2, xintercept = 3.9871)+
labs(title = "t-распределение с параметром df = 29")
Если бы значение t-критерия оказалось где-то посередине, то тест Стьюдента бы выдал p-value больше 0.05 и тогда у нас бы не было оснований ни для отвержения, ни для принятия нулевой гипотезы.
8.2.1 Двухвыборочный тест Стьюдента
Логика двухвыборочного теста идентична логике одновыброчного, с тем лишь исключением, что мы сравниваем две группы:
Welch Two Sample t-test
data: sample_1 and sample_2
t = -5.0632, df = 41.295, p-value = 9.005e-06
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-11.046695 -4.748026
sample estimates:
mean of x mean of y
40.93768 48.83504
На практике разница видна только в названии аргументов. Представим, что у нас есть две выборки:
sample_1
[1] 46.85479 37.17651 41.81564 43.16431 42.02134 39.46938 47.55761 39.52670
[9] 50.09212 39.68643 46.52435 51.43323 33.05570 38.60606 39.33339 43.17975
[17] 38.57874 26.71772 27.79767 46.60057 38.46681 31.09346 39.14041 46.07337
[25] 49.47597
sample_2
[1] 48.06289 48.84229 42.06577 52.07044 47.12002 52.04953 53.17177 54.65797
[9] 47.25983 52.27230 42.27346 46.46993 46.17092 39.13607 50.16255 50.92699
[17] 48.37524 53.41173 46.72983 43.84274 51.94768 46.34873 56.49846 48.05849
[25] 52.95042
Тогда для того, чтобы применить тест Стьюдента, нужно запустить следующий код:
t.test(sample_1, sample_2)
Welch Two Sample t-test
data: sample_1 and sample_2
t = -5.0632, df = 41.295, p-value = 9.005e-06
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-11.046695 -4.748026
sample estimates:
mean of x mean of y
40.93768 48.83504
8.3 Регрессионный анализ
8.3.1 Основы
Суть регрессионного анализа заключается в моделировании связи между двумя и более переменными при помощи прямой на плоскости. Формула прямой зависит от двух параметров: свободного члена (intercept) и углового коэффициента (slope).
Когда мы пытаемся научиться предсказывать данные одной переменной \(Y\) при помощи другой переменной \(X\), мы получаем похожую формулу:
\[y_i = \hat\beta_0 + \hat\beta_1 \times x_i + \epsilon_i,\] где
- \(x_i\) — \(i\)-ый элемент вектора значений \(X\);
- \(y_i\) — \(i\)-ый элемент вектора значений \(Y\);
- \(\hat\beta_0\) — оценка случайного члена (intercept);
- \(\hat\beta_1\) — оценка углового коэффициента (slope);
- \(\epsilon_i\) — \(i\)-ый остаток, разница между оценкой модели (\(\hat\beta_0 + \hat\beta_1 \times x_i\)) и реальным значением \(y_i\); весь вектор остатков иногда называют случайным шумом (на графике выделены красным).
Задача регрессии — оценить параметры \(\hat\beta_0\) и \(\hat\beta_1\), если нам известны все значения \(x_i\) и \(y_i\) и мы пытаемся минимизировать значения \(\epsilon_i\). В данном случае, задачу можно решить аналитически и получить следующие формулы:
\[\hat\beta_1 = \frac{(\sum_{i=1}^n x_i\times y_i)-n\times\bar x \times \bar y}{\sum_{i = 1}^n(x_i-\bar x)^2}\]
\[\hat\beta_0 = \bar y - \hat\beta_1\times\bar x\]
8.3.2 Первая регрессия
Давайте попробуем смоделировать количество слов и в рассказах М. Зощенко в зависимости от длины рассказа:
<- read_csv("https://raw.githubusercontent.com/agricolamz/daR4hs/main/data/w8_tidy_zoshenko.csv")
zoshenko
|>
zoshenko filter(word == "и") |>
distinct() ->
zoshenko_filtered
|>
zoshenko_filtered ggplot(aes(n_words, n))+
geom_point()+
labs(x = "количество слов в рассказе",
y = "количество и")
Давайте избавимся от них и добавим регрессионную линию при помощи функции geom_smooth()
:
|>
zoshenko_filtered ggplot(aes(n_words, n))+
geom_point()+
geom_smooth(method = "lm", se = FALSE)+
labs(x = "количество слов в рассказе",
y = "количество и")
Чтобы получить формулу этой линии нужно запустить функцию, которая оценивает линейную регрессию:
<- lm(n~n_words, data = zoshenko_filtered)
fit fit
Call:
lm(formula = n ~ n_words, data = zoshenko_filtered)
Coefficients:
(Intercept) n_words
-1.47184 0.04405
Вот мы и получили коэффициенты, теперь мы видим, что наша модель считает следующее:
\[n = -1.47184 + 0.04405 \times n\_words\]
Более подробную информацию можно посмотреть, если запустить модель в функцию summary()
:
summary(fit)
Call:
lm(formula = n ~ n_words, data = zoshenko_filtered)
Residuals:
Min 1Q Median 3Q Max
-19.6830 -4.3835 0.8986 4.6486 19.6413
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.471840 2.467149 -0.597 0.553
n_words 0.044049 0.003666 12.015 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.945 on 64 degrees of freedom
Multiple R-squared: 0.6928, Adjusted R-squared: 0.688
F-statistic: 144.4 on 1 and 64 DF, p-value: < 2.2e-16
В разделе Coefficients
содержится информацию про наши коэффициенты:
Estimate
– полученная оценка коэффициентов;Std. Error
– стандартная ошибка среднего;t value
– \(t\)-статистика, полученная при проведении одновыборочного \(t\)-теста, сравнивающего данный коэфициент с 0;Pr(>|t|)
– полученное \(p\)-значение;Multiple R-squared
иAdjusted R-squared
— одна из оценок модели, показывает связь между переменными. Без поправок совпадает с квадратом коэффициента корреляции Пирсона.F-statistic
— \(F\)-статистика полученная при проведении теста, проверяющего, не является ли хотя бы один из коэффицинтов статистически значимо отличным от нуля. Совпадает с результатами дисперсионного анализа (ANOVA).
Теперь мы можем даже предсказывать значения, которые мы еще не видели. Например, сколько будет и в рассказе Зощенко длиной 1000 слов?
predict(fit, tibble(n_words = 1000))
1
42.57715
8.3.3 Категориальные переменные
Что если мы хотим включить в наш анализ категориальные переменные? Давайте рассмотрим простой пример с рассказами Чехова и Зощенко, которые мы рассматривали в прошлом разделе. Мы будем анализировать логарифм доли слова деньги:
<- read_csv("https://raw.githubusercontent.com/agricolamz/daR4hs/main/data/w8_tidy_chekhov.csv")
chekhov <- read_csv("https://raw.githubusercontent.com/agricolamz/daR4hs/main/data/w8_tidy_zoshenko.csv")
zoshenko
|>
chekhov bind_rows(zoshenko) |>
filter(str_detect(word, "деньг")) |>
group_by(author, titles, n_words) |>
summarise(n = sum(n)) |>
mutate(log_ratio = log(n/n_words)) ->
checkov_zoshenko
Визуализация выглядит так:
Красной точкой обозначены средние значения, так что мы видим, что между двумя писателями есть разница, но является ли она статистически значимой? В прошлом разделе мы рассмотрели, что в таком случае можно сделать t-test:
t.test(log_ratio~author,
data = checkov_zoshenko,
var.equal = TRUE) # здесь я мухлюю, отключая поправку Уэлча
Two Sample t-test
data: log_ratio by author
t = 6.3897, df = 124, p-value = 3.045e-09
alternative hypothesis: true difference in means between group Зощенко and group Чехов is not equal to 0
95 percent confidence interval:
1.009976 1.916472
sample estimates:
mean in group Зощенко mean in group Чехов
-4.878002 -6.341226
Разница между группами является статистически значимой (t(125) = 5.6871, p-value = 8.665e-08).
Для того, чтобы запустить регрессию на категориальных данных, категориальная переменная автоматически разбивается на группу бинарных dummy-переменных:
tibble(author = c("Чехов", "Зощенко"),
dummy_chekhov = c(1, 0),
dummy_zoshenko = c(0, 1))
Дальше для регрессионного анализа выкидывают одну из переменных, так как иначе модель не сойдется (dummy-переменных всегда n-1, где n — количество категорий в переменной).
tibble(author = c("Чехов", "Зощенко"),
dummy_chekhov = c(1, 0))
Если переменная dummy_chekhov
принимает значение 1, значит речь о рассказе Чехова, а если принимает значение 0, то о рассказе Зощенко. Если вставить нашу переменную в регрессионную формулу, получится следующее:
\[y_i = \hat\beta_0 + \hat\beta_1 \times \text{dummy\_chekhov} + \epsilon_i\]
Так как dummy_chekhov
принимает либо значение 1, либо значение 0, то получается, что модель предсказывает лишь два значения:
\[y_i = \left\{\begin{array}{ll}\hat\beta_0 + \hat\beta_1 \times 1 + \epsilon_i = \hat\beta_0 + \hat\beta_1 + \epsilon_i\text{, если рассказ Чехова}\\ \hat\beta_0 + \hat\beta_1 \times 0 + \epsilon_i = \hat\beta_0 + \epsilon_i\text{, если рассказ Зощенко} \end{array}\right.\]
Таким образом, получается, что свободный член \(\beta_0\) и угловой коэффициент \(\beta_1\) в регрессии с категориальной переменной получают другую интерпретацию. Одно из значений переменной кодируется при помощи \(\beta_0\), а сумма коэффициентов \(\beta_0+\beta_1\) дает другое значение переменной. Так что \(\beta_1\) — это разница между оценками двух значений переменной.
Давайте теперь запустим регрессию на этих же данных:
<- lm(log_ratio~author, data = checkov_zoshenko)
fit2 summary(fit2)
Call:
lm(formula = log_ratio ~ author, data = checkov_zoshenko)
Residuals:
Min 1Q Median 3Q Max
-2.24643 -0.61293 -0.05149 0.65130 3.09655
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -4.878 0.210 -23.22 < 2e-16 ***
authorЧехов -1.463 0.229 -6.39 3.05e-09 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.9393 on 124 degrees of freedom
Multiple R-squared: 0.2477, Adjusted R-squared: 0.2416
F-statistic: 40.83 on 1 and 124 DF, p-value: 3.045e-09
Во-первых, стоит обратить внимание на то, что R сам преобразовал нашу категориальную переменную в dummy-переменную authorЧехов
. Во-вторых, можно заметить, что значения t-статистики и p-value совпадают с результатами, полученными нами в t-тесте выше. Статистически значимый коэффициент при аргументе authorЧехов
следует интерпретировать как разницу средних между логарифмом долей в рассказах Чехова и Зощенко.
8.3.4 Множественная регрессия
Множественная регрессия позволяет проанализировать связь между переменной и несколькими предикторами. Формула множественной регрессии не сильно отличается от формулы обычной линейной регрессии:
\[y_i = \hat\beta_0 + \hat\beta_1 \times x_{1i}+ \dots+ \hat\beta_n \times x_{ni} + \epsilon_i,\]
- \(x_{ki}\) — \(i\)-ый элемент векторов значений \(X_1, \dots, X_n\);
- \(y_i\) — \(i\)-ый элемент вектора значений \(Y\);
- \(\hat\beta_0\) — оценка случайного члена (intercept);
- \(\hat\beta_k\) — коэфциент при переменной \(X_{k}\);
- \(\epsilon_i\) — \(i\)-ый остаток, разница между оценкой модели (\(\hat\beta_0 + \hat\beta_1 \times x_i\)) и реальным значением \(y_i\); весь вектор остатков иногда называют случайным шумом.
В такой регрессии предикторы могут быть как числовыми, так и категориальными (со всеми вытекающими последствиями, которые мы обсудили в предыдущем разделе). Такую регрессию чаще всего сложно визуализировать, так как в одну регрессионную линию вкладываются сразу несколько переменных.
Попробуем предсказать длину лепестка на основе длины чашелистиков и вида ириса:
|>
iris ggplot(aes(Sepal.Length, Petal.Length, color = Species))+
geom_point()
Запустим регрессию:
<- lm(Petal.Length ~ Sepal.Length + Species, data = iris)
fit3 summary(fit3)
Call:
lm(formula = Petal.Length ~ Sepal.Length + Species, data = iris)
Residuals:
Min 1Q Median 3Q Max
-0.76390 -0.17875 0.00716 0.17461 0.79954
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.70234 0.23013 -7.397 1.01e-11 ***
Sepal.Length 0.63211 0.04527 13.962 < 2e-16 ***
Speciesversicolor 2.21014 0.07047 31.362 < 2e-16 ***
Speciesvirginica 3.09000 0.09123 33.870 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.2826 on 146 degrees of freedom
Multiple R-squared: 0.9749, Adjusted R-squared: 0.9744
F-statistic: 1890 on 3 and 146 DF, p-value: < 2.2e-16
Все предикторы статистически значимы. Давайте посмотрим предсказания модели для всех наблюдений:
|>
iris mutate(prediction = predict(fit3)) |>
ggplot(aes(Sepal.Length, prediction, color = Species))+
geom_point()
Всегда имеет смысл визуализировать, что нам говорит наша модель. Если использовать пакет ggeffects
(или предшествовавший ему пакет effects
), это можно сделать не сильно задумываясь, как это делать:
library(ggeffects)
plot(ggpredict(fit3, terms = c("Sepal.Length", "Species")))
Как видно из графиков, наша модель имеет одинаковые угловые коэффициенты (slope) для каждого из видов ириса и разные свободные члены (intercept).
summary(fit3)
Call:
lm(formula = Petal.Length ~ Sepal.Length + Species, data = iris)
Residuals:
Min 1Q Median 3Q Max
-0.76390 -0.17875 0.00716 0.17461 0.79954
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.70234 0.23013 -7.397 1.01e-11 ***
Sepal.Length 0.63211 0.04527 13.962 < 2e-16 ***
Speciesversicolor 2.21014 0.07047 31.362 < 2e-16 ***
Speciesvirginica 3.09000 0.09123 33.870 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.2826 on 146 degrees of freedom
Multiple R-squared: 0.9749, Adjusted R-squared: 0.9744
F-statistic: 1890 on 3 and 146 DF, p-value: < 2.2e-16
\[y_i = \left\{\begin{array}{ll} -1.70234 + 0.63211 \times \text{Sepal.Length} + \epsilon_i\text{, если вид setosa}\\ -1.70234 + 2.2101 + 0.63211 \times \text{Sepal.Length} + \epsilon_i\text{, если вид versicolor} \\ -1.70234 + 3.09 + 0.63211 \times \text{Sepal.Length} + \epsilon_i\text{, если вид virginica} \end{array}\right.\]
8.3.5 Сравнение моделей
Как нам решить, какая модель лучше? Ведь теперь можно добавить сколько угодно предикторов? Давайте создадим новую модель без предиктора Species
:
<- lm(Petal.Length ~ Sepal.Length, data = iris) fit4
- можно сравнивать статистическую значимость предикторов
- можно сравнивать \(R^2\)
summary(fit3)$adj.r.squared
[1] 0.9743786
summary(fit4)$adj.r.squared
[1] 0.7583327
- чаще всего используют так называемые информационные критерии, самый популярный – AIC (Akaike information criterion). Само по себе значение этого критерия не имеет смысла – только в сравнении моделей, построенных на похожих данных. Чем меньше значение, тем модель лучше.
AIC(fit3, fit4)
8.3.6 Послесловие
- существуют ограничения на применение линейной регрессии
- связь между предсказываемой переменной и предикторами должна быть линейной
- остатки должны быть нормально распределены (оценивайте визуально)
- дисперсия остатков вокруг регрессионной линии должна быть постоянна (гомоскедастичность)
- предикторы не должны коррелировать друг с другом
- все наблюдения в регрессии должны быть независимы друг от друга
Вот так вот выглядят остатки нашей модели на основе датасета iris
. Смотрите пост, в котором обсуждается, как интерпретировать график остатков.
plot(fit3, which=c(1, 2))
- существуют трюки, позволяющие автоматически отбирать модели (см. функцию
step()
) - существует достаточно большое семейство регрессий, которые зависят от типа независимой (предсказываемой) переменной или ее распределения
- логистическая (если предсказываемая переменная имеет два возможных исхода)
- мультиномиальная (если предсказываемая переменная имеет больше двух возможных дискретных исходов)
- нелинейные регрессии (если связь между переменными нелинейна)
- регрессия со смешанными эффектами (если внутри данных есть группировки, т. е. наблюдения не независимы)
- и другие.