Автор: Десислава Христова
Библиотеката Hyperopt е създадена специално за оптимизация на модели за машинно обучение и позволява бързо и лесно да открием кои са най-добрите параметри и техните стойности вместо да се опитваме да ги търсим чрез ръчни настройки.
В тази статия ще използваме Hyperopt, за да открием оптималните параметри на модел за машинно обучение в контекста на практическа задача и ще видим как се изменят резултатите след оптимизация.
Hyperopt използва Бейсовата оптимизация за откриване на оптималните параметри, т.е. подходът е вероятностен, като се преминава през пространство от параметри и техните стойности, за да се намери минимума на конкретна функция. За разлика от други методи като рандомизираното и решетъчното търсене на Scikit-learn, при Hyperopt се взимат под внимание предишни итерации, когато се търсят оптималнитe параметри.
Необходимо е да преминем през няколко стъпки, когато оптимизираме модел чрез библиотеката Hyperopt:
1/ Дефиниране на целевата функция
Целевата функция е тази, на която търсим минимума. Това често е функция на загубите (loss function). Например, ако искаме да намерим тези стойности на параметрите, при които средната квадратична грешка е най-ниска.
2/ Дефиниране на пространство от параметри и техните възможни стойности
Hyperopt предоставя много възможности за настройки на параметрите благодарение на функциите от модула hp. Поддържат се числови и нечислови стойности:
За цели и дробни числа може да се използва и hp.choice(), когато искаме да изберем една конкретна стойност от определени такива в списък.
Употребата на тези функции следва малко по-надолу в практическия пример.
3/ Инициализиране на Trials обекта
В Trials обекта се съхраняват всички резултати от извършеното търсене на оптимални параметри. Получаваме ги под формата на списък от речници.
4/ Избор на оптимизационен алгоритъм, който да търси в пространството от параметри
Hyperopt предлага няколко варианта за оптимизационен алгоритъм, като основен е Tree Parzen Estimator (TPE). При него се изгражда вероятностен модел, който е базиран на теоремата на Бейс.
Формулата е следната:
Стойностите на параметрите се разделят на 2 части на базата на определен праг, с който се сравнява оценката на целевата функция. Едната част е l(x), където резултатите са хубави и стойността на прага е по-висока от оценката на целевата функция. Другата е g(x), където резултатите са лоши, а прагът е по-нисък от оценката.
Правят се последващи математически изчисления, като идеята е отношението между l(x) и g(x) да се максимизира. На базата на това се избират конкретни параметри и стойностите им, които да се използват, като се взимат под внимание и предишни итерации. Това допринася за по-добри резултати с течение на итерациите.
5/ Прилагане на функцията fmin()
В основата на библиотеката Hyperopt стои функцията fmin(), чрез която се прилага Бейсовата оптимизация. Нейните основни параметри са следните:
За да видим на практика възможностите на Hyperopt, ще направим един пример, в който задачата е да определим дали даден клиент на банка ще се възползва от оферта за срочен депозит или не, т.е. имаме задача за бинарна класификация и двете възможни стойности за целевата променлива са "да" или "не". Данните, които ще използваме са предварително изчистени - премахнати са ненужни колони и екстремни стойности, направен е визуален анализ и т.н.
Ако искате да научите повече за стъпките от етапа на предварителна обработка на данните, можете да прочетете в следните статии:
Примерът, който ще разгледаме по-надолу, можете да изтеглите от тук.
Ще използваме алгоритъма RandomForest при изграждане на модела за машинно обучение, като неговите параметри и техните подразбиращи се стойности можете да видите в таблицата по-долу:
Parameter | Default value | |
---|---|---|
0 | criterion | gini |
1 | max_depth | None |
2 | max_features | auto |
3 | min_samples_leaf | 1 |
4 | min samples_split | 2 |
5 | n_estimators | 100 |
1 2 3 4 5 6 7 8 |
# Създаване на модела с параметри по подразбиране rf = RandomForestClassifier() # Обучение на модела rf.fit(X_train_res, y_train_res) # Тест на модела rf_pred = rf.predict(X_test) |
Резултати:
Metrics | Values | |
---|---|---|
0 | Overall Accuracy | 0.714925 |
1 | Overall Error | 0.285075 |
2 | Precision | 0.665428 |
3 | Specificity | 0.769231 |
4 | Sensitivity | 0.639286 |
5 | F1_score | 0.652095 |
В 71% от всички случаи класификаторът е разпределил правилно обектите в съответните класове. Определил е, че в 67% от случаите хората ще приемат офертата за депозит и те в действителност биха приели. Открил е 77% от хората, които няма да се възползват от офертата и 64% от тези, които ще приемат.
Ако искате да научите по-подробно за тези метрики, можете да прочетете в статията Machine Learning: Метрики за оценка на класификационни модели.
1 2 |
# Откриване на разликата между определените от класификатора класове и тези в действителност error = df_rf['Actual'].mean() - df_rf['Predicted'].mean() |
41.79% в тестовата извадка са от положителния клас, а класификаторът е определил 40.14% правилно, т.е. грешката е 1.65%.
Първата стъпка, която трябва да предприемем при оптимизация на модела с библиотеката Hyperopt, е да създадем пространство от параметри и техните стойности.
1 2 3 4 5 6 7 8 |
# Създаване на речник с параметри и техни възможни стойности params = {'criterion': hp.choice('criterion', ['entropy', 'gini']), 'max_depth': hp.quniform('max_depth', 1, 11, 1), 'max_features': hp.choice('max_features', ['sqrt','log2', None]), 'min_samples_leaf': hp.choice('min_samples_leaf', [2, 5, 10, 14]), 'min_samples_split' : hp.choice ('min_samples_split', [2, 4, 6, 8]), 'n_estimators' : hp.choice('n_estimators', [200, 500]) } |
За всеки от параметрите са зададени конкретни възможни стойности, които след това можем да използваме, когато създаваме модел при дефиниране на целевата функция.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# Създаване на целева функция def objective(params): # Създаване на модел rf_new = RandomForestClassifier(criterion = params['criterion'], max_depth = params['max_depth'], max_features = params['max_features'], min_samples_leaf = params['min_samples_leaf'], min_samples_split = params['min_samples_split'], n_estimators = params['n_estimators'], ) # Изчисляване на обща точност accuracy = cross_val_score(rf_new, X_train_res, y_train_res, cv = 5).mean() # Полученият резултат трябва да е с отрицателен знак, защото се стремим да намерим максимум обща точност return {'loss': -accuracy, 'status': STATUS_OK } |
Като метрика за оценка при целевата функция задаваме общата точност (accuracy). Тъй като целта е да се намерят тези стойности на параметрите, при които общата точност е най-висока, а при Hyperopt алгоритъмът се стреми да открие минимума на функцията, е необходимо да сменим знака на получения резултат с отрицателен.
Следващата стъпка е да използваме функцията fmin(), чрез която да открием оптималните параметри. На нея като параметри подаваме целевата функция objective, пространството от параметри params и trials обекта. Алгоритъмът за търсене задаваме да е tpe.suggest и броят итерации да бъде 80, т.е. ще се пробват 80 комбинации на параметрите и техните стойности и накрая ще получим като резултат най-добрата.
1 2 3 4 5 6 7 8 9 |
# Създаване на Trials обект trials = Trials() # Използване на функцията fmin() best = fmin(fn= objective, space= params, algo= tpe.suggest, max_evals = 80, trials= trials) |
Резултат:
Parameters | Values | |
---|---|---|
0 | criterion | 1 |
1 | max_depth | 10 |
2 | max_features | 1 |
3 | min_samples_leaf | 0 |
4 | min_samples_split | 0 |
5 | n_estimators | 0 |
При тези параметри, които са зададени с hp.choice, получаваме индекс, показващ позицията на конкретната стойност в зададения списък. Необходимо е за тях да създадем отделни речници с конкретните индекси и техните съответстващи стойности.
1 2 3 4 5 |
criterion = {0: 'entropy', 1: 'gini'} m_features = {0: 'sqrt', 1: 'log2', 2: None} n_est = {0: 200, 1: 500} split = {0: 2, 1: 4, 2: 6, 3: 8} leaf = {0: 2, 1: 5, 2: 10, 3: 14} |
Оптималните параметри, определени от функцията fmin(), можете да видите в таблицата по-надолу:
Parameters | Values | |
---|---|---|
0 | criterion | gini |
1 | max_depth | 10 |
2 | max_features | log2 |
3 | min_samples_leaf | 2 |
4 | min_samples_split | 2 |
5 | n_estimators | 200 |
След като вече имаме оптималните параметри, можем да създадем новия модел.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# Създаване на модел с оптималните параметри trainedforest = RandomForestClassifier(criterion = criterion[best['criterion']], max_depth = best['max_depth'], max_features = m_features[best['max_features']], min_samples_leaf = leaf[best['min_samples_leaf']], min_samples_split = split[best['min_samples_split']], n_estimators = n_est[best['n_estimators']]) # Обучение на модела trainedforest.fit(X_train_res, y_train_res) # Тест на модела rf_new_pred = trainedforest.predict(X_test) |
Основните метрики за оценка на класификационни модели са със следните стойности:
Metrics | Values | |
---|---|---|
0 | Overall Accuracy | 0.756716 |
1 | Overall Error | 0.243284 |
2 | Precision | 0.736842 |
3 | Specificity | 0.833333 |
4 | Sensitivity | 0.65 |
5 | F1_score | 0.690702 |
Моделът е със 76% обща точност. В 74% от случаите правилно е определил обектите от положителния клас, които в действителност са положителни. Открил е 83% от отрицателния клас и 65% от положителния.
1 2 |
# Откриване на разликата между определените от класификатора класове и тези в действителност error = df_rf_best['Actual'].mean() - df_rf_best['Predicted'].mean() |
41.79% от обектите в тестовата извадка спадат към положителния клас, а класификаторът е определил правилно 36.86% от тях. Имаме 4.93% грешка.
В следната сравнителна таблица можете да видите разликата в стойностите на различните метрики за оценка на класификационни модели за модела с параметри по подразбиране и след оптимизация.
Metrics | RF Default | RF Best Params | |
---|---|---|---|
0 | Overall Accuracy | 0.714925 | 0.756716 |
1 | Overall Error | 0.285075 | 0.243284 |
2 | Precision | 0.665428 | 0.736842 |
3 | Specificity | 0.769231 | 0.833333 |
4 | Sensitivity | 0.639286 | 0.65 |
5 | F1_score | 0.652095 | 0.690702 |
Наблюдава се подобрение във всичките метрики след извършване на оптимизация. Това може да се види и в графиките на матрицата на неточностите и на ROC и Precision-Recall кривите.
Моделът с оптимални параметри има по-добри резултати, защото стойностите на False Positive и False Negative са по-ниски от тези, изобразени на матрицата на модела с параметри по подразбиране. Правилно е определил 325 от общо 390 обекта от отрицателния клас и 182 от 280 от положителния клас.
Съдейки по двете графики, оптимизираният модел дава по-добри резултати от този с параметри по подразбиране. Неговата ROC крива е с по-голяма площ под кривата и е по-далеч от нулевия класификатор, а Precision-Recall кривата му е по-близко до горния десен ъгъл на графиката отколкото тази на другия модел.
Библиотеката Hyperopt предоставя много възможности за оптимизация на модел за машинно обучение, най-вече при задаване на пространството от параметри и техните стойности. При нея предимство е това, че взима под внимание предишни итерации при търсене на най-добрите стойности за параметрите, което ѝ позволява по-бързо да открие тези, които са оптимални.
Включете се в курса по машинно обучение и анализ на данни с Python.