Automatic Relevance Determination или машинное обучение когда данных очень мало
Когда речь заходит про машинное обучение, обычно подразумевают большие объемы данных — миллионы или даже миллиарды транзакций, из которых надо сделать сложный вывод о поведении, интересах или текущем cостоянии пользователя, покупателя или какого-нибудь аппарата (робота, автомобиля, дрона или станка).
Однако в жизни обычного аналитика самой обычной компании много данных встречается нечасто. Скорее даже наоборот — у вас будет мало или очень мало данных — буквально десятки или сотни записей. Но анализ все же нужно провести. Причем не какой попало анализ, а качественный и достоверный.
Зачастую ситуация усугубляется еще и тем, что вы без труда можете нагенерить для каждой записи много признаков (чаще всего добавляют полиномы, разницу с предыдущим значением и значением за прошлый год, one-hot-encoding для категориальных признаков и т.п.). Вот только совсем нелегко разобраться, какие из них действительно полезны, а какие только усложняют модель и увеличивают ошибки вашего прозноза.
Для этого вы можете воспользоваться методами байесовой статистики, например, Automatic Relevance Determination. Это относительно новый метод, предложенный в 1992 Дэвидом Макаем (все началось с его докторской диссертации (PDF)). Предельно краткое, но непонятное изложение метода можно найти в этой PDF-презентации. Понятное, но излишне многословное объяснение можно посмотреть здесь:
Если совсем просто, то в ARD для каждого коэффициента выводится апостериорная оценка дисперсии, и затем коэффициенты с маленькой дисперсией обнуляются.
Посмотрим, как это работает на практике. Итак, у нас есть исходные данные — всего 30 точек (например, данные о 30 магазинах). Причем у каждого магазина по 30 признаков. И ваша задача — создать регрессионную модель (например, предсказать объем продаж по данным о местоположении, формату, торговой площади, конфигурации, численности персонала и другим параметрам магазина).
Строить обычную линейную регрессию в таких условиях будет чистой воды безумием. Давайте еще больше усугубим проблему тем, что лишь 5 признаков на самом деле имеют значение, а остальные — совершенно не отноcящиеся к делу данные.
Таким образом, пусть реальная зависимость представлена формулой Y = w * X + e, где e — случайная нормальная ошибка, а коэффициенты w равны [1, 2, 3, 4, 5, 0, 0, …,0], то есть только первые пять коэффициентов ненулевые, а признаки с 6-го по 30-й вообще никак не влияют на реальное значение Y. Однако мы этого не знаем. У нас есть только данные — X и Y —, а коэффициенты w нам надо рассчитать.
Теперь запустим ARD:
import numpy as np
from sklearn.linear_model import ARDRegression
N = 30
# данные о магазинах (в данном примере случайные)
X = np.random.random(size=(N,N)) * 10 + 1
# реальные коэффициенты [1 2 3 4 5 0 0 ... 0]
w = np.zeros(N)
w[:5] = np.arange(5) + 1
# добавим случайную ошибку
e = np.random.normal(0, 1, size=N)
# данные о продажах
Y = np.dot(X, w) + e
ard = ARDRegression()
ard.fit(X, Y)
print ard.coef_
И получаем просто впечатляющий результат:
array([ 1.01, 2.14, 2.95, 3.89, 4.79, 0., 0., 0., 0., 0.01,
0., 0., 0.31, 0.04, -0.05, 0. , 0., 0.01, 0., 0.,
0., 0., 0.01, 0., 0., 0., 0., 0.17, 0., 0. ])
Напомню, что реальные коэффициенты равны:
array([ 1., 2., 3., 4., 5., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0. ])
Таким образом, имея всего лишь 30 точек в 30-мерном пространстве, мы смогли построить модель, которая почти в точности повторяет реальную зависимость.
Для сравнения приведу коэффициенты, рассчитанные с помощью обычной линейной регрессии:
array([ 0.39 2.07 3.16 2.86 4.8 -0.21 -0.13 0.42 0.6 -0.21
-0.96 0.03 -0.46 0.57 0.89 0.15 0.24 0.11 -0.38 -0.36
-0.28 -0.01 0.43 -1.22 0.23 0.15 0.12 0.43 -1.11 -0.3 ])
линейной регрессии с L2-регуляризацией:
array([-0.36 1.48 2.67 3.44 3.99 -0.4 1.01 0.58 -0.81 0.78
-0.13 -0.23 -0.26 -0.24 -0.38 -0.24 -0.38 -0.25 0.54 -0.31
-0.21 -0.42 0.14 0.88 1.09 0.66 0.12 -0.07 0.08 -0.58])
И они обе не выдерживают никакой критики.
А вот линейная регрессия с L1-регуляризацией дает похожий результат:
array([ 0.68 1.9 2.88 3.86 4.88 -0.05 0.09 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0.01 0. 0. 0. 0. 0. 0. 0. ])
Как вы видите, L1-регуляризация даже лучше обнуляет незначимые коэффициенты, однако значимые коэффициенты могут быть рассчитаны с чуть большей погрешностью.
В общем, ARD — метод замечательный, но есть нюанс. Как и многие (можно даже сказать, почти все) байесовы методы, ARD чрезвычайно сложен с вычислительной точки зрения (хотя и хорошо параллелится). Поэтому на данных объемом несколько десятков-сотен точек он работает быстро (доли секунды), на нескольких тысячах — медленно (десятки-сотни секунд), а на десятках и сотнях тысяч — о-о-о-очень медленно (минуты и часы). Кроме того, ему необходим огромный объем оперативной памяти.
Однако это не так страшно. Если у вас много данных, то вы смело можете пользоваться классическими стат.методами, и они дадут достаточно хороший результат. Серьезные проблемы начинаются, когда данных мало, и обычные методы уже не работают. И тогда на помощь приходит байес.
ARD активно применяется в разнообразных kernel-методах, например, Relevance Vector Machine (RVM) — это Support Vector Machine (SVM) вместе с ARD. Также он удобен в классификаторах, когда вам необходимо оценить значимость имеющихся признаков. В общем, попробуйте — и вам понравится.