
— Не могли бы вы построить нам статистическую модель?
— С удовольствием. Можно посмотреть на ваши исторические данные?
— Данных у нас ещё нет. Но модель всё равно нужна.
Знакомый диалог, не правда ли? Далее возможны два варианта развития событий:
A. «Тогда приходите, когда появятся данные.» Вариант рассматриваться не будет как тривиальный.
Б. «Расскажите, какие факторы по вашему мнению наиболее важны.» Остаток статьи про это.
Под катом рассказ о том, что такое improper model, почему их красота устойчива и чего это стоит. Всё на примере многострадального набора данных о выживании пассажиров Титаника.
Откуда такое странное название
Из статьи The Robust Beauty of Improper Linear Models in Decision Making товарища Robyn M. Dawes, который в свою очередь ссылается на работы предшественников.
Приличные линейные модели (proper linear models) — те, в которых веса назначаются таким образом, чтобы полученная линейная комбинация предсказывала интересующую величину оптимальным образом. Примером может служить обычная линейная регрессия, подогнанная методом наименьших квадратов. [...]
Неприличные линейные модели (improper linear models) — те, в которых веса определяются неоптимально. Например, назначаются на основании интуиции, предыдущего опыта или приравниваются единице.
Обычная линейная модель выглядит так:
y = ?0 + ?1x1 + ?2x2 +… + ?mxm
Здесь y — оценка зависимой переменной, ?0 — свободный член, ?1...?m — коэффициенты регрессии, x1...xm — независимые переменные.
По причине отсутствия данных для определения значений ?1...?m мы поступим волюнтаристски: назначим им значения +1 (влияет положительно), -1 (влияет отрицательно) и 0 (не влияет).
Притянутый за уши пример
Характерными примерами статистических моделей, о которых шёл разговор в начале статьи, являются скоркарты для потребительского кредитования (они предсказывает вероятность глубокой просрочки или невозврата клиентом долга), модели отклика (они предсказывают вероятность того, что клиент ответит на предложение что-то купить или подписаться на продукт), модели оттока (предсказывают вероятность того, что клиент уйдёт к конкуренту) и т.п.
В данной статье будет использован более простой набор данных, скорее всего уже хорошо знакомый всем заинтересованным в теме машинного обучения читателям: список пассажиров Титаника. Ранее на Хабре на него уже смотрели:
- Предсказание выживания пассажиров Титаника при помощи Azure Machine Learning
- Титаник на Kaggle: вы не дочитаете этот пост до конца
Участники состязаний
ImproperModel— регрессия с единичными весами (тема этой статьи)ProperModel— логистическая регрессия с теми же независимыми переменнымиLogisticRegression— логистическая регрессия со всеми независимыми переменнымиRandomForest— один из широко распространённых современных алгоритмов
Как будем сравнивать
Список пассажиров разобьём на две части, на одной будем подгонять модель, на другой проверять качество её работы.
Чудес не бывает и совсем без каких-то знаний толковую модель не построить. В данном случае таким знанием будет галантность — женщин и детей при посадке в шлюпки пропускали вперёд. На основании этого априорного знания для регрессии с единичными весами назначаем переменной
female вес +1, а переменной age вес -1. Кроме того, пассажирам с билетами второго и третьего класса, у которых каюты в трюме, дальше бежать до шлюпок, поэтому переменной pclass назначаем вес -1.Чтобы два раза не вставать, тут же проведём нормализацию — поделим на стандартное отклонение в обучающей выборке. Это нужно для приведения независимых переменных к сравнимой шкале. Можно было поделить на диапазон и получить похожий результат.
Обратите внимание на то, что в модели с единичными весами мы не использовали информацию о том, кто выжил, а кто утонул, только стандартное отклонение независимых переменных для масштабирования.
Повторим эксперимент тысячу раз и посмотрим на результаты. Качество модели будем измерять с помощью коэффициента Gini (G1).
install.packages("pROC")
install.packages("randomForest")
library(pROC)
library(randomForest)
Читаем исходные данные, также доступны тут:
titanic3.csvdata <- read.csv('~/habr/unit_weights/titanic3.csv')
Зависимая переменная
surviveddata$survived <- as.factor(data$survived)
Исключаем переменные, у которых слишком много разных значений для нормального анализа
data$name <- NULL
data$ticket <- NULL
data$cabin <- NULL
data$home.dest <- NULL
data$embarked <- NULL
Не используем переменные из будущего
data$boat <- NULL
data$body <- NULL
Заменяем пропущенные значения средним
data$age[is.na(data$age)] <- mean(data$age, na.rm=TRUE)
data$fare[is.na(data$fare)] <- mean(data$fare, na.rm=TRUE)
Преобразуем пол в индикаторную переменную
data$female <- 0
data$female[which(data$sex == 'female')] <- 1
data$sex <- NULL
Смотрим на то, что осталось:
survived pclass age sibsp
0:809 Min. :1.000 Min. : 0.1667 Min. :0.0000
1:500 1st Qu.:2.000 1st Qu.:22.0000 1st Qu.:0.0000
Median :3.000 Median :29.8811 Median :0.0000
Mean :2.295 Mean :29.8811 Mean :0.4989
3rd Qu.:3.000 3rd Qu.:35.0000 3rd Qu.:1.0000
Max. :3.000 Max. :80.0000 Max. :8.0000
parch fare female
Min. :0.000 Min. : 0.000 Min. :0.000
1st Qu.:0.000 1st Qu.: 7.896 1st Qu.:0.000
Median :0.000 Median : 14.454 Median :0.000
Mean :0.385 Mean : 33.295 Mean :0.356
3rd Qu.:0.000 3rd Qu.: 31.275 3rd Qu.:1.000
Max. :9.000 Max. :512.329 Max. :1.000
Повторяем эксперимент тысячу раз
im.gini = NULL
pm.gini = NULL
lr.gini = NULL
rf.gini = NULL
set.seed(42)
for (i in 1:1000) {
Разбиваем пассажиров на две выборки — 70% отправляем в обучающую выборку, на остальных 30% будем мерять качество модели.
data$random_number <- runif(nrow(data),0,1)
development <- data[ which(data$random_number > 0.3), ]
holdout <- data[ which(data$random_number <= 0.3), ]
development$random_number <- NULL
holdout$random_number <- NULL
Модель с единичными весами
beta_pclass <- -1/sd(development$pclass)
beta_age <- -1/sd(development$age )
beta_female <- 1/sd(development$female)
im.score <- beta_pclass*holdout$pclass + beta_age*holdout$age + beta_female*holdout$female
im.roc <- roc(holdout$survived, im.score)
im.gini[i] <- 2*im.roc$auc-1
Обычная модель — логистическая регрессия с теми же независимыми переменными
pm.model = glm(survived~pclass+age+female, family=binomial(logit), data=development)
pm.score <- predict(pm.model, holdout, type="response")
pm.roc <- roc(holdout$survived, pm.score)
pm.gini[i] <- 2*pm.roc$auc-1
Логистическая регрессия со всеми переменными
lr.model = glm(survived~., family=binomial(logit), data=development)
lr.score <- predict(lr.model, holdout, type="response")
lr.roc <- roc(holdout$survived, lr.score)
lr.gini[i] <- 2*lr.roc$auc-1
Всеми любимый (и не без оснований) RandomForest
rf.model <- randomForest(survived~., development)
rf.score <- predict(rf.model, holdout, type = "prob")
rf.roc <- roc(holdout$survived, rf.score[,1])
rf.gini[i] <- 2*rf.roc$auc-1
}
Выводим результаты
bpd<-data.frame(ImproperModel=im.gini, ProperModel=pm.gini, LogisticRegression=lr.gini, RandomForest=rf.gini)
png('~/habr/unit_weights/auc_comparison.png', height=700, width=400, res=120, units='px')
boxplot(bpd, las=2, ylab="Gini", ylim=c(0,1), par(mar=c(9,5,1,1)+ 0.1), col=c("red","green","royalblue2","brown"))
dev.off()
mean(im.gini)
mean(pm.gini)
mean(lr.gini)
mean(rf.gini)
mean(im.gini)/mean(rf.gini)
mean(pm.gini)/mean(rf.gini)
mean(lr.gini)/mean(rf.gini)
mean(rf.gini)/mean(rf.gini)
Результаты
| Модель | Gini | В процентах от лучшего |
|---|---|---|
| ImproperModel | 0.639 | 90.4% |
| ProperModel | 0.667 | 94.3% |
| LogisticRegression | 0.679 | 96.0% |
| RandomForest | 0.707 | 100% |

Далекоидущие выводы
Пессимист скажет, что модель с единичными весами в этом сравнении заняла последнее место, и это верно. Но так же верно, что она набрала 90% от лучшего результата без использования исторических данных, и отстала от обычной логистической регрессии с теми же независимыми переменными всего на 4%.
Почему так происходит
В статье с необычным названием Estimating Coefficients in Linear Models: It Don't Make No Nevermind её автор (Ховард Вайнер) приводит такую теорему равных весов:
Если k линейно независимых переменных xi (i = 1, ..., k) с нулевым средним значением и единичной дисперсией используются для предсказания переменной y, которая также отмасштабирована до нулевого среднего и единичной дисперсии, и стандартизованные значения коэффициентов регрессии по методу наименьших квадратов ?i (i = 1, ..., k) равномерно распределены на интервале [0.25, 0.75], то при переходе к равным весам (0.5) матожидание уменьшения доли дисперсии зависимой переменной, объясняемой моделью, будет меньше k/96. Потери ещё меньше, если xi коррелированы между собой.
В приведённом выше примере регрессия логистическая, но эффект всё равно виден.
Далее в той же статье автор отмечает, что модели с единичными весами устойчивы в частности потому, что они не подвержены влиянию выбросов в обучающей выборке и их невозможно перетренировать.
Комментарии (8)

knagaev
07.12.2015 18:09+2Почему для proper и improper выбрали именно такой вариант, как приличные и неприличные, соответственно? :)

dimview
08.12.2015 04:04А как надо было перевести? translate.ru предлагает «надлежащий, приличный, присущий, самый» и «неподходящий, неуместный, неправильный, непристойный, незаконный».
А «improper model» переводит как «неподходящая модель», что совсем неправильно — модель-то как раз подходящая.
knagaev
08.12.2015 07:20+2У proper много вариантов перевода.
В данном случае наверно больше подходит совершенный или точный, и их антонимы для improper.
А то напомнило известный случай — «парень клеит модель в клубе».
dimview
08.12.2015 15:51Варианты «совершенный» и «точный» не подходят — модели по определению являются грубым приближением к реальности, к тому же коэффициенты подгоняем по случайной выборке, то есть неизбежны ошибки. На приведённом графике видно, что improper model зачастую показывает лучше результат, чем proper (распределения Gini перекрываются).
Кроме того, в оригинале тогда было бы perfect или exact, а судя по совсем не статистическому слову beauty там та же игра слов про «клеить модель в клубе».
ServPonomarev
То есть, имея вектор признаков длиной К, можно перебрать 3^K вариантов (-1 0 1 на каждый из признаков) и выбрать наилучшую модель? Хорошо, а дальше что?
dimview
Нет, идея в том, чтобы вообще ничего не перебирать. Не обучать модель, а выбрать значения коэффициентов исключительно на основании априорных знаний.