Как улучшить производительность RandomForest?

У меня есть набор для обучения размером 38 МБ (12 атрибутов с 420000 строк). Я использую снимок R для обучения модели с помощью randomForest. Это занимает несколько часов для меня.

rf.model <- randomForest(
              Weekly_Sales~.,
              data=newdata,
              keep.forest=TRUE,
              importance=TRUE,
              ntree=200,
              do.trace=TRUE,
              na.action=na.roughfix
            )

Я думаю, из-за na.roughfix для выполнения требуется много времени. В учебном наборе есть так много NA's.

Может ли кто-нибудь дать мне знать, как я могу улучшить производительность?

Моя конфигурация системы:

Intel(R) Core i7 CPU @ 2.90 GHz
RAM - 8 GB
HDD - 500 GB
64 bit OS

Ответ 1

(The tl; dr вам следует: a) увеличить nodeize до → 1 и b) исключить столбцы с очень низкой значимостью, возможно даже исключить (скажем) 80% ваших столбцов. Ваша проблема почти наверняка не na.roughfix, но если вы подозреваете, что запустите na.roughfix отдельно как отдельный шаг, перед вызовом randomForest. Сначала извлеките эту красную селедку.)

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

Основные параметры, влияющие на производительность randomForest:

  • mtry (меньше быстрее)
  • ntrees
  • количество функций/cols в данных - больше квадратично медленнее или хуже! См. Ниже
  • количество наблюдений/строк в данных
  • ncores (больше быстрее - до тех пор, пока используется параллельная опция)
  • повышение производительности путем установки значения = F и близости = F (не вычислять матрицу приближения)
  • Никогда не используйте безумный по умолчанию nodesize=1, для классификации! В пакете Breiman вы не можете напрямую установить maxdepth, но используйте nodesize в качестве прокси для этого, а также прочитайте все полезные советы по адресу: CrossValidated: "Практические вопросы по настройке Random Леса"
  • Итак, ваши данные имеют 4.2e + 5 строк, тогда если каждый node не должен быть меньше ~ 0.01%, попробуйте nodesize=42. (Сначала попробуйте nodeize = 4200 (1%), посмотрите, как быстро это произойдет, а затем повторите попытку, отрегулируйте узел вниз вниз. Эмпирически определите хороший узел для этого набора данных.)
  • время выполнения пропорционально ~ 2 ^ D_max, то есть полинома (-log1p (nodeize))
  • по желанию вы также можете ускорить с помощью выборки, см. strata,sampsize arguments

Тогда оценка времени выполнения первого порядка, обозначающая mtry = M, ntrees = T, ncores = C, nfeatures = F, nrows = R, maxdepth = D_max, равна:

Runtime proportional to: T * F^2 * (R^1.something) * 2^D_max / C

(Опять же, все ставки отключены, если вы превысите объем памяти. Также попробуйте запустить только одно ядро, затем 2, затем 4 и убедитесь, что вы действительно получаете линейное ускорение, а не замедление.) (Эффект большого R хуже линейного, а может быть квадратичного, поскольку разбиение по дереву должно учитывать все разделы строк данных, конечно, это несколько хуже, чем линейное. Убедитесь, что с помощью выборки или индексации, чтобы дать ей сказать 10% строки).

Совет. Сохранение множества функций с низкой значимостью квадратично увеличивает время выполнения, для сублинейного увеличения точности. Это связано с тем, что в каждом node мы должны учитывать все возможные варианты выбора (или любое другое число mtry). И внутри каждого дерева мы должны рассматривать все (F-choose-mtry) возможные комбинации функций. Итак, вот моя методология, делая "быстрый и грязный выбор функций для производительности":

  • генерировать дерево нормально (медленно), хотя использовать нормальный nodesize=42 или более крупный
  • посмотрите на значения rf $или randomForest::varImpPlot(). Выберите только функции top-K, где вы выбираете K; для примера, глупого, выберите K = 3. Сохраните весь этот список для справок в будущем.
  • теперь запустите дерево, но дайте ему newdata[,importantCols]
  • подтверждают, что скорость квадратично быстрее, а oob.error не намного хуже
  • Как только вы узнаете переменные значения, вы можете отключить importance=F
  • tweak mtry и nodeize (настраивать по одному), повторять и измерять скорость улучшения
  • постройте результаты своей работы по логарифмическим осям
  • опубликуйте результаты! Вы подтвердили это? Любые комментарии по использованию памяти?

(Обратите внимание, что приведенное выше не является статистически достоверной процедурой для фактического выбора функции, не полагайтесь на него для этого, прочитайте пакет randomForest для правильных методов для выбора функции RF).

Ответ 2

Я подозреваю, что do.trace может также потреблять время... вместо do.trace = TRUE, вы можете использовать do.trace = 5 (чтобы показать только 5 трасс), чтобы просто почувствовать ошибки. Для большого набора данных do.trace также займет много времени.