Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boosting method implementation (XGBoost) #1209

Merged
merged 29 commits into from
Jul 26, 2024
Merged

Boosting method implementation (XGBoost) #1209

merged 29 commits into from
Jul 26, 2024

Conversation

RomanKharkovskoy
Copy link
Collaborator

@RomanKharkovskoy RomanKharkovskoy commented Nov 27, 2023

План

  • Добавить основные XGBoost основываясь на PR по CatBoost (см. на изменения в boostings_implementation.py и boostings.py)
  • Реализовать convert_to_dmatrix()
  • Реализовать check_and_update_params() для XGBoost (для конфликтов параметров)
  • Посмотреть подбор начальных параметров для XGBoost в default_operation_params.json для классификации
  • Перебор гиперпараметров в search_space.py для классификации
  • Протестировать для решения классификации
  • Посмотреть подбор начальных параметров для XGBoost в default_operation_params.json для регрессии
  • Перебор гиперпараметров в search_space.py для регрессии
  • Протестировать для решения регрессии
  • Пофиксить PEP8
  • Тесты (?)

Как работает

Реализован интерфейс fit/predict в родительском классе FedotXGBoostImplementation

Код
class FedotXGBoostImplementation(ModelImplementation):
    __operation_params = ['n_jobs', 'use_eval_set']

    def __init__(self, params: Optional[OperationParameters] = None):
        super().__init__(params)

        self.model_params = {k: v for k, v in self.params.to_dict().items() if k not in self.__operation_params}
        self.model = None

    def fit(self, input_data: InputData):
        input_data = input_data.get_not_encoded_data()

        if self.params.get('use_eval_set'):
            train_input, eval_input = train_test_data_setup(input_data)

            train_input = self.convert_to_dataframe(train_input)
            eval_input = self.convert_to_dataframe(eval_input)

            train_x, train_y = train_input.drop(columns=['target']), train_input['target']
            eval_x, eval_y = eval_input.drop(columns=['target']), eval_input['target']

            if self.classes_ is None:
                eval_metric = 'rmse'
            elif len(self.classes_) < 3:
                eval_metric = 'auc'
            else:
                eval_metric = 'mlogloss'

            self.model.fit(X=train_x, y=train_y,
                           eval_set=[(eval_x, eval_y)], eval_metric=eval_metric)

        else:

            train_data = self.convert_to_dataframe(input_data)
            train_x, train_y = train_data.drop(columns=['target']), train_data['target']
            self.model.fit(X=train_x, y=train_y)

        return self.model

    def predict(self, input_data: InputData):
        input_data = self.convert_to_dataframe(input_data.get_not_encoded_data())
        train_x, _ = input_data.drop(columns=['target']), input_data['target']
        prediction = self.model.predict(train_x)

        return prediction

Интерфейс fit/predict не поддерживает работу с внутренним типом данных xgboost.DMatrix, поэтому необходимо было найти обходной путь. В данном случае был использован тип данных pandas.DataFrame.

Внутри интерфейса идёт преобразование InputData в pandas.DataFrame (categorical_idx становятся category, а numerical_idx становятся float

Код
@staticmethod
def convert_to_dataframe(data: Optional[InputData]):
    dataframe = pd.DataFrame(data=data.features, columns=data.features_names)
    dataframe['target'] = data.target

    if data.categorical_idx is not None:
        for col in dataframe.columns[data.categorical_idx]:
            dataframe[col] = dataframe[col].astype('category')

    if data.numerical_idx is not None:
        for col in dataframe.columns[data.numerical_idx]:
            dataframe[col] = dataframe[col].astype('float')

    return dataframe

Таблица сравнения метрик из Fedot'а и из без AutoML (inputer кодирование категориальных данных)

Датасет Метрика Запуск без AutoML FEDOT
Internet-Advertisements ROC-AUC 0,97622 0,97157
adult ROC-AUC 0,92792 0,88797
Amazon_employee_access ROC-AUC 0,81353 0,82456
credit-g ROC-AUC 0,76364 0,73071
blood-transfusion-service-center ROC-AUC 0,68082 0,70955
kc1 ROC-AUC 0,77625 0,80227
bank-marketing ROC-AUC 0,93192 0,92422
qsar-biodeg ROC-AUC 0,92399 0,91268
electricity ROC-AUC 0,96874 0,96539
ozone-level-8hr ROC-AUC 0,91429 0,89595
car LogLoss 0,04482 0,69721
vehicle LogLoss 0,60539 0,55317
mfeat-factors LogLoss 0,12889 0,16635
pendigits LogLoss 0,03452 0,04912
cardiotocography LogLoss 0,00291 0,00478
page-blocks LogLoss 0,10433 0,11678
nursery LogLoss 0,00611 0,18016
mfeat-karhunen LogLoss 0,19698 0,21434
anneal LogLoss 0,41601 0,42384
satimage LogLoss 0,25953 0,24396

Метрики из коробки оказались лучше, чем метрики из Fedot'а, что может быть связано с внутренним препроцессингом внутри Fedot'а.

@pep8speaks
Copy link

pep8speaks commented Nov 27, 2023

Hello @RomanKharkovskoy! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2024-07-24 17:08:37 UTC

@nicl-nno
Copy link
Collaborator

nicl-nno commented Nov 27, 2023

Выставлять на ревью PR-ы без описания и с PEP8-дефектами - плохая практика.

Изменения не покрыты тестами (нужны в случае если поведение чем-то отличается от предыдущей реализации xgb).

Copy link

codecov bot commented Dec 5, 2023

Codecov Report

Attention: Patch coverage is 77.08333% with 22 lines in your changes missing coverage. Please review.

Project coverage is 80.10%. Comparing base (a7e4243) to head (f20d98e).
Report is 1 commits behind head on master.

Files Patch % Lines
...mplementations/models/boostings_implementations.py 76.84% 22 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1209       /-   ##
==========================================
  Coverage   79.96%   80.10%    0.14%     
==========================================
  Files         146      146              
  Lines       10100    10190       90     
==========================================
  Hits         8076     8163       87     
- Misses       2024     2027        3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

github-actions bot commented Jan 10, 2024

All PEP8 errors has been fixed, thanks ❤️

Comment last updated at

Copy link
Collaborator

@andreygetmanov andreygetmanov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не совсем понял, как идёт сравнение с Федотом?
Берутся xgboost из коробки и федот с 1 моделью (xgboost)?
Тогда перед имплементацией стоит взять больше датасетов (хотя бы 10), запустить их минимум по 5 раз и усреднить
Возможно, @nicl-nno знаешь более оптимальные цифры или датасеты подскажешь?

@RomanKharkovskoy
Copy link
Collaborator Author

Не совсем понял, как идёт сравнение с Федотом? Берутся xgboost из коробки и федот с 1 моделью (xgboost)? Тогда перед имплементацией стоит взять больше датасетов (хотя бы 10), запустить их минимум по 5 раз и усреднить Возможно, @nicl-nno знаешь более оптимальные цифры или датасеты подскажешь?

Взял по 10 датасетов для классификации (заменил таблицу в шапке PR'а). XGBoost берётся из коробки заполняются пропуски с помощью sklearn.SimpleInputer и кодируются категориальные признаки с помощью sklearn.OneHotEncoder. А для сравнения с FEDOT берётся predefined_model='xgboost'

@andreygetmanov
Copy link
Collaborator

Не совсем понял, как идёт сравнение с Федотом? Берутся xgboost из коробки и федот с 1 моделью (xgboost)? Тогда перед имплементацией стоит взять больше датасетов (хотя бы 10), запустить их минимум по 5 раз и усреднить Возможно, @nicl-nno знаешь более оптимальные цифры или датасеты подскажешь?

Взял по 10 датасетов для классификации (заменил таблицу в шапке PR'а). XGBoost берётся из коробки заполняются пропуски с помощью sklearn.SimpleInputer и кодируются категориальные признаки с помощью sklearn.OneHotEncoder. А для сравнения с FEDOT берётся predefined_model='xgboost'

А усреднение по скольки запускам считаешь?

@aPovidlo
Copy link
Collaborator

/fix-pep8

Copy link
Collaborator

@aPovidlo aPovidlo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-- wip --

@aPovidlo aPovidlo self-assigned this Jul 24, 2024
@aPovidlo aPovidlo merged commit 80eba8e into master Jul 26, 2024
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants