Полное руководство по исправлению ошибки sklearn2pmml XGBoost classes_
Решение ошибки параметра classes_ в sklearn2pmml XGBoost при создании PMML-файлов. Узнайте причины, решения и лучшие практики для успешного преобразования модели.
Как решить ошибку sklearn2pmml с параметром ‘classes_’ при создании PMML из модели XGBoost?
Я столкнулся с ошибкой при попытке создать PMML-файл из модели XGBoost с использованием sklearn2pmml. Вот мой код:
from sklearn.preprocessing import LabelEncoder
y_h_train = LabelEncoder().fit_transform(y_train.copy(deep=True))
modele_label_encoded = model.fit(X_train, y_h_train)
import sklearn2pmml as skpmml
from sklearn2pmml import PMMLPipeline, sklearn2pmml
cols_used = list(X_train.columns)
pmml_model = skpmml.make_pmml_pipeline(modele_label_encoded)
pmml_model.active_fields = cols_used
pmml_model.target_fields = ['Target']
skpmml.sklearn2pmml(pmml_model, os.path.join('test.pmml'), debug=True)
Однако я получаю следующую ошибку:
Exception in thread "main" java.lang.IllegalArgumentException: The value of 'xgboost.sklearn.XGBClassifier.classes_' attribute (null) is not a supported array type
Я проверил, что моя модель имеет атрибут classes_ с правильным типом массива:
modele_label_encoded.classes_
Output: array([0, 1])
Несмотря на наличие правильного типа массива, sklearn2pmml все равно выдает эту ошибку. Кто-нибудь сталкивался с этой проблемой раньше и нашел решение?
Ошибка sklearn2pmml с параметром ‘classes_’ при создании PMML из моделей XGBoost обычно возникает из-за несовместимости версий между XGBoost и sklearn2pmml, или проблем с тем, как атрибут classes_ доступен для конвертера PMML на базе Java. Эта ошибка происходит, несмотря на то, что модель Python имеет правильный атрибут classes_, что указывает на проблему сериализации или преобразования типов.
Содержание
- Понимание ошибки
- Основные причины
- Проблемы совместимости версий
- Решения и обходные пути
- Лучшие практики
- Альтернативные подходы
Понимание ошибки
Сообщение об ошибке java.lang.IllegalArgumentException: The value of 'xgboost.sklearn.XGBClassifier.classes_' attribute (null) is not a supported array type указывает на то, что хотя ваша модель XGBoost в Python имеет правильно установленный атрибут classes_, конвертер PMML на базе Java не может правильно получить доступ или преобразовать этот атрибут.
Как сообщают пользователи Stack Overflow, это обычно не проблема на уровне Python, а проблема сериализации между компонентами Python и Java. Конвертер ожидает, что атрибут classes_ будет доступен в определенном формате, который может обработать среда Java.
Ключевое наблюдение: Ошибка возникает в процессе преобразования PMML на базе Java, а не во время обучения модели Python, что объясняет, почему ваша модель, похоже, имеет правильный атрибут
classes_в Python.
Основные причины
1. Проблемы с атрибутом Label Encoder
Наиболее распространенной причиной является проблема с атрибутом _le (label encoder) в XGBClassifier. Согласно GitHub issue #197, проблема часто возникает из-за:
java.lang.IllegalArgumentException: Attribute 'xgboost.sklearn.XGBClassifier._le' has an unsupported value (Python class sklearn.preprocessing._label.LabelEncoder)
Это происходит, потому что sklearn2pmml ожидает, что label encoder будет определенного типа, но более новые версии XGBoost могут использовать разные реализации внутреннего label encoder.
2. Проблемы с декораторами домена
Другая частая проблема связана с тем, что декораторы домена не настроены должным образом. Как упоминается в GitHub issue #278:
java.lang.IllegalArgumentException: The value of 'sklearn2pmml.decoration.ContinuousDomain.data_min_' attribute (null) is not a supported array type
Эта ошибка указывает на то, что декораторы домена нужно настроить перед преобразованием.
3. Проблемы преобразования типов массивов
Исследования показывают, что существуют проблемы преобразования типов между массивами Python и коллекциями Java. Из GitHub issue #16:
java.lang.ClassCastException: numpy.core.NDArray cannot be cast to java.util.List
Это указывает на то, что процесс преобразования не удается при попытке преобразовать массивы numpy в совместимые с Java структуры данных.
Проблемы совместимости версий
Результаты исследований последовательно указывают на проблемы совместимости версий как на основную причину:
Совместимость версий XGBoost
- Переход от XGBoost 1.2.X к 1.3.X: Как отмечено в исследованиях, этот конкретный переход версий связан с характерными сообщениями об исключениях
- Ожидания пакета: Пакет sklearn2pmml ожидает, что label encoder (атрибут
XGBClassifier._le) будет “обычным” классом label encoder Scikit-Learn, но более новые версии XGBoost могут использовать разные реализации
Требования к версиям sklearn2pmml
- Поддерживаемые пакеты: На момент sklearn2pmml 0.84(.2), пакеты LightGBM и XGBoost перечислены как поддерживаемые, но проблемы совместимости все еще сохраняются
- Поддержка функций: Пакет может не полностью поддерживать все функции XGBoost или может иметь конкретные требования для определенных конфигураций моделей
Решения и обходные пути
Решение 1: Понижение версии
Если вы используете XGBoost 1.3.X, рассмотрите возможность понижения до XGBoost 1.2.X. Согласно исследованиям, переход с 1.2.X на 1.3.X связан с характерными сообщениями об исключениях, которые вы видите.
# Установка совместимой версии XGBoost
!pip install xgboost==1.2.1
Решение 2: Использование оберток sklearn2pmml
Создайте обертку, которая явно обрабатывает атрибут classes_:
from sklearn2pmml import sklearn2pmml
from sklearn2pmml.decoration import CategoricalDomain, ContinuousDomain
from sklearn2pmml.pipeline import PMMLPipeline
import sklearn2pmml as skpmml
# Создайте конвейер с явными декораторами домена
cols_used = list(X_train.columns)
# Настройте декораторы домена при необходимости
domain_features = {}
for col in cols_used:
if X_train[col].dtype == 'object':
domain_features[col] = CategoricalDomain()
else:
domain_features[col] = ContinuousDomain()
pmml_model = PMMLPipeline([
("classifier", modele_label_encoded)
])
# Установите активные и целевые поля
pmml_model.active_fields = cols_used
pmml_model.target_fields = ['Target']
# Настройте конвейер с декораторами домена
pmml_model.fit(X_train, y_h_train)
# Преобразуйте в PMML
skpmml.sklearn2pmml(pmml_model, 'test.pmml', debug=True)
Решение 3: Ручная настройка Label Encoder
Как предлагается в исследованиях, убедитесь, что ваша настройка label encoder соответствует ожиданиям sklearn2pmml:
from sklearn.preprocessing import LabelEncoder
from xgboost import XGBClassifier
# Создайте и настройте label encoder отдельно
le = LabelEncoder()
y_h_train = le.fit_transform(y_train.copy(deep=True))
# Создайте и настройте модель
modele_label_encoded = XGBClassifier()
modele_label_encoded.fit(X_train, y_h_train)
# Проверьте, что атрибут classes_ существует и правильный
print(f"Classes: {modele_label_encoded.classes_}")
print(f"Classes label encoder: {le.classes_}")
# Создайте конвейер PMML
pmml_model = skpmml.make_pmml_pipeline(modele_label_encoded)
pmml_model.active_fields = cols_used
pmml_model.target_fields = ['Target']
skpmml.sklearn2pmml(pmml_model, 'test.pmml', debug=True)
Решение 4: Использование PMMLPipeline напрямую
Вместо использования make_pmml_pipeline, создайте конвейер PMML более явно:
from sklearn2pmml import PMMLPipeline
from sklearn2pmml.decoration import ContinuousDomain
# Создайте явный конвейер
pipeline = PMMLPipeline([
("classifier", modele_label_encoded)
])
# Настройте конвейер
pipeline.active_fields = cols_used
pipeline.target_fields = ['Target']
# Настройте и преобразуйте
pipeline.fit(X_train, y_h_train)
skpmml.sklearn2pmml(pipeline, 'test.pmml', debug=True)
Лучшие практики
1. Проверка совместимости модели
Перед попыткой преобразования убедитесь, что ваша модель имеет все необходимые атрибуты:
# Проверьте, имеет ли модель необходимые атрибуты
print(f"Has classes_: {hasattr(modele_label_encoded, 'classes_')}")
print(f"Classes type: {type(modele_label_encoded.classes_)}")
print(f"Classes shape: {modele_label_encoded.classes_.shape}")
# Дополнительные проверки для label encoder
print(f"Has _le: {hasattr(modele_label_encoded, '_le')}")
if hasattr(modele_label_encoded, '_le'):
print(f"_le type: {type(modele_label_encoded._le)}")
2. Тестирование с простыми моделями
Всегда тестируйте преобразование с простой моделью сначала, чтобы изолировать проблему:
# Создайте простую тестовую модель
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
X_test, y_test = make_classification(n_samples=100, n_features=4, n_classes=2, random_state=42)
test_model = RandomForestClassifier(random_state=42)
test_model.fit(X_test, y_test)
# Протестируйте преобразование
test_pipeline = PMMLPipeline([("classifier", test_model)])
skpmml.sklearn2pmml(test_pipeline, 'test_model.pmml', debug=True)
3. Использование режима отладки
Всегда используйте режим отладки при устранении неполадок:
skpmml.sklearn2pmml(pmml_model, 'test.pmml', debug=True)
Это предоставляет подробную информацию об ошибках, которая может помочь определить коренную причину.
Альтернативные подходы
1. Использование других инструментов преобразования PMML
Если sklearn2pmml продолжает давать сбой, рассмотрите альтернативные инструменты преобразования PMML:
- JPMML-Sklearn: Основная Java-библиотека, которую обертывает sklearn2pmml
- ONNX Runtime: Сначала преобразуйте в формат ONNX, затем в PMML
- Пользовательская генерация PMML: Напишите код для пользовательской генерации PMML
2. Переключение на альтернативные модели
Если проблемы совместимости с XGBoost сохраняются, рассмотрите использование нативно поддерживаемых моделей:
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
# Используйте нативно поддерживаемые модели
model = RandomForestClassifier(random_state=42)
# или
model = LogisticRegression(random_state=42)
3. Обновление до последних версий
Иногда обновление до последних стабильных версий обоих пакетов решает проблемы совместимости:
!pip install --upgrade sklearn2pmml xgboost
Однако будьте осторожны, так как это может вызвать новые проблемы совместимости, как отмечено в результатах исследований о переходах версий.
Заключение
Ошибка sklearn2pmml ‘classes_’ с моделями XGBoost в основном вызвана несовместимостью версий между XGBoost и sklearn2pmml, или проблемами с тем, как Java-конвертер обращается к атрибутам модели Python. Ключевые выводы включают:
- Совместимость версий имеет решающее значение - Переход с XGBoost 1.2.X на 1.3.X особенно проблематичен
- Проблемы с label encoder распространены - Атрибут
_leчасто вызывает проблемы сериализации - Декораторы домена нуждаются в правильной настройке - Убедитесь, что все декораторы настроены перед преобразованием
- Режим отладки предоставляет ценную информацию - Используйте
debug=Trueдля получения подробных сообщений об ошибках - Могут потребоваться альтернативные подходы - Рассмотрите другие инструменты или модели, если проблемы сохраняются
Для немедленного решения попробуйте понизить версию XGBoost до 1.2.X или используйте явное построение конвейера PMML с правильно настроенными декораторами домена. Если проблемы продолжаются, рассмотрите альтернативные инструменты преобразования PMML или временно переключитесь на нативно поддерживаемые модели, такие как RandomForest.
Источники
- Stack Overflow - Error writing XGBoost Classifier to pmml with sklearn2pmml
- GitHub Issue #265 - Attribute ‘xgboost.sklearn.XGBClassifier._le’ not set
- GitHub Issue #278 - XGBoost to PMML fails for unknown reason
- GitHub Issue #197 - Attribute ‘xgboost.sklearn.XGBClassifier._le’ has an unsupported value
- GitHub Issue #16 - XGBClassifier wrapper failing to convert
- Stack Overflow - sklearn2pmML error with pycaret model to PMML