uralpro
uralpro личный блог
18 июня 2015, 14:19

Как быстро увеличить производительность алгоритма. Часть 2

NN2Main

Прошлая часть — см. в моем блоге.

В этой части разберем технику улучшения производительности стратегии, использующую множество моделей.

Одним из наиболее мощных методов улучшения прибыльности вашей модели является объединение нескольких алгоритмов в так называемое «множество». Теория состоит в том, что комбинируя разные модели и их предсказания, мы получаем более робастные результаты. Тесты показывают, что даже объединение простых моделей может быть производительнее более сложной, но единственной стратегии.

Существует три основных техники объединения:

Смешивание:

Смешивание основано на создании моделей, прогоняемых на немного различных тренировочных наборах и усреднения их результатов для получения одного предсказания. Тренировочный набор переделывается путем повторения или удаления вхождений данных, в результате чего получается несколько разных наборов. Этот процесс работает хорошо для нестабильных алгоритмов (например, деревья решений) или, если присутствует определенная степень случайности в процессе создания моделей ( как, например, начальные веса в нейронных сетях). Получив усредненное предсказание для коллекции моделей с высоким значением подгонки, мы можем уменьшить результирующую подгонку без увеличения недооценки, что приведет к лучшим результатам.

Форсирование:

Форсирование представляет собой пошаговый процесс стимулирования моделей к улучшению их результатов в тех местах, где ранее они показывали низкую производительность. Большие веса присваиваются диапазонам исходных данных, ранее неправильно классифицированных, и окончательное предсказание получается путем комбинирования взвешенного «голосования» всех моделей в множестве. Эта техника хорошо работает со «слабыми» классификаторами с тенденцией к недооценке данных, таких как простые деревья решений и наивный байесовский классификатор. Здесь используются алгоритмы с высокой недооценкой, множество которых в целом позволяет лучше детектировать необходимый сигнал.

Упаковка:

Ранее мы рассматривали множества, содержащие модели с одним и тем же алгоритмом, но разными параметрами. Что если у нас имеется множество моделей с разными алгоритмами? Упаковка включает широкий спектр моделей с использованием «метаобучения», позволяющего составить наилучшую комбинацию отдельных моделей. Предсказания, сделанные каждой моделью, подаются далее в «метаобучение», которое анализирует характеристики каждой модели и выдает окончательное предсказание. Упаковку лучше всего применять, когда вы владеете коллекцией моделей, основанных на отличных друг от друга алгоритмах.

Применим модель с высокой дисперсией результатов, простое дерево решений, чтобы продемонстрировать, как смешивание улучшает производительность.

Сначала, построим дерево решений, используя те же индикаторы, что и при создании наивного байесовского классификатора из части 1:

install.packages(“rpart”)
library(rpart)
install.packages(“foreach”)
library(foreach)

BaselineDecisionTree<-rpart(Class~EMA5Cross+RSI14ROC3+VolumeROC1,data=FeatureTrainingSet, cp=.001) 

Посмотрим, как модель ведет себя на тестовой выборке:

table(predict(BaselineDecisionTree,FeatureTestSet,type="class"),FeatureTestSet[,4],dnn=list('predicted','actual')) 

nnnb2

Доля правильных предсказаний около 51%. Сравнивая этот результат с долей на тренировочном наборе, которая была равна 73%, мы делаем вывод, что наше дерево решений имеет высокую подгонку под тренировочную выборку.

Давайте посмотрим, как техника смешивания поможет уменьшить подгонку. Язык R предоставляет пару различных алгоритмов смешивания, но мы создадим такой алгоритм самостоятельно, для лучшего управления параметрами смешивания:

length_divisor<-10
iterations<-1501
#Эти операторы определяют как мы создаем разные тренировочные наборы и сколько моделей включить во множество. Мы строим 1501 модель на случайных выборках по 1/10 от всех данных

BaggedDecisionTree<- foreach(m=1:iterations,.combine=cbind) %do% { training_positions <- sample(nrow(FeatureTrainingSet), size=floor((nrow(FeatureTrainingSet)/length_divisor)))
train_pos<-1:nrow(FeatureTrainingSet) %in% training_positions
BaselineDecisionTree<-rpart(Class~EMA5Cross+RSI14ROC3+VolumeROC1,data=FeatureTrainingSet[train_pos,])
predict(BaselineDecisionTree,newdata=FeatureTestSet)
}
#Это наш алгоритм смешивания.

CumulativePredictions<-apply(BaggedDecisionTree[,1:iterations],1,function(x){s<-(sum(x)/iterations)
round(s,0)})
#Сейчас нужно агрегировать предсказания наших 1501 моделей

FinalPredictions<-ifelse(CumulativePredictions==1,"DOWN","UP")
#Возвращаем решение - бинарный выбор из нашей классификации (цена возросла/снизилась) 

Снова проверяем производительность на тестовой выборке (так как дерево создано на случайных диапазонах из тренировочного набора, мы можем получить несколько разные результаты — это один из недостатков работы с нестабильными алгоритмами):

table(FinalPredictions,FeatureTestSet[,4],dnn=list('predicted','actual')) 

nnnb3

Намного лучше! Из-за уменьшения дисперсии нам удалось увеличить нашу производительность до 54%. В окончании, возьмем лучшую модель и прогоним ее на проверочной выборке, чтобы удостовериться, что мы построили робастный алгоритм.

Пока смешанные деревья решений на проверочной выборке и наивный байесовский классификатор из части 1 на тестовой выборке работают примерно с одинаковой производительностью. Автор отмечает, что ему больше нравятся модели с высокой недооценкой, чем с высокой подгонкой. Модели с тенденцией к недооценке могут работать не так хорошо на тренировочной и тестовой выборке, но вы можете быть  уверены, что они покажут те же результаты на новых данных. Модели с высокой подгонкой, с другой стороны, имеют высокий риск показать значительно более низкую производительность в этом случае.

По этим соображением, применим технику смешивания к нашему наивному байесовскому алгоритму. И в результате прогона на проверочном наборе получаем:

table(predict(FeatureNB,FeatureValSet),FeatureValSet[,4],dnn=list('predicted','actual')) 

nnnb4

Неплохо, и очень похоже на производительность на тренировочной и тестовой выборках! Наша окончательная производительность на проверочной выборке составила 54%. Значит мы построили хорошую робастную модель.

Заключение.

Первый шаг к увеличению производительности вашей модели — это понимание, в каком случае она подвержена недооценке/подгонке. Если вы сможете определить эти состояния, значит сможете и предпринять необходимые исправления.

Другие стратегии, применяемые в алгоритмической торговле и биржевых роботах смотрите на моем сайте.

13 Комментариев
  • Том Сойер
    18 июня 2015, 14:57
    Если бы было написано на нормальном языке программирования, то цены бы не было:)
      • Том Сойер
        18 июня 2015, 21:14
        uralpro, посмотрел в Википедии — толковый язычок, другое дело как его прикрутить к C# или Lua, изучайть Пайтон не охота
        • Marco
          18 июня 2015, 23:13
          Том Сойер, примеры на R, не на Пайтоне… Скрипты на R можно вызывать из C# (либо тупо процесс запускать, либо есть C++ интерфейс к R'у). Все это работает конечно только если скорость исполнения не критична. Или брать alglib и переписывать реализацию используемых методов R на C# (мы так и делаем).
          • Том Сойер
            19 июня 2015, 00:44
            Marco, да-да, я знаю, что на R, я неоднозначно выразился.
            Библиотечку потом общедоступной сделаете? :)
            • Marco
              19 июня 2015, 07:35
              Том Сойер, может, вам сразу деньги выслать? :) Возможно, я тоже неточно выразился. На C# переписывается не все подряд, конечно, а конкретные матмодели, которые сначала тестируются в R.
              • Том Сойер
                19 июня 2015, 08:26
                Marco, ну вдруг Вы патриот, помогающий всем жителям нашей многострадальной страны :)
                • Marco
                  19 июня 2015, 10:20
                  Том Сойер, помогаю, конечно, но не всем. Только родственникам. :)
  • Marco
    18 июня 2015, 16:59
    Спасибо, интересно. Как идея для расчета распределения капитала по алгоритмам — можно генерировать тестовые equities разными стратегиями, считать по ним minimum variance portfolio и распределять капитал в соответствии с полученными весами.
    3
      • Marco
        18 июня 2015, 23:15
        uralpro, одно время я так и делал, потом забил. Сейчас на глаз распределяю. Наверное это неправильно. :)
  • Lafert
    18 июня 2015, 23:19
    Я в свое время, используя классификаторы на микроструктурных данных (а имеено на ряде аггрегированных характеристик ордерлога), столкнулся со следующей проблемой:
    Есть, скажем, 2 состояния рынка. В одном он 95% времени, а в другом 5%. Очевидно, что классификаторы скатываются к ответу «всегда первое состояние». Искусственное «выравнивание» данных в выборках (к примеру, во время обучения подаем каждый элемент с состоянием 2 20 раз подряд) приводит к тому, что классификатор на реальных данных всегда видит состояние 2.

    Интересна Ваша мысль о такой проблеме.

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн