ВЫБОР ПРИЗНАКОВ В ПРОГНОЗИРОВАНИИ БАНКРОТСТВА
Теоретический раздел
Прогнозирование банкротства является важной задачей в сфере финансов и бухгалтерского учета, поскольку позволяет заинтересованным сторонам выявлять фирмы, которым грозит банкротство, и предпринимать соответствующие действия для уменьшения потенциальных убытков. Методология построения и создания моделей машинного обучения включает в себя множество последовательных шагов от подготовки данных до оценки модели после подгонки и настройки. Но теперь я хочу поговорить об отборе признаков — одном из сложных и неоднозначных этапов прогнозирования банкротства. Целью выбора признаков является определение наиболее важных переменных или признаков, которые способствуют прогнозированию банкротства. Это важно, потому что не все переменные могут быть полезны для прогнозирования, а включение нерелевантных переменных может привести к переоснащению и снижению точности прогнозирования. Кроме того, наборы данных финансовой отчетности, которые имеют большую размерность, влияют на время работы модели обучения. Кроме того, важно иметь релевантную немультиколлинеарную независимую переменную и низкоразмерный набор данных (набор данных финансового отчета настолько велик), поэтому жизненно важно найти лучшие гиперпараметры для разных моделей, и эта задача требует много времени. Выбор функций может помочь повысить точность и эффективность моделей прогнозирования банкротства.
В последнее время для решения проблемы выбора признаков некоторые авторы используют многокритериальный выбор признаков с использованием (MOEA), стремясь одновременно оптимизировать несколько показателей оценки, таких как точность и AUC, и определить набор признаков, которые уравновешивают компромисс между показателями. . Этот подход может помочь определить более надежные подмножества функций, которые эффективны по нескольким критериям оценки.
Многоцелевые эволюционные алгоритмы (MOEA) — это алгоритмы оптимизации, которые могут одновременно оптимизировать несколько целей в задаче. Основная идея MOEA состоит в том, чтобы создать популяцию возможных решений, оценить их в соответствии с несколькими целями, а затем применить генетические операторы (такие как скрещивание и мутация) к популяции для создания новых решений. Затем оцениваются новые решения, и процесс повторяется до тех пор, пока не будет получен удовлетворительный набор недоминируемых решений. Эти недоминируемые решения представляют собой набор компромиссов между различными целями, и лицо, принимающее решения, может затем выбрать решение, которое лучше всего соответствует его потребностям.
Чтобы применить MOEA к прогнозированию банкротства, нам сначала нужно определить цели и ограничения проблемы. Затем мы можем использовать алгоритмы MOEA, такие как NSGA-II, SPEA2 или MOEA/D, для поиска набора решений, оптимальных по Парето (т. е. ни одно решение не может быть улучшено в одной задаче без ухудшения другой). Затем мы можем использовать эти решения для создания набора компромиссов между целями и выбора решения, которое лучше всего соответствует нашим потребностям.
Стоит отметить, что MOEA могут быть дорогостоящими в вычислительном отношении, особенно когда количество целей велико или когда пространство поиска велико. Поэтому важно тщательно спроектировать целевые функции и ограничения, чтобы обеспечить эффективность и результативность поиска. Кроме того, MOEA требует большого объема данных для обучения моделей, поэтому важно иметь всеобъемлющий набор данных, содержащий финансовые и экономические данные о рассматриваемых фирмах.
В целом, MOEA предлагают мощный подход к выбору признаков, который может помочь принять обоснованные решения по очистке набора данных от недействительных и неважных переменных. Имеются работы, посвященные прогнозированию банкротства и выбору признаков по алгоритму МОЭА [1, 3, 4, 5].
В этом исследовании я буду использовать алгоритм NSGA-II (тип алгоритма MOEA) для выбора признаков. Мой выбор сделан в пользу этого алгоритма, так как работ, в которых он используется для выбора признаков банкротства, немного. Но есть много работ, где используется алгоритм NSGA-II для выбора признаков в разных областях [6, 7, 8, 9, 10].
Практический раздел
Мы будем работать с набором данных kaggle «Прогнозирование банкротства компаний» — «данные о банкротстве из Тайваньского экономического журнала за 1999–2009 годы».
Основная цель прогнозировать банкротство или небанкротство компании в будущем.
Итак, есть несколько способов реализовать подход MOEA к выбору функций в python. Существуют библиотеки pymoo, platypus, deap и др. для алгоритмов многокритериальной оптимизации [2]. Я использую pymoo для решения проблемы выбора функций. Ссылка в официальных документах здесь. Давайте посмотрим пример кода, и я объясню его шаг за шагом.
- Прежде всего, мы импортируем библиотеки, загружаем и очищаем датасет финансовой отчетности компании.
from pymoo.core.problem import Problem from pymoo.algorithms.moo.nsga2 import NSGA2 from pymoo.factory import get_sampling, get_crossover, get_mutation from pymoo.optimize import minimize from pymoo.operators.sampling.rnd import BinaryRandomSampling from pymoo.operators.crossover.pntx import TwoPointCrossover from pymoo.operators.mutation.bitflip import BitflipMutation import pandas as pd import numpy as np from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score from sklearn.model_selection import train_test_split from sklearn.metrics import f1_score import plotly.express as px import xgboost as xgb from imblearn.over_sampling import SMOTE from collections import Counter df = pd.read_csv('data.csv') X = df.drop(['Bankrupt?'], axis=1) y = df[['Bankrupt?']] print(X.shape[0]) # 96 ---> columns (independent variables)
- Затем мы определяем количество значений целевой переменной.
df['Bankrupt?'].value_counts().plot(kind='bar') """ It's imbalanced class so that we see high disproportion between 0 ---> not bankruptcy and 1 ----> bankcruptcy """
- Я использую XGBoost Classifier для прогнозирования банкротства.
X_train,X_test,y_train,y_test = train_test_split(X, y, test_size=0.33, random_state = 100) smote = SMOTE(sampling_strategy='auto') X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train) # train logistic regression model clf = xgb.XGBClassifier() clf.fit(X_train_smote, y_train_smote) # compute accuracy and AUC on validation set y_pred = clf.predict(X_test) acc = accuracy_score(y_test, y_pred) f_1 = f1_score(y_test, y_pred) print('accuracy for XGBoost ----> ', acc) # accuracy for XGBoost ----> 0.9626832518880497 print('accuracy for f-1 score ----> ', f_1) # f-1 score for XGBoost ----> 0.46835443037974683 print(confusion_matrix(y_test, y_pred)) """ Confusion matrix [[2130 37] [ 47 37]] """
- Мы видим высокую точность и низкий показатель f-1, что характерно для класса дисбаланса.
- В матрице путаницы мы видим, что истинное предсказание 1 (банкротство) равно 37, а 2130 — для 0 (не банкротство).
- Примечание! В прогнозировании банкротства мы должны ориентироваться на миноритарный класс (банкротство), поэтому важно прогнозировать именно банкротство компании.
- Теперь я пытаюсь увеличить счет f-1, используя выбор функций.
- Для выбора функций мы выбираем подход MOEA с использованием алгоритма pymoo и NSGA2.
- Затем мы создаем класс BankruptcyProblem, который наследует класс Problem с основными параметрами и атрибутами:
# define the feature selecting problem class BankruptcyProblem(Problem): def __init__(self, X, y): self.X = X self.y = y self.n_features = X.shape[1] self.eval_dict = {'accuracy':[], 'f-1 score':[]} super().__init__(n_var=self.n_features, n_obj=2, n_constr=0, xl=np.zeros(self.n_features), xu=np.ones(self.n_features), elementwise_evaluation=True, type_var=np.bool, )
- Примечание! супер(). init позволяет вызвать конструктор родительского класса (Problem) внутри подкласса (BankruptcyProblem).
- Задача — это объектно-ориентированное определение, которое реализует метод оценки набора решений. Для получения дополнительной информации вы можете написать эту и эту статьи.
# create the problem instance problem = BankruptcyProblem(X.values, y.values) # features -> cleaned and preprocessed finansial statments, target -> bankruptcy or not company
- Мы используем алгоритм NSGA2 подхода MOEA.
# define the algorithm algorithm = NSGA2(pop_size=1, sampling=BinaryRandomSampling(), crossover=TwoPointCrossover(), mutation=BitflipMutation())
- Функция _evaluate реализует алгоритм NSGA2 с набором данных финансовой отчетности и моделью XGBClassifier, которая представляет собой обучающую модель для прогнозирования банкротства компании, оценивает модель с использованием точности метрик и оценки f-1.
- В строке out["F"] = [-acc, -f_1] мы сохраняем эти метрики для выбора наиболее важных признаков по алгоритму NSGA2.
def _evaluate(self, x, out, *args, **kwargs): # select features based on binary vector selected_features = np.where(x == 1)[-1] X_selected = self.X[:, selected_features] # split data into train and validation sets X_train, X_valid, y_train, y_valid = train_test_split(X_selected, self.y, test_size=0.1, random_state=100) # use smote methodic for solving imbalanced data (disproportion between 0 and 1 values) smote = SMOTE(sampling_strategy='minority') X_train, y_train = smote.fit_resample(X_train, y_train) # train XGBClassifier model clf = xgb.XGBClassifier() clf.fit(X_train, y_train) # compute f_1 and AUC on validation set y_pred = clf.predict(X_valid) acc = accuracy_score(y_valid, y_pred) f_1 = f1_score(y_valid, y_pred) # save resiults self.eval_dict['accuracy'].append(acc) self.eval_dict['f-1 score'].append(f_1) # set objectives to be minimized out["F"] = [-acc, -f_1]
- Наконец, запускаем алгоритм оптимизации, чтобы найти лучший набор классификаторов, который максимизирует несколько показателей производительности.
# run the optimization res = minimize(problem, # problem class algorithm, # NSGA2 algorithm ("n_gen", 50), # number of iteration for eval problem class verbose=True)
- На рис. 1 показано, как изменить показатель f-1 на каждой итерации с помощью различных функций.
- На рис. 2 показано, как изменить показатель точности на каждой итерации с разностными функциями.
- Для извлечения важной функции мы используем объект res.
columns = X.columns.tolist() columns_dict = {k:v for k, v in enumerate(columns)} # create dict where key - index, value - columns name # extract the selected features as index of dataset columns selected_features = np.where(res.X == 1)[-1] print("Selected features: ", selected_features) """ Selected features: [ 0 4 5 6 11 12 13 18 21 22 24 26 27 29 30 31 32 33 34 35 37 39 40 42 45 46 49 52 53 55 56 63 65 67 70 73 75 77 81 83 89 91 92 93] Reduced data dimension by 26 columns """ selected_features_final = [columns_dict[i] for i in selected_features] # convert index to column name print("Selected features final: ", selected_features_final) """ Selected features final: [' ROA(C) before interest and depreciation before interest', ' Realized Sales Gross Margin', ' Operating Profit Rate', ' Pre-tax net Interest Rate', ' Research and development expense rate', ' Cash flow rate', ' Interest-bearing debt interest rate', ' Persistent EPS in the Last Four Seasons', ' Operating Profit Per Share (Yuan ¥)', ' Per Share Net profit before tax (Yuan ¥)', ' Operating Profit Growth Rate', ' Regular Net Profit Growth Rate', ' Continuous Net Profit Growth Rate', ' Net Value Growth Rate', ' Total Asset Return Growth Rate Ratio', ' Cash Reinvestment %', ' Current Ratio', ' Quick Ratio', ' Interest Expense Ratio', ' Total debt[/Total](https://file+.vscode-resource.vscode-cdn.net/Total) net worth', ' Net worth[/Assets](https://file+.vscode-resource.vscode-cdn.net/Assets)', ' Borrowing dependency', ' Contingent liabilities[/Net](https://file+.vscode-resource.vscode-cdn.net/Net) worth', ' Net profit before tax[/Paid-in](https://file+.vscode-resource.vscode-cdn.net/Paid-in) capital', ' Accounts Receivable Turnover', ' Average Collection Days', ' Net Worth Turnover Rate (times)', ' Allocation rate per person', ' Working Capital to Total Assets', ' Current Assets[/Total](https://file+.vscode-resource.vscode-cdn.net/Total) Assets', ' Cash[/Total](https://file+.vscode-resource.vscode-cdn.net/Total) Assets', ' Current Liabilities[/Liability](https://file+.vscode-resource.vscode-cdn.net/Liability)', ' Current Liabilities[/Equity](https://file+.vscode-resource.vscode-cdn.net/Equity)', ' Retained Earnings to Total Assets', ' Current Asset Turnover Rate', ' Cash Turnover Rate', ' Fixed Assets to Assets', ' Current Liability to Equity', ' CFO to Assets', ' Current Liability to Current Assets', " Net Income to Stockholder's Equity", ' Degree of Financial Leverage (DFL)', ' Interest Coverage Ratio (Interest expense to EBIT)', ' Net Income Flag'] """
- Таким образом, мы определяем с помощью алгоритма NSGA2 важные функции. Теперь я фильтрую переменные X_train и X_test по важным функциям, снова подбираю классификатор XGBoost и сравниваю результаты.
X_train_new = X_train.iloc[:, selected_features] X_test_new = X_test.iloc[:, selected_features] y_train_new = y_train.copy() smote = SMOTE(sampling_strategy='auto') X_train_smote, y_train_smote = smote.fit_resample(X_train_new, y_train_new) # train logistic regression model clf = xgb.XGBClassifier() clf.fit(X_train_smote, y_train_smote) # compute accuracy and AUC on validation set y_pred = clf.predict(X_test_new) acc = accuracy_score(y_test, y_pred) f_1 = f1_score(y_test, y_pred) print('accuracy for XGBoost ----> ', acc) # accuracy for XGBoost ----> 0.9595735228787206 print('f-1 score for XGBoost ----> ', f_1) # f-1 score for XGBoost ----> 0.49162011173184356 print(confusion_matrix(y_test, y_pred)) """ Confusion matrix [[2116 51] [ 40 44]] """
- Результат с выбором характеристик орудия: показатель f-1 увеличился на 0,2 процента, но точность снизилась на 0,03 процента. Это не так уж много, но если мы посмотрим на матрицу путаницы, мы увидим, что истинное предсказание увеличения класса меньшинства в компании 7 по сравнению с классификатором XGBoost без выбора функций. Не забывайте, что всех компаний-банкротов 84, когда все тестовые данные 2251 и добиться результата по метрике f-1 score будет очень сложно из-за дисбаланса классов.
- При всем при этом можно сделать вывод, что подгонка модели по данным с выделением признаков лучше предсказывает банкротство компании. Так же не забываем, что мы значительно уменьшили размерность датасета и это здорово скажется на скорости обучения модели, если в датасете много строк.
Примечание! Для достижения лучшего результата в прогнозировании банкротства компаний необходимо использовать не только отбор признаков, но и другие способы повышения качества модели. Например, нормализация и корреляция для обнаружения линейно-зависимых функций, GridSearchCV, RenadomSearchCV и байесовская оптимизация для поиска лучших гиперпараметров для модели и перекрестной проверки.
Объяснение алгоритма NSGA2
NSGA-II (генетический алгоритм сортировки без доминирования II) представляет собой многокритериальный алгоритм оптимизации, основанный на принципах генетических алгоритмов. Он работает, создавая начальную популяцию решений-кандидатов и итеративно улучшая их с помощью операторов отбора, скрещивания и мутации.
Алгоритм использует сортировку без доминирования для ранжирования решений-кандидатов на основе их доминирования по Парето. Отношение доминирования Парето используется для сравнения двух решений на основе их эффективности в отношении нескольких целей. Говорят, что решение доминирует над другим решением, если оно работает лучше по крайней мере в одной цели и не хуже в каких-либо других целях.
После ранжирования популяции на основе недоминируемой сортировки алгоритм выполняет сортировку по расстоянию скученности, чтобы выбрать лучших особей для следующего поколения. Расстояние скученности измеряет плотность решений в определенной области объективного пространства и используется для поддержания разнообразия в популяции.
NSGA-II — это широко используемый алгоритм для задач многокритериальной оптимизации, который успешно применялся к различным реальным задачам, включая выбор признаков при прогнозировании банкротства.
Заключение
В заключение, выбор признаков является важным шагом в построении эффективных моделей прогнозирования банкротства. Выбор соответствующих функций может повысить точность модели, уменьшить переоснащение, повысить точность и показатели оценки f-1, а также улучшить ее интерпретируемость. В частности, было обнаружено, что методы многокритериального отбора признаков более эффективны при выборе наиболее информативных признаков для прогнозирования банкротства. Алгоритм NSGA-II — популярный метод многокритериальной оптимизации, который успешно применялся при выборе признаков для прогнозирования банкротства.
Рекомендации
- Выбор признаков для прогнозирования банкротства: многоцелевой подход к оптимизации
- Pymoo: многоцелевая оптимизация в Python
- Презентация Многоцелевая оптимизация
- Многоцелевые эволюционные алгоритмы выбора признаков: применение в прогнозировании банкротства
- Прогнозирование банкротства на основе несбалансированных данных с использованием многокритериального выбора классификаторов
- NSGA-II как метод выбора признаков и классификатор AdaBoost для прогнозирования COVID-19 на основе симптомов пациента
- Подход к выбору признаков на основе NSGA-II с ReliefF
- Многокритериальный выбор характеристик с использованием NSGA-II для прогнозирования оттока клиентов в телекоммуникациях
- Многокритериальный выбор признаков с помощью NSGA II для доменов распознавания образов
- Многокритериальная оценка генетического алгоритма при выборе признаков