Откройте для себя возможности 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].