Есть ли способ выполнить гиперпараметрическую оптимизацию поиска по сетке на One-Class SVM

Есть ли способ использовать GridSearchCV или любую другую встроенную функцию sklearn, чтобы найти лучшие гиперпараметры для классификатора OneClassSVM?

Что я сейчас делаю, так это сам выполняю поиск, используя разделение поезд / тест следующим образом:

Гамма и числовые значения определяются как:

gammas = np.logspace(-9, 3, 13)
nus = np.linspace(0.01, 0.99, 99)

Функция, которая исследует все возможные гиперпараметры и находит лучшие из них:

clf = OneClassSVM()

results = []

train_x = vectorizer.fit_transform(train_contents)
test_x = vectorizer.transform(test_contents)

for gamma in gammas:
    for nu in nus:
        clf.set_params(gamma=gamma, nu=nu)

        clf.fit(train_x)

        y_pred = clf.predict(test_x)

        if 1. in y_pred:  # Check if at least 1 review is predicted to be in the class
            results.append(((gamma, nu), (accuracy_score(y_true, y_pred),
                                              precision_score(y_true, y_pred),
                                              recall_score(y_true, y_pred),
                                              f1_score(y_true, y_pred),
                                              roc_auc_score(y_true, y_pred),
                                              ))
                               )

    # Determine and print the best parameter settings and their performance
    print_best_parameters(results, best_parameters(results))

Результаты хранятся в списке кортежей формы:

((гамма, числовое значение) (оценка_точности, оценка_точности, оценка_повтора, оценка_f1, оценка_рок_точности))

Чтобы найти лучшую точность, оценки и параметры f1, roc_auc, я написал свою собственную функцию:

best_parameters (результаты)


person Yustx    schedule 22.06.2017    source источник
comment
Вы пробовали это с GridSearchCV? У вас есть ошибки?   -  person Vivek Kumar    schedule 22.06.2017
comment
Как мне это сделать, не применяя перекрестную проверку, потому что SVM одного класса нужно подогнать только под данные, принадлежащие тому классу, над которым работает классификатор. Что я делаю: обучаю 80% экземпляров, которые принадлежат классу, затем я объединяю остальные 20% с экземплярами, которые не принадлежат классу, и использую их для тестирования.   -  person Yustx    schedule 22.06.2017
comment
Как вы разделяете данные на обучающие и тестовые?   -  person Vivek Kumar    schedule 22.06.2017
comment
@Yustx, не могли бы вы рассказать, как вы решили эту проблему с помощью OC-SVM. Я борюсь с той же проблемой, и я не уверен, как мне совместить ваш вопрос с ответом, чтобы заставить его работать.   -  person duichwer    schedule 19.12.2018


Ответы (2)


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

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

Вы можете использовать sklearn.model_selection.KFold, чтобы разделить

from sklearn.model_selection import KFold

Предположим, что Xpos - это массив данных nXp numpy для положительного класса для OneClassSVM, а Xneg - массив данных mXp для известных аномальных примеров.

Сначала вы можете сгенерировать разбиения для Xpos, используя

splits = KFold(n_splits=5).split(Xpos)

Это создаст генератор кортежей формы (train, test), где train - это массив чисел типа int, содержащий индексы для примеров в обучающей свертке, а test - массив чисел, содержащий индексы для примеров в свертке теста.

Затем вы можете объединить Xpos и Xneg в один набор данных, используя

X = np.concatenate([Xpos, Xneg], axis=0)

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

y = np.concatenate([np.repeat(1.0, len(Xpos)), np.repeat(-1.0, len(Xneg))])

Затем мы можем создать новый генератор (train, test) разбиений с индексами для аномальных примеров, включенных в тестовые свертки.

n, m = len(Xpos), len(Xneg)

splits = ((train, np.concatenate([test, np.arange(n, n + m)], axis=0)
          for train, test in splits)

Затем вы можете передать эти разбиения в GridSearchCV, используя данные X, y и любой метод подсчета очков и другие параметры, которые вам нужны.

grid_search = GridSearchCV(estimator, param_grid, cv=splits, scoring=...)

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

Он также гибок в выборе метода подсчета очков. Вы можете использовать несколько методов оценки, передав строки сопоставления словаря в вызываемые объекты оценки и даже определить пользовательские вызываемые объекты оценки. Это описано в документации Scikit-learn здесь. Индивидуальный метод выбора лучших параметров, вероятно, может быть реализован с помощью специальной функции оценки. Все метрики, используемые OP, могут быть включены с использованием словарного подхода, описанного в документации.

Вы можете найти реальный пример здесь . Я сделаю заметку, чтобы изменить ссылку, когда она будет объединена с мастером.

person Albert Steppi    schedule 18.10.2019
comment
@ asj3 Есть ли в строке splits = ((train, np.concatenate ([test, np.arange (n, n + m), axis = 0) для train, test in splits) синтаксическую ошибку? - person tisch; 04.03.2020
comment
@tisch Хороший улов. Отсутствовал кронштейн. Исправлено сейчас - person Albert Steppi; 04.03.2020
comment
@ asj3 Я также не думаю, что вы можете передать X и y в GridSearchCV. Позже передается в grid_Search.fit (X, y) - person tisch; 05.03.2020

Да, есть способ поиска по гиперпараметрам без перекрестной проверки входных данных. Этот метод называется ParameterGrid() и хранится в sklearn.model_selection. Вот ссылка на официальную документацию:

http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.ParameterGrid.html

Ваш случай может выглядеть следующим образом:

grid = {'gamma' : np.logspace(-9, 3, 13),
        'nu' : np.linspace(0.01, 0.99, 99)}

Чтобы подтвердить все возможные шаги с помощью сетки, вы можете ввести list(ParameterGrid(grid)). Мы также можем проверить его длину с помощью len(list(ParameterGrid(grid))), что в сумме дает 1287 и, следовательно, 1287 моделей, которые подходят для данных поезда.

Чтобы использовать метод, вам обязательно понадобится цикл for. Подразумевая, что у вас есть переменная clf, поскольку вы импортировали одноклассную SVM из sklearn.svm, цикл будет выглядеть примерно так:

for z in ParameterGrid(grid):
    clf.set_params(**z)
    clf.fit(X_train, y_train)
    clf.predict(X_test)
    ...

Надеюсь, этого достаточно. Не забывайте, что имена в сетке должны быть согласованы с параметром одноклассной SVM. Чтобы получить имена этих параметров, вы можете набрать clf.get_params().keys(), и там вы увидите «гамма» и «ню».

person E.Z.    schedule 23.06.2017
comment
Это хорошее решение. Но опять же, OP должен поддерживать всю информацию об оценках, подгонках, параметрах и т. Д. GridSearchCV сделает это автоматически. А поскольку пользователь разделяет данные на обучающие и тестовые, мы можем использовать настраиваемый итератор cv, который соответственно разделит данные. - person Vivek Kumar; 23.06.2017
comment
Меня это тоже немного сбивает с толку. Я бы поступил так же, как вы указали. Однако я не уверен, занимает ли этот цикл больше времени, чем базовый GridSearchCV, или они почти равны. - person E.Z.; 23.06.2017
comment
Я не могу сказать наверняка об этом цикле for, но GridSearchCV будет распараллеливать внутреннюю подгонку различных параметров, так что, возможно, это будет иметь немного более высокую производительность, чем этот / - person Vivek Kumar; 23.06.2017
comment
О, да. Наверняка было бы быстрее. - person E.Z.; 23.06.2017
comment
Сокращает вложенность на один отступ. Производительность вроде примерно такая же. Однако это не очень полезно, поскольку мне все еще приходится использовать свою собственную реализацию для поиска лучших гиперпараметров. - person Yustx; 27.06.2017