Поиск по сайту:

Многоклассовая несбалансированная классификация


Несбалансированная классификация — это те задачи прогнозирования, в которых распределение примеров по меткам классов неравномерно.

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

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

После завершения этого урока вы будете знать:

  • О проблеме несбалансированного многоклассового предсказания стандарта идентификации стекла.
  • Как использовать передискретизацию SMOTE для несбалансированной многоклассовой классификации.
  • Как использовать экономичное обучение для несбалансированной многоклассовой классификации.

Начните свой проект с моей новой книги «Несбалансированная классификация с помощью Python», включающей пошаговые руководства и файлы исходного кода Python для всех примеры.

Давайте начнем.

  • Обновление: январь 2021 г.: обновлены ссылки на документацию по API.

Обзор руководства

Этот урок разделен на три части; они есть:

  1. Набор данных классификации нескольких классов стекла
  2. Передискретизация SMOTE для многоклассовой классификации
  3. Экономичное обучение для многоклассовой классификации

Набор данных классификации нескольких классов стекла

В этом уроке мы сосредоточимся на стандартной задаче несбалансированной многоклассовой классификации, называемой «Идентификация стекла» или просто «стекло».

Набор данных описывает химические свойства стекла и включает классификацию образцов стекла по их химическим свойствам в один из шести классов. Набор данных был приписан Вине Шпилер в 1987 году.

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

  • RI: показатель преломления
  • Na: натрий
  • Мг: Магний
  • Ал: Алюминий
  • Си: Кремний
  • К: Калий
  • Са: кальций
  • Ба: Барий
  • Fe: железо

Химический состав измеряется как весовой процент соответствующего оксида.

Перечислено семь типов стекла; они есть:

  • Класс 1: окна здания (плавающая обработка)
  • Класс 2: окна здания (не плавающие)
  • Класс 3: окна автомобиля (поплавковые).
  • Класс 4: окна автомобиля (неплавающие)
  • Класс 5: контейнеры
  • Класс 6: посуда
  • Класс 7: фары

Флоат-стекло — это процесс изготовления стекла.

В наборе данных 214 наблюдений, и количество наблюдений в каждом классе несбалансировано. Обратите внимание, что в наборе данных нет примеров для класса 4 (окна транспортных средств с неплавающей обработкой).

  • Класс 1: 70 примеров
  • Класс 2: 76 примеров
  • Класс 3: 17 примеров
  • Класс 4: 0 примеров
  • Класс 5: 13 примеров
  • Класс 6: 9 примеров
  • Класс 7: 29 примеров

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

Набор данных можно разделить на оконные стекла (классы 1–4) и неоконные стекла (классы 5–7). Имеется 163 образца оконного стекла и 51 образец неоконного стекла.

  • Оконное стекло: 163 примера
  • Неоконные стекла: 51 пример

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

  • Флоат-стекло: 87 примеров
  • Нефлоатское стекло: 76 примеров

Подробнее о наборе данных можно узнать здесь:

  • Набор данных по стеклу (glass.csv)
  • Описание набора данных Glass (glass.names)

Нет необходимости загружать набор данных; мы загрузим его автоматически как часть отработанных примеров.

Ниже приведен образец первых нескольких строк данных.

1.52101,13.64,4.49,1.10,71.78,0.06,8.75,0.00,0.00,1
1.51761,13.89,3.60,1.36,72.73,0.48,7.83,0.00,0.00,1
1.51618,13.53,3.55,1.54,72.99,0.39,7.78,0.00,0.00,1
1.51766,13.21,3.69,1.29,72.61,0.57,8.22,0.00,0.00,1
1.51742,13.27,3.62,1.24,73.08,0.55,8.07,0.00,0.00,1
...

Мы видим, что все входные данные являются числовыми, а целевая переменная в последнем столбце — это метка класса в целочисленной кодировке.

Вы можете узнать больше о том, как работать с этим набором данных в рамках проекта, в руководстве:

  • Несбалансированная мультиклассовая классификация с набором данных для идентификации стекла

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

Передискретизация SMOTE для многоклассовой классификации

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

Пожалуй, наиболее широко используемый подход к синтезу новых примеров называется «Техника передискретизации синтетического меньшинства», или сокращенно SMOTE. Этот метод был описан Нитешем Чавлой и др. в своей статье 2002 года, названной в честь метода под названием «SMOTE: метод синтетической избыточной выборки меньшинства». »

Вы можете узнать больше о SMOTE в руководстве:

  • SMOTE для несбалансированной классификации с помощью Python

Библиотека несбалансированного обучения предоставляет реализацию SMOTE, которую мы можем использовать и совместимую с популярной библиотекой scikit-learn.

Сначала необходимо установить библиотеку. Мы можем установить его с помощью pip следующим образом:

sudo pip установить несбалансированное обучение

Мы можем подтвердить, что установка прошла успешно, распечатав версию установленной библиотеки:

# check version number
import imblearn
print(imblearn.__version__)

При запуске примера будет выведен номер версии установленной библиотеки; например:

0.6.2

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

# load and summarize the dataset
from pandas import read_csv
from collections import Counter
from matplotlib import pyplot
from sklearn.preprocessing import LabelEncoder
# define the dataset location
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/glass.csv'
# load the csv file as a data frame
df = read_csv(url, header=None)
data = df.values
# split into input and output elements
X, y = data[:, :-1], data[:, -1]
# label encode the target variable
y = LabelEncoder().fit_transform(y)
# summarize distribution
counter = Counter(y)
for k,v in counter.items():
	per = v / len(y) * 100
	print('Class=%d, n=%d (%.3f%%)' % (k, v, per))
# plot the distribution
pyplot.bar(counter.keys(), counter.values())
pyplot.show()

При выполнении примера сначала загружается набор данных и разбивается на обучающий и тестовый наборы.

Затем сообщается количество строк в каждом классе, что подтверждает, что некоторые классы, например 0 и 1, имеют гораздо больше примеров (более 70), чем другие классы, например 3 и 4 (менее 15).

Class=0, n=70 (32.710%)
Class=1, n=76 (35.514%)
Class=2, n=17 (7.944%)
Class=3, n=13 (6.075%)
Class=4, n=9 (4.206%)
Class=5, n=29 (13.551%)

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

Это дает более четкое представление о том, что в классах 0 и 1 гораздо больше примеров, чем в классах 2, 3, 4 и 5.

Далее мы можем применить SMOTE для передискретизации набора данных.

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

В этом случае класс 1 содержит больше всего примеров — 76, поэтому SMOTE будет выполнять передискретизацию всех классов, чтобы получить 76 примеров.

Полный пример передискретизации набора данных стекла с помощью SMOTE приведен ниже.

# example of oversampling a multi-class classification dataset
from pandas import read_csv
from imblearn.over_sampling import SMOTE
from collections import Counter
from matplotlib import pyplot
from sklearn.preprocessing import LabelEncoder
# define the dataset location
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/glass.csv'
# load the csv file as a data frame
df = read_csv(url, header=None)
data = df.values
# split into input and output elements
X, y = data[:, :-1], data[:, -1]
# label encode the target variable
y = LabelEncoder().fit_transform(y)
# transform the dataset
oversample = SMOTE()
X, y = oversample.fit_resample(X, y)
# summarize distribution
counter = Counter(y)
for k,v in counter.items():
	per = v / len(y) * 100
	print('Class=%d, n=%d (%.3f%%)' % (k, v, per))
# plot the distribution
pyplot.bar(counter.keys(), counter.values())
pyplot.show()

Выполнение примера сначала загружает набор данных и применяет к нему SMOTE.

Затем сообщается о распределении примеров в каждом классе, что подтверждает, что теперь в каждом классе 76 примеров, как мы и ожидали.

Class=0, n=76 (16.667%)
Class=1, n=76 (16.667%)
Class=2, n=76 (16.667%)
Class=3, n=76 (16.667%)
Class=4, n=76 (16.667%)
Class=5, n=76 (16.667%)

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

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

Например, мы могли бы увеличить выборку до 100 примеров в классах 0 и 1 и до 200 примеров в остальных классах. Этого можно добиться, создав словарь, который сопоставляет метки классов с количеством желаемых примеров в каждом классе, а затем указав это с помощью аргумента «sampling_strategy» класса SMOTE.

...
# transform the dataset
strategy = {0:100, 1:100, 2:200, 3:200, 4:200, 5:200}
oversample = SMOTE(sampling_strategy=strategy)
X, y = oversample.fit_resample(X, y)

Ниже приведен полный пример использования пользовательской стратегии передискретизации для SMOTE.

# example of oversampling a multi-class classification dataset with a custom strategy
from pandas import read_csv
from imblearn.over_sampling import SMOTE
from collections import Counter
from matplotlib import pyplot
from sklearn.preprocessing import LabelEncoder
# define the dataset location
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/glass.csv'
# load the csv file as a data frame
df = read_csv(url, header=None)
data = df.values
# split into input and output elements
X, y = data[:, :-1], data[:, -1]
# label encode the target variable
y = LabelEncoder().fit_transform(y)
# transform the dataset
strategy = {0:100, 1:100, 2:200, 3:200, 4:200, 5:200}
oversample = SMOTE(sampling_strategy=strategy)
X, y = oversample.fit_resample(X, y)
# summarize distribution
counter = Counter(y)
for k,v in counter.items():
	per = v / len(y) * 100
	print('Class=%d, n=%d (%.3f%%)' % (k, v, per))
# plot the distribution
pyplot.bar(counter.keys(), counter.values())
pyplot.show()

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

Class=0, n=100 (10.000%)
Class=1, n=100 (10.000%)
Class=2, n=200 (20.000%)
Class=3, n=200 (20.000%)
Class=4, n=200 (20.000%)
Class=5, n=200 (20.000%)

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

UserWarning: After over-sampling, the number of samples (200) in class 5 will be larger than the number of samples in the majority class (class #1 -> 76)

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

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

Вы можете увидеть пример правильного использования SMOTE в конвейере в этом уроке:

  • SMOTE для несбалансированной классификации с помощью Python

Экономичное обучение для многоклассовой классификации

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

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

Дополнительную информацию о экономичном обучении см. в руководстве:

  • Экономичное обучение для несбалансированной классификации

Класс RandomForestClassifier в scikit-learn поддерживает экономичное обучение с помощью аргумента «class_weight».

По умолчанию класс случайного леса присваивает каждому классу одинаковый вес.

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

Полный пример приведен ниже.

# baseline model and test harness for the glass identification dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import RandomForestClassifier

# load the dataset
def load_dataset(full_path):
	# load the dataset as a numpy array
	data = read_csv(full_path, header=None)
	# retrieve numpy array
	data = data.values
	# split into input and output elements
	X, y = data[:, :-1], data[:, -1]
	# label encode the target variable to have the classes 0 and 1
	y = LabelEncoder().fit_transform(y)
	return X, y

# evaluate a model
def evaluate_model(X, y, model):
	# define evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=3, random_state=1)
	# evaluate model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# define the location of the dataset
full_path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/glass.csv'
# load the dataset
X, y = load_dataset(full_path)
# define the reference model
model = RandomForestClassifier(n_estimators=1000)
# evaluate the model
scores = evaluate_model(X, y, model)
# summarize performance
print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))

При выполнении примера оценивается алгоритм случайного леса по умолчанию с 1000 деревьями в стеклянном наборе данных с использованием повторной стратифицированной k-кратной перекрестной проверки.

Точность классификации среднего и стандартного отклонения сообщается в конце прогона.

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

В этом случае мы видим, что модель по умолчанию достигла точности классификации около 79,6 процента.

Mean Accuracy: 0.796 (0.047)

Мы можем указать аргумент «class_weight» для значения «balanced», которое автоматически вычислит вес класса, который будет гарантировать, что каждый класс получит равный вес во время обучения модели. .

...
# define the model
model = RandomForestClassifier(n_estimators=1000, class_weight='balanced')

Полный пример приведен ниже.

# cost sensitive random forest with default class weights
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import RandomForestClassifier

# load the dataset
def load_dataset(full_path):
	# load the dataset as a numpy array
	data = read_csv(full_path, header=None)
	# retrieve numpy array
	data = data.values
	# split into input and output elements
	X, y = data[:, :-1], data[:, -1]
	# label encode the target variable
	y = LabelEncoder().fit_transform(y)
	return X, y

# evaluate a model
def evaluate_model(X, y, model):
	# define evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=3, random_state=1)
	# evaluate model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# define the location of the dataset
full_path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/glass.csv'
# load the dataset
X, y = load_dataset(full_path)
# define the model
model = RandomForestClassifier(n_estimators=1000, class_weight='balanced')
# evaluate the model
scores = evaluate_model(X, y, model)
# summarize performance
print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))

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

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

В этом случае мы видим, что модель по умолчанию достигла повышения точности классификации по сравнению с нечувствительной к затратам версией алгоритма: точность классификации составила 80,2 процента против 79,6 процента.

Mean Accuracy: 0.802 (0.044)

Аргумент «class_weight» принимает словарь меток классов, сопоставленных со значением веса класса.

Мы можем использовать это, чтобы указать собственный вес, например вес по умолчанию для классов 0 и 1.0, которые имеют много примеров, и двойной вес класса 2.0 для других классов.

...
# define the model
weights = {0:1.0, 1:1.0, 2:2.0, 3:2.0, 4:2.0, 5:2.0}
model = RandomForestClassifier(n_estimators=1000, class_weight=weights)

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

# cost sensitive random forest with custom class weightings
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import RandomForestClassifier

# load the dataset
def load_dataset(full_path):
	# load the dataset as a numpy array
	data = read_csv(full_path, header=None)
	# retrieve numpy array
	data = data.values
	# split into input and output elements
	X, y = data[:, :-1], data[:, -1]
	# label encode the target variable
	y = LabelEncoder().fit_transform(y)
	return X, y

# evaluate a model
def evaluate_model(X, y, model):
	# define evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=3, random_state=1)
	# evaluate model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# define the location of the dataset
full_path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/glass.csv'
# load the dataset
X, y = load_dataset(full_path)
# define the model
weights = {0:1.0, 1:1.0, 2:2.0, 3:2.0, 4:2.0, 5:2.0}
model = RandomForestClassifier(n_estimators=1000, class_weight=weights)
# evaluate the model
scores = evaluate_model(X, y, model)
# summarize performance
print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))

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

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

В этом случае мы видим, что мы достигли дальнейшего повышения точности примерно с 80,2 процента при сбалансированном взвешивании классов до 80,8 процента при более смещенном взвешивании классов.

Mean Accuracy: 0.808 (0.059)

Дальнейшее чтение

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

Похожие руководства

  • Несбалансированная мультиклассовая классификация с набором данных для идентификации стекла
  • SMOTE для несбалансированной классификации с помощью Python
  • Чувствительная к затратам логистическая регрессия для несбалансированной классификации
  • Экономичное обучение для несбалансированной классификации

API

  • imblearn.over_sampling.SMOTE API.
  • sklearn.ensemble.RandomForestClassifier API.

Краткое содержание

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

В частности, вы узнали:

  • О проблеме несбалансированного многоклассового предсказания стандарта идентификации стекла.
  • Как использовать передискретизацию SMOTE для несбалансированной многоклассовой классификации.
  • Как использовать экономичное обучение для несбалансированной многоклассовой классификации.

У вас есть вопросы?
Задавайте свои вопросы в комментариях ниже, и я постараюсь ответить.