Откройте для себя возможности Yellowbrick и расширьте возможности!

Пульсары - это сильно намагниченные вращающиеся нейтронные звезды, испускающие пучки электромагнитного излучения из своих магнитных полюсов. Пульсары - один из кандидатов на роль источника космических лучей сверхвысокой энергии. Они важны, поскольку помогают изучать экстремальные состояния материи, искать экзопланеты, измерять космические расстояния и находить гравитационные волны.

Мы проведем классификацию пульсаров, охватывающую все аспекты проблемы, включая EDA с использованием автоматизированного модуля EDA, выбор функции с использованием важности функции, настройку гиперпараметров с помощью RandomizedSearchCV, работу с несбалансированными классами и визуализацией с использованием Yellowbrick и mlxtend.

Исходный код можно найти по следующей ссылке:



Для доступа к набору данных перейдите по следующей ссылке:



Предпосылки

yellowbrick, mlxtend и imblearn необходимо установить отдельно, выполнив следующие действия: Установите yellowbrick, mlxtend и imblearn с помощью команды PIP в командной строке или в строке Anaconda:

$ pip install yellowbrick
$ pip install mlxtend
$ pip install imblearn

Импорт пакетов

import timeit
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import mlxtend
import warnings
warnings.filterwarnings("ignore")
from ClfAutoEDA import *

ClfAutoEDA - это автоматизированный EDA практически для любой задачи классификации. Его использование можно понять, обратившись к моей предыдущей статье:



Загрузка данных

# Load the pulsar dataset from the csv file using pandas
df=pd.read_csv('pulsar_stars.csv')

Запустите автоматизированную программу EDA

#set the values of EDA function parameters and then run the program
labels=["non-pulsar","pulsar"]
target_variable_name='target_class'
df_processed,num_features,cat_features=EDA(df,labels,
                                         target_variable_name,
                                         data_summary_figsize=(6,6),
                                         corr_matrix_figsize=(6,6),
                                         corr_matrix_annot=True,
                                         pairplt=True)

Вуаля! Он автоматически дает вам следующее описание данных и графики

The data looks like this: 
     Mean of the integrated profile  ...  target_class
0                       140.562500  ...             0
1                       102.507812  ...             0
2                       103.015625  ...             0
3                       136.750000  ...             0
4                        88.726562  ...             0
[5 rows x 9 columns]
The shape of data is:  (17898, 9)
The missing values in data are: 
 target_class                                     0
 Skewness of the DM-SNR curve                    0
 Excess kurtosis of the DM-SNR curve             0
 Standard deviation of the DM-SNR curve          0
 Mean of the DM-SNR curve                        0
 Skewness of the integrated profile              0
 Excess kurtosis of the integrated profile       0
 Standard deviation of the integrated profile    0
 Mean of the integrated profile                  0
dtype: int64
The summary of data is: 
         Mean of the integrated profile  ...  target_class
count                     17898.000000  ...  17898.000000
mean                        111.079968  ...      0.091574
std                          25.652935  ...      0.288432
min                           5.812500  ...      0.000000
25%                         100.929688  ...      0.000000
50%                         115.078125  ...      0.000000
75%                         127.085938  ...      0.000000
max                         192.617188  ...      1.000000
[8 rows x 9 columns]
Some useful data information:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 17898 entries, 0 to 17897
Data columns (total 9 columns):
 #   Column                                         Non-Null Count  Dtype  
---  ------                                         --------------  -----  
 0    Mean of the integrated profile                17898 non-null  float64
 1    Standard deviation of the integrated profile  17898 non-null  float64
 2    Excess kurtosis of the integrated profile     17898 non-null  float64
 3    Skewness of the integrated profile            17898 non-null  float64
 4    Mean of the DM-SNR curve                      17898 non-null  float64
 5    Standard deviation of the DM-SNR curve        17898 non-null  float64
 6    Excess kurtosis of the DM-SNR curve           17898 non-null  float64
 7    Skewness of the DM-SNR curve                  17898 non-null  float64
 8   target_class                                   17898 non-null  int64  
dtypes: float64(8), int64(1)
memory usage: 1.2 MB
None
The columns in data are: 
 [' Mean of the integrated profile'
 ' Standard deviation of the integrated profile'
 ' Excess kurtosis of the integrated profile'
 ' Skewness of the integrated profile' ' Mean of the DM-SNR curve'
 ' Standard deviation of the DM-SNR curve'
 ' Excess kurtosis of the DM-SNR curve' ' Skewness of the DM-SNR curve'
 'target_class']
The target variable is divided into: 
 0    16259
1     1639
Name: target_class, dtype: int64
The numerical features are: 
 [' Mean of the integrated profile', ' Standard deviation of the integrated profile', ' Excess kurtosis of the integrated profile', ' Skewness of the integrated profile', ' Mean of the DM-SNR curve', ' Standard deviation of the DM-SNR curve', ' Excess kurtosis of the DM-SNR curve', ' Skewness of the DM-SNR curve', 'target_class']
The categorical features are: 
 []
Execution Time for EDA: 0.48 minutes

Глядя на все вышеперечисленные сюжеты и описание, можно сделать вывод:

  • В наборе данных нет нулевых значений
  • Несбалансированные классы
  • Данные вполне разделимы
  • Без категориальных признаков
  • Некоторые функции сильно искажены

Когда у нас есть асимметрия, мы делаем их нормально распределенными путем преобразования (логарифм, прямоугольник и т. Д.), Но в данном случае асимметрия связана с тем, что характеристики, рассматриваемые для описания пульсара, в буквальном смысле являются измерениями асимметрии, стандартных отклонений и т. Д., И поэтому нам необходимо рассматривайте такие особенности как они есть.

Сюжет RadViz

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

Он используется для обнаружения разделимости между классами, то есть есть ли возможность учиться на наборе функций или слишком много шума?

#dividing the X and the y
X=df_processed.drop([target_variable_name], axis=1)
y=df_processed[target_variable_name]
#RadViz plot
from yellowbrick.features import RadViz
visualizer = visualizer = RadViz(classes=labels, features=X.columns.tolist(),size = (800,300))
visualizer.fit(X, y)      
visualizer.transform(X)  
visualizer.show()

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

Важность функции

# Split the data into training and testing sets
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 42)
#import classification models
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier,ExtraTreesClassifier
from sklearn.model_selection import cross_val_score, RandomizedSearchCV
logreg=LogisticRegression()
SVM=SVC()
knn=KNeighborsClassifier()
etree=ExtraTreesClassifier(random_state=42)
rforest=RandomForestClassifier(random_state=42)
scaler=StandardScaler()
features=X_train.columns.tolist()
X_train_scaled=scaler.fit_transform(X_train) 
X_test_scaled=scaler.fit_transform(X_test)
#get feature importance
start_time = timeit.default_timer()
mod=etree
# fit the model
mod.fit(X_train_scaled, y_train)
# get importance
importance = mod.feature_importances_
# summarize feature importance
for i,v in enumerate(importance):
 print('Feature: %0d, Score: %.5f' % (i,v))
# plot feature importance
df_importance=pd.DataFrame({'importance':importance},index=features)
df_importance.plot(kind='barh')
elapsed = timeit.default_timer() - start_time
print('Execution Time for feature selection: %.2f minutes'%(elapsed/60))

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

Настройка гиперпараметров

В отличие от GridSearchCV, не все значения параметров проверяются в RandomizedSearchCV, а скорее фиксированное количество настроек параметров выбирается из указанных распределений, что значительно ускоряет поиск.

#create a list of models you want to try for random search
models=[knn,rforest,etree,SVM]
#create a list of dictionaries containing hyperparameters of different models
param_distributions=[{'n_neighbors':[5,10,15]},{'criterion':['gini', 'entropy'],'n_estimators':[100,200,300]},{'criterion':['gini', 'entropy'],'n_estimators':[100,200,300]},{'kernel':['rbf','linear'],'C':[0.1,1,10],'gamma':[0.1,0.01,0.001]}]
for model in models: rand=RandomizedSearchCV(model,param_distributions=param_distributions[models.index(model)],cv=3,scoring='accuracy', n_jobs=-1, random_state=42,verbose=10)
rand.fit(X_train_sfs_scaled,y_train)
print(rand.best_params_,rand.best_score_)

Он дает лучшие параметры и точность для ExtraTreesClassifier: {‘n_estimators’: 300, ‘criterion’: ‘gini’} 0,979565772669221

Мы будем использовать эти настроенные гиперпараметры и подогнать модель под данные.

Подгонка и визуализация данных

Мы подгоним данные, используя настроенную модель классификации Extra Trees, а для визуализации производительности модели воспользуемся Yellowbrick. Визуализация производительности модели будет состоять из матрицы неточностей, отчета о классификации и кривой ROC-AUC.

#fitting the data with tuned model
classes=['Non-Pulsar','Pulsar']
model=ExtraTreesClassifier(n_estimators=300,criterion='gini',random_state=42)
model.fit(X_train_sfs_scaled,y_train)
y_pred = model.predict(X_test_sfs_scaled)
#Creating a visualization function using Yellowbrick
from yellowbrick.classifier import ConfusionMatrix, ClassificationReport, ROCAUC
from sklearn.metrics import  classification_report
def yellowbrick_visualizations(model,classes,X_tr,y_tr,X_te,y_te):
    visualizer=ConfusionMatrix(model,classes=classes)
    visualizer.fit(X_tr,y_tr)
    visualizer.score(X_te,y_te)
    visualizer.show()
    
    visualizer = ClassificationReport(model, classes=classes, support=True)
    visualizer.fit(X_tr,y_tr)
    visualizer.score(X_te,y_te)
    visualizer.show()
    
    visualizer = ROCAUC(model, classes=classes)
    visualizer.fit(X_tr,y_tr)
    visualizer.score(X_te,y_te)
    visualizer.show()
    

yellowbrick_visualizations(model,classes,X_train_sfs_scaled,y_train,X_test_sfs_scaled,y_test)

Глядя на отчеты, мы видим, что отзыв для обнаружения пульсаров составляет всего 83,3%. Это связано с тем, что мы не исправили дисбаланс классов, и поэтому наша модель имеет смещение в сторону непульсаров, поскольку они составляют 90,84% от всех данных.

Устранение дисбаланса в классе

Мы можем использовать различные методы, такие как SMOTE, Near Miss, Random Sampling и т. Д., Чтобы справиться с дисбалансом классов. Мы использовали SMOTE для решения этой проблемы, но вы можете попробовать эти различные выпрямители и увидеть изменения.

from imblearn.over_sampling import SMOTE,RandomOverSampler,BorderlineSMOTE
from imblearn.under_sampling import NearMiss,RandomUnderSampler
smt = SMOTE()
nr = NearMiss()
bsmt=BorderlineSMOTE(random_state=42)
ros=RandomOverSampler(random_state=42)
rus=RandomUnderSampler(random_state=42)
#Use one of these class imbalance rectifiers to balance the data
X_train_bal, y_train_bal = smt.fit_sample(X_train_sfs_scaled, y_train)
print(np.bincount(y_train_bal))
#fit the tuned model with balanced data
model_bal=model
model_bal.fit(X_train_bal, y_train_bal)
y_pred = model_bal.predict(X_test_sfs_scaled)

yellowbrick_visualizations(model_bal,classes,X_train_bal, y_train_bal,X_test_sfs_scaled,y_test)

Глядя на отчеты, мы видим, что запоминаемость для обнаружения пульсаров улучшилась почти до 90% (с 83,3%) с высоким значением точности (88,8%).

Регион принятия решения

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

Мы будем использовать mlxtend для построения области решения для нашего настроенного классификатора Extra Trees, сначала уменьшив количество функций до 2 с помощью PCA.

from sklearn.decomposition import PCA
from mlxtend.plotting import plot_decision_regions as plot_dr
#Plot decision region
def plot_classification(model,X_t,y_t):
    clf=model
    pca = PCA(n_components = 2)
    X_t2 = pca.fit_transform(X_t)
    clf.fit(X_t2,np.array(y_t))
    plot_dr(X_t2, np.array(y_t), clf=clf, legend=2)
plot_classification(model_bal,X_test_sfs_scaled,y_test)

Чтобы узнать больше о Yellowbrick и mlxtend, смотрите их документацию:





Прежде чем ты уйдешь

Спасибо за чтение! Не стесняйтесь применять эту методологию к своим задачам классификации. Если у вас есть какие-либо трудности или сомнения, пожалуйста, оставьте комментарий ниже. Мы всегда высоко ценим вашу поддержку. Если вы хотите связаться со мной, напишите мне на [email protected].