Это вторая и заключительная часть статьи, в которой мы рассматриваем проблему классификации экзопланет. Если предыдущая статья была больше о предварительной обработке данных, то здесь мы будем создавать модели, выбирать лучшие и экспериментировать.

PS некоторые моменты могут быть не понятны, поэтому лучше начать с первой части: https://habr.com/ru/articles/800999/

Так что, надеюсь, все, кто хотел посмотреть первую часть, смогут начать.

Случайный лес

На этот раз мы выбрали объекты методом Gain с использованием случайного леса. Теперь давайте посмотрим, насколько эффективным это оказалось, построив еще одну модель случайного леса.

rfi = RandomForestClassifier(max_depth=2, random_state=42)
rfi.fit(X_train[['koi_fpflag_nt', 'koi_fpflag_ss', 'koi_fpflag_co', 'koi_fpflag_ec',
       'koi_depth', 'koi_prad', 'koi_prad_err1', 'koi_prad_err2', 'koi_teq',
       'koi_insol_err1', 'koi_insol_err2', 'koi_model_snr', 'koi_steff_err1',
       'koi_steff_err2']], y_train)
rfi_pred_train=rfi.predict(X_train[['koi_fpflag_nt', 'koi_fpflag_ss', 'koi_fpflag_co', 'koi_fpflag_ec',
       'koi_depth', 'koi_prad', 'koi_prad_err1', 'koi_prad_err2', 'koi_teq',
       'koi_insol_err1', 'koi_insol_err2', 'koi_model_snr', 'koi_steff_err1',
       'koi_steff_err2']])
rfi_pred_test=rfi.predict(X_test[['koi_fpflag_nt', 'koi_fpflag_ss', 'koi_fpflag_co', 'koi_fpflag_ec',
       'koi_depth', 'koi_prad', 'koi_prad_err1', 'koi_prad_err2', 'koi_teq',
       'koi_insol_err1', 'koi_insol_err2', 'koi_model_snr', 'koi_steff_err1',
       'koi_steff_err2']])

На самом деле не очень красочно таскать этот список функций, но я ленивый человек, увидел вывод функции в Feature Selection, скопировал, добавил скобки [квадратные] и вперед.

Давайте посмотрим на показатели

metrics(y_test,rfi_pred_test)

точность: 0,9456351280710925
f1: 0,94831013916501
рок auc: 0,9462939057241274

Что это за функция, может спросить читатель, который не зашел на первую часть и поленился. Я не сужу. Вот функция и вот она:

def metrics(y_true,y_pred):
    acc=accuracy_score(y_true, y_pred)
    f1=f1_score(y_true, y_pred)
    roc_auc=roc_auc_score(y_true, y_pred)
    print(f'accuracy: {acc}\nf1: {f1}\nroc auc: {roc_auc} ')

Так как мы собираемся строить несколько моделей, то наличие такой функции облегчает нам жизнь, инженерное решение, можно сказать)

Теперь вспомните, что мы также использовали F-тест для выбора функций и получили следующий список: [‘koi_fpflag_nt’, ‘koi_fpflag_ss’, ‘koi_fpflag_co’, ‘koi_fpflag_ec’, ‘koi_depth’, ‘koi_teq’, ‘koi_steff_err1’, ‘koi_steff_err2’] мы просто берем переменную X_f, которая была объявлена ​​в коде первой части

y_f=y
X_f_train, X_f_test, y_f_train, y_f_test = train_test_split(X_f, y_f, test_size=0.2, random_state=42)
model_f=RandomForestClassifier(max_depth=2, random_state=42)
model_f.fit(X_f_train, y_f_train)
f_pred=model_f.predict(X_f_test)
metrics(y_f_test, f_pred)

точность: 0,9790904338734971
f1: 0,9801192842942346
рок auc: 0,9798926657489797

Пока что F-тест — лучшее, что случилось с этими данными, мне очень нравятся эти измерения, но мы не будем на этом останавливаться.

ЧИТАТЬ   Dj Андрей Боженков - 2k23 Юбилей! Ретро танцевальная вечеринка-2 (часть 09)

XGBoost

даже из Интернета, чтобы не скучать

Прежде чем создавать модель XGBoost, давайте прогоним ее через GridSearchCV, вероятно, это произойдет относительно быстро. Отмечу лишь, что чем больше настроек вы решите запустить, тем больше времени это займет.
GridSearchCV позволяет выбрать лучшие параметры для обучения модели; на мой взгляд эта функция работает быстрее с XGBoost, чем с Catboost, как и процесс обучения в принципе. Возможно, я ошибаюсь, поэтому, если у кого-то есть какие-либо мысли по этому поводу, я буду рад их услышать.
Начнем процесс:

from xgboost import XGBClassifier
from sklearn.model_selection import GridSearchCV
xgbmodel = XGBClassifier()
parameters = {'learning_rate': [0.03, 0.1],
              'max_depth': [2,3.5, 10],
              'colsample_bytree': [0.7, 0.5, 1],
              'n_estimators': [0,150,10]}

xgb_grid = GridSearchCV(xgbmodel,
                        parameters,
                        cv = 2,
                        n_jobs = 5,
                        verbose=True)

xgb_grid.fit(X,y)

print(xgb_grid.best_score_)
print(xgb_grid.best_params_)

Результат следующий:
Скорректировано 2 сгиба для каждого из 54 кандидатов, всего 108 совпадений.

мы пишем эти параметры в нашей модели XGBoost

xgb=XGBClassifier(n_estimators=150, learning_rate=0.1, max_depth=2, colsample_bytree=0.7 ,randomstate=0)
xgb.fit(X_f_train, y_f_train)
metrics(y_test, xgb.predict(X_f_test))

точность: 0,9822268687924726
f1: 0,9831516352824579
рок auc: 0,982836728555653

Метрики лучше, чем у случайного леса, причём в трёх его вариантах.
Можно добавить Gain вверху и уменьшить выборку, но для меня 8 параметров и такие метрики — хорошее соотношение. Если у кого-то есть желание, думаю, не составит труда реализовать метод Gain по аналогии со Random-Forest (опять же предыдущая статья).

И мы переходим к следующему шагу

ЧатBoost

7cbb99feed99cfefc7c546585ee9e6bd

Подбор параметров можно сделать и через Catboost, к тому же у него для этого есть свой метод, который тоже строит крутой график, но придется подождать, а параметры XGBoost у нас уже есть и думаю никто не будет против, если интегрируем их в Catboost с небольшими изменениями:

from catboost import CatBoostClassifier
cat=CatBoostClassifier(n_estimators=150, learning_rate=0.1, max_depth=2,bootstrap_type="Bayesian", task_type="GPU")
cat.fit(X_f_train,y_f_train, verbose=False)
cat_pred=cat.predict(X_f_test)
metrics(y_test, cat_pred)

Метрика:
точность: 0,9822268687924726
f1: 0,9831516352824579
рок auc: 0,982836728555653

Итак, с классической точки зрения ML мы реализовали самые популярные модели и, как и ожидалось, получили лучшие метрики по моделям повышения градиента.

Нейронная сеть на тензорном потоке

Теперь проверим высказанный в первой части тезис о том, что эту задачу можно решить с помощью нейронной сети.

Во-первых, давайте нормализуем данные к нормальному распределению.

mean=X_train.mean(axis=0)
std=X_train.std(axis=0)
X_train-= mean
X_train/= std
X_test-= mean
X_test/= std
#запринтим что мы сделали
print('train mean',X_train.mean(axis=0)[:5]) 
print('test mean',X_test.mean(axis=0)[:5]) 
print('train std',X_train.std(axis=0)[:5])
print('train std',X_test.std(axis=0)[:5])

стандартное отклонение – стандартное отклонение
средний — средний

Кстати, std будет равен 1 для всех напечатанных

e0032699e4a0ef87605dd0c54f727d5f

Небольшое отступление

Для построения нейронной сети мы будем использовать tensorflow, который после версии 2.11 перестал поддерживать обучение GPU в Windows; вы можете узнать больше на их сайте: https://www.tensorflow.org/install/pip?hl=ru#windows-native_1
Чтобы это исправить нужно установить Python версии 3.9 (у меня 3.9.18), текущий Python удалять не нужно, но для версии 3.9 нужно создать отдельную виртуальную среду, например через miniconda, скачать CUDA и CUDNN, если у вас есть NVidia, я не знаю альтернатив, так как она есть у самой Nvidia. Вся прелесть установки заключается в том, что вам предстоит выбрать правильные версии всех этих расширений и библиотеки tensorflow. Это действительно может занять много времени, если вы никогда раньше не делали ничего подобного, поэтому вам также может помочь этот парень с YouTube, который ошибся и сделал подробную установку всех Cuda и Cudnn: https://www.youtube.com/watch?v=xTF_n1jp9n8
Тем не менее, о создании новой Venv (виртуальной среды) разговоров, похоже, не так много, поэтому те, кто ищет в Google, помогите мне.
Альтернативой всему этому является либо обучение на CPU, то есть на классическом процессоре, либо на Google Colab, где вы можете выбрать, на чем будет работать ваша среда, и воспользоваться преимуществами сервиса. Их мощности должно быть достаточно для этой задачи.
Обучение на GPU идет явно быстрее, чем на CPU: прироста в 1,5-2 раза можно добиться с уверенностью.

ЧИТАТЬ   10 признаков того, что работодатель выжмет из вас все соки, не оставив и капли

Давайте закончим это отступление

Зададим параметры модели, а перед этим проверим, работает ли графический процессор

import tensorflow as tf 
physical_devices = tf.config.list_physical_devices('GPU')
print("Num GPUs:", len(physical_devices))
#output: 1  если gpu работает

model = tf.keras.Sequential([
    tf.keras.layers.Dense(32, activation='relu', input_shape=(X_train.shape[1],)),
    tf.keras.layers.Dense(16, activation='relu' ),
                    
    tf.keras.layers.Dense(1, activation='sigmoid')
])
model.summary()

# Model: "sequential"
# _________________________________________________________________
#  Layer (type)                Output Shape              Param #   
# =================================================================
#  dense (Dense)               (None, 32)                1376      
                                                                 
#  dense_1 (Dense)             (None, 16)                528       
                                                                 
#  dense_2 (Dense)             (None, 1)                 17        
                                                                 
# =================================================================
# Total params: 1,921
# Trainable params: 1,921
# Non-trainable params: 0
# _________________________________________________________________

Мы обучаем и проверяем потери


model.compile(optimizer="adam", loss="binary_crossentropy")

history = model.fit(X_train, y_train, epochs=16, verbose=1)

# Визуализация процесса обучения
plt.plot(history.history['loss'])
plt.xlim(-0.5,20)
plt.title('Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show()
потеря модели

потеря модели

Давайте воспользуемся Datagenerator, позаимствованным у этого замечательного автора YouTube: https://www.youtube.com/watch?v=PLlic60dgS4&list=PLkJJmZ1EJno4lRvtQjQrNNACpeMLOd-SD&index=7

Он устанавливает пакетный_размер, поэтому если вы хотите получить результат быстрее, просто увеличьте его, скажем, до 16, 32 или 48 и т. д. Качество модели снизится, но она будет строиться быстрее.

import numpy as np
from tensorflow.keras.utils import Sequence


class DataGenerator(Sequence):
    def __init__(self, data, labels, batch_size=1):
        self.batch_size = batch_size
        self.data = data
        self.labels = labels
        
    def __len__(self):
        return int(np.round(len(self.data) / self.batch_size))

    def __getitem__(self, index):
        X = self.data[index * self.batch_size : (index+1) * self.batch_size]
        y = self.labels[index * self.batch_size : (index+1) * self.batch_size]

        return X, y
train_datagen = DataGenerator(X_train, y_train)
test_datagen = DataGenerator(X_test, y_test)
print(len(train_datagen))
print(len(test_datagen))

Давайте обучим другой нейрон оценке данных для проверки.

from tensorflow.keras.callbacks import ModelCheckpoint

# Создаем коллбэк для выполнения оценки на валидационных данных
checkpoint = ModelCheckpoint(filepath="best_model.h5", save_best_only=True, save_weights_only=True)
# Обучение модели с выполнением оценки на валидационных данных
history = model.fit(train_datagen, epochs=16, batch_size=100, validation_data=test_datagen, callbacks=[checkpoint])

# Загрузка лучших весов модели
model.load_weights('best_model.h5')

plt.plot(history.history['loss'], label="train loss")
plt.plot(history.history['val_loss'], label="validation loss")
plt.legend( );
99d4448a75edbfff0363939dc502497c

Ну, видимо не сегодня, тензорный поток.

Вы можете изменить настройки модели и, возможно, получить хорошие измерения, но это того не стоит.

Основной. Изоляционный лес

Похоже, мы сделали все, что могли, и после увеличения градиента можно было бы остановиться и сказать, что модель готова, но ради интереса можно рассмотреть Isolation Forest. Это метод обучения без учителя, используемый в задачах кластеризации и обнаружения аномалий.

from sklearn.ensemble import IsolationForest
clf = IsolationForest(max_samples=50, random_state=0)
clf.fit(X_f)
pred=clf.predict(X_f_test)
# на выход модель выдает либо 1 либо -1, для перехода к нашим параметрам, нужно переписать значения:
pred_processed = np.where(pred == -1, 0, pred)

pred_counts = pd.Series(pred_processed).value_counts()

# Строим график
pred_counts.plot(kind='barh', color=sns.palettes.mpl_palette('Dark2'))
plt.gca().spines[['top', 'right']].set_visible(False)
plt.title('Isolation Forest')
plt.xlim(0, pred_counts.max()) 
plt.show()
13ef6a5a4169238d6db51dcba1fefd38
zeros_count = y_test[y_test == 0].count()
ones_count = y_test[y_test == 1].count()

print("Количество нулей в y_test:", zeros_count)
print("Количество единиц в y_test:", ones_count)

Количество нулей в y_test: koi_pdisposition 894 dtype: int64
Количество единиц в y_test: koi_pdisposition 1019 dtype: int64

ЧИТАТЬ   Создал и продвигал MidPad в App Store для чайников. Первая часть - Идея

Можно прогнать через метрики, но особого смысла в этом нет, потому что количество нулей в реальных данных примерно на 150-200 значений больше, чем в модели, и в принципе подход от метрик к задачам без учитель — сомнительный процесс. Возможно, мы получили совсем не то, что искали.

Заключение

Повышение градиента остается громом Kaggle и является отличной моделью для решения этой проблемы, которая справилась с этой задачей лучше, чем NN. Причина, мне кажется, в том, что нейрону нужно на порядок больше данных, тогда он будет играть по-другому и ожидание процесса обучения окупится. Надеюсь, что последние 2 статьи заинтересовали определенный круг людей, как новичков, так и более опытных в области науки о данных; Хотелось бы получить отзыв о проделанной работе или совет, как можно улучшить результаты модели.

Source

От admin