Классифицируйте разные типы очков

Описание проблемы
Эта проблема связана с классификацией стекла по определенным характеристикам. Эта конкретная проблема может быть решена с помощью алгоритма машинного обучения, такого как SVC, Random Forest или любого другого алгоритма классификации, но я использовал нейронную сеть. Однако выбор простого алгоритма будет лучше, потому что у нас мало данных.

Источник данных
Данные общедоступны через Kaggle, отсюда вы можете легко скачать их здесь.

О данных
Цель набора данных - предсказать класс стекла на основе заданных характеристик. Всего имеется около 9 функций (номер идентификатора, RI, Na, Mg, Al, Si, K, Ca, Ba), в котором все столбцы, кроме столбцов Id, играют важную роль в определении типа стакана, который также является нашей целевой переменной, есть 7 типов очков, которые указаны в описании набора данных, но в наборе данных у нас нет данных о стекле типа 4, у каждого типа стекла есть собственное имя, но в данных целевая переменная пронумерована от 1 до 7. Таким образом, на основе доступных функций мы должны предсказать целевую переменную (тип стекло).

import pandas as pd
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
from imblearn.over_sampling import SMOTE
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
import tensorflow as tf
from tensorflow as keras
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.utils import to_categorical, normalize
from keras.callbacks import Callback, EarlyStopping
import warnings
warnings.filterwarnings('ignore')

Доступный мне набор данных не содержал заголовка, если данные, которые вы загрузили, имеют заголовок, тогда игнорируйте «header = None»

df=pd.read_csv('/content/glass_data.csv',header=None)
df.columns=['Id','refractive_index','Sodium','Magnesium',\
'Aluminium','Silicon','Potassium','Calcium','Barium','Iron','Glass_type']
df.head()

Столбец Id бесполезен, поэтому его следует отбросить. Следует отметить, что когда мы отбросили столбец Id, мы обнаружили, что данные также содержат некоторые повторяющиеся значения.

df.drop('Id',axis=1,inplace=True)

Сводка данных

Сводка данных - одна из полезных операций для фреймов данных, которая дает нам количество, среднее значение, стандартное отклонение вместе с 5-кратной сводкой об особенностях данных.
Сводка из 5-ти номеров содержит:

  1. Мин.
  2. Q1
  3. Медиана
  4. Q3
  5. Максимум

поэтому функция describe возвращает сводку из 5 чисел вместе с другими статистическими методами, такими как стандартное отклонение, счетчик и среднее значение.

df.describe()

Проверка нуля

В наборе данных нет нулевого значения.

df.isna().sum()

Повторный чек

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

df[df.duplicated()]

Удаление дубликатов

Как работать с повторяющимися записями
Есть несколько способов справиться с повторяющимися записями, но мы приняли подход, сохранив последние строки и опуская строки, которые появились первыми в наборе данных.

df.drop_duplicates(keep='last',inplace=True

Краткое резюме

Функция info фрейма данных предоставляет краткую сводку функций, включая количество ненулевых значений, тип данных каждой функции и использование памяти.

df.info()

Парный график

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

corr_mat=df.corr()
plt.figure(figsize=(16,10))
sns.heatmap(corr_mat,annot=True,fmt='.2f',alpha = 0.7,   cmap= 'coolwarm')
plt.show())

Распределение классов

Распределение набора данных типа стекла, которое показывает распределение каждого типа стекла в наборе данных, а также то, сколько раз конкретное стекло встречается в наборе данных. Распределение показывает нам, что данные несбалансированы

plt.figure(figsize=(10,10))
sns.countplot(x='Glass_type', data=df, order=df['Glass_type'].value_counts().index);

Разделение функций и целевой переменной

мы разделили функции и целевые переменные, все независимые переменные хранятся в переменной X, а зависимая переменная хранится в переменных y.
Независимые переменные нормализуются с помощью функции нормализации из Keras.Util API Keras. Нормализацию также можно выполнить с помощью Scikit-Learn API Standard-Scaler, Min-Max-Scaler или Robust-Scaler. Есть много способов справиться с этим.

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

X=df.drop('Glass_type',axis=1)
X=normalize(X)
y=df['Glass_type']

Балансировка классов

Как указано выше в разделе «Распределение классов», мы видим, что классы являются дисбалансными, поэтому, если мы разработаем модель набора данных по дисбалансу, модель будет смещаться в сторону класса, содержащего большую часть образцов, поэтому работа с классами дисбаланса поможет в разработке справедливой модели.

from imblearn.over_sampling import RandomOverSampler

ros = RandomOverSampler(random_state=42)
x_ros, y_ros = ros.fit_resample(X, y)

Разделение данных
Теперь данные сбалансированы, поэтому мы разделяем этот сбалансированный набор данных на данные тестирования и проверки. Дважды используя разделение обучающих тестов Scikit-Learn API, мы разделяем данные, 75% данных используются в качестве обучающих данных, а затем мы разделяем 25% тестовых данных на тестовые и проверочные данные.
Распечатывая форму данных. мы видим, что 75% данных находится в обучающем наборе, а оставшиеся 25% данных далее делятся наполовину на данные тестирования и проверки.

X_train, X_test, y_train, y_test = train_test_split(x_ros,y_ros,test_size=0.25,random_state=42)
X_test, X_val, y_test, y_val = train_test_split(X_test,y_test,stratify=y_test,test_size = 0.5,random_state=42)
y_train=to_categorical(y_train)
y_test=to_categorical(y_test)
y_val=to_categorical(y_val)
print('X_train :',X_train.shape)
print('y_train :',y_train.shape)
print('X_test :',X_test.shape)
print('y_test :',y_test.shape)
print('X_val :',X_val.shape)
print('y_val :',y_val.shape)
# Output:
# X_train : (342, 9)
# y_train : (342, 8)
# X_test : (57, 9)
# y_test : (57, 8)
# X_val : (57, 9)
# y_val : (57, 8)

Построение модели

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

Можно найти хорошую модель, используя библиотеки Keras для настройки параметров и определения наилучшего количества слоев. Но я придерживаюсь простого подхода, потому что наша проблема не так уж и сложна.

model = tf.keras.models.Sequential([
tf.keras.layers.Dense(40,input_shape=(9,),activation='relu'),

tf.keras.layers.Dense(20,activation='relu'),

tf.keras.layers.Dense(8, activation='softmax')
])

model.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])
model.summary()

Стоп-лосс

Перед обучением модели на данных мы определили подход к ранней остановке, повторное обучение модели может занять очень много времени, когда размер эпохи больше. Таким образом, добавление раннего стопа было лучшим вариантом для измерения потерь при проверке, всякий раз, когда потери при проверке модели перестают улучшаться в течение 20 периодов, которые задаются с помощью параметра терпения, модель прекращает обучение. Модель настраивается на обучающие данные и одновременно проверяется на проверочном наборе.

early_stop = EarlyStopping(
                monitor='val_loss', #Quantity to be monitored.
                mode='auto', #direction is automatically inferred from the name of the monitored quantity
                verbose=1, #verbosity mode.
                patience=20 #Number of epochs with no improvement after which training will be stopped
              )

Обучение модели

Теперь архитектура модели доработана, и мы также поставили раннюю остановку. Теперь пришло время обучить модель на обучающих данных и проверить ее с помощью данных проверки. Модель будет тренироваться в течение 1000 эпох, если потеря проверки будет продолжать уменьшаться, если потеря проверки перестанет уменьшаться, тогда модель остановит итерации после проверки далее до 20 эпох.

history = model.fit(X_train, y_train,
                    epochs=1000,
                    validation_data=(X_val, y_val),
                    callbacks=[early_stop],
                    verbose=2,
                   )

График точности

Модель успешно обучена и проверена на данных, теперь мы можем отобразить точность модели на наборе поездов и точность на наборе данных проверки. На приведенном ниже графике показано визуальное представление обеих погрешностей вместе с легендами в правом нижнем углу.

plt.figure(figsize=(18,8))
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Training-Accuracy', 'validation-Accuracy'], loc='lower right')
plt.show()

График потерь

Представление потерь модели можно увидеть на графике ниже вместе с легендами.

plt.figure(figsize=(18,8))
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Training-Loss', 'validation-Loss'], loc='upper right')
plt.show()

Оценка модели

Теперь мы закончили со всеми вещами, связанными с обучением модели, теперь пришло время протестировать нашу модель на тестовых данных, которые модель не увидела, чтобы проверить, как модель работает с невидимым набором данных. Мы видим, что модель также достигла точности 63% по сравнению с тестовыми данными. Оценка точности не является хорошим вариантом для измерения производительности модели, которая обучается с использованием набора данных о дисбалансе, однако мы сбалансировали набор данных, поэтому можем считать этот показатель надежным.

model.evaluate(X_test, y_test)

Отчет о классификации

Отчет о классификации дает представление о классе, который модель предсказывает, или является правильным, или неправильным. Значения в диагоналях представляют классы, которые предсказаны правильно, тогда как значения, отличные от диагоналей, являются неверными предсказаниями.

y_pred = model.predict(X_test) # model predicions of test data y_pred_max = np.argmax(y_pred,axis=1) # choosing the max probability predicted by model y_test_max = np.argmax(y_test,axis=1) # selecting max from y_test for comparison confusion_matrix(y_test_max, y_pred_max)
#Output
array([[1, 2, 8, 0, 0, 0],
      [0, 6, 6, 0, 0, 0],
      [0, 1, 5, 0, 0, 0],
      [0, 0, 0, 7, 0, 0],
      [0, 0, 0, 0, 8, 2], 
      [0, 0, 1, 1, 0, 9]])

Заключение

С помощью нейронной сети мы достигли точности около 65% процентов, что достигается применением методов отслеживания и ошибок, чтобы найти лучшую архитектуру нейронной сети, которая не соответствует ни избыточной, ни недостаточной. Точность можно повысить, добавив больше данных, поскольку нейронные сети считаются лучшими для большого количества данных. для меньшего объема данных лучше работают традиционные алгоритмы машинного обучения. Чем больше данных у нас есть, тем больше они помогают модели в изучении лучших параметров.