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

Рецепты, с которыми вы столкнетесь в этой главе, следующие:

  • Обнаружение выбросов с помощью KNN
  • Обнаружение выбросов с использованием LOF
  • Обнаружение выбросов с помощью iForest
  • Обнаружение выбросов с помощью Машины опорных векторов одного класса (OCSVM)
  • Обнаружение выбросов с помощью COPOD
  • Обнаружение выбросов с помощью PyCaret

Загрузите данные nyc_taxi.csv в кадр данных pandas и создайте функцию plot_outliers, которую вы будете использовать во всех рецептах.

Предыдущий код должен создать график временного ряда с маркерами x для известных выбросов:

PyOD — одна из таких библиотек для обнаружения выбросов в ваших данных. Он обеспечивает доступ к более чем 20 различным алгоритмам для обнаружения выбросов и совместим как с Python 2, так и с Python 3. Абсолютная жемчужина!

Обнаружение выбросов с помощью KNN

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

Как правило, алгоритмы, основанные на близости, полагаются на расстояние или близость между точкой выброса и ее ближайшими соседями. В KNN количество ближайших соседей, k, является параметром, который вам необходимо определить. Существуют и другие варианты алгоритма KNN, поддерживаемые PyOD, например, Average KNN (AvgKNN), который использует среднее расстояние до KNN для оценки, и Median KNN (MedKNN), который использует срединное расстояние для подсчета очков.

Начните с загрузки класса KNN:

from pyod.models.knn import KNN

Прежде чем идти дальше, вы должны быть знакомы с несколькими параметрами для управления поведением алгоритма. Первый параметр — загрязнение, является общим параметром для всех различных классов (алгоритмов) в PyOD. Например, значение загрязнения, равное 0,1, означает, что вы ожидаете, что 10 % данных будут выбросами. Значение по умолчанию: загрязнение=0,1. Значение загрязнения варьируется от 0 до 0,5 (или 50%).

Второй параметр, относящийся к KNN, — это метод, который по умолчанию имеет значение method=‘largest’. В этом рецепте вы измените его на среднее (среднее значение всех kрасстояний до соседей). Третий параметр, также относящийся к KNN, представляет собой метрику, которая сообщает алгоритму, как вычислять расстояния. По умолчанию используется расстояние Минковского, но оно может принимать любые показатели расстояния из библиотеки scikit-learn или SciPy. Наконец, вам нужно указать количество соседей, которое по умолчанию равно n_neighbors=5. В идеале вы захотите запустить разные модели KNN с различными значениями k и сравнить результаты, чтобы определить оптимальное количество соседей. Вам нужно будет поэкспериментировать с этими параметрами.

Создайте экземпляр KNN с обновленными параметрами, а затем обучите (подгоните) модель:

knn = KNN(contamination=0.03,method='mean',n_neighbors=5) knn.fit(tx)

Метод predict будет генерировать двоичные метки, либо 1, либо 0 для каждой точки данных. Значение 1 указывает на выброс. Сохраните результаты в серии pandas и отфильтруйте прогнозируемые серии, чтобы отображались только выбросы.

predicted = pd.Series(knn.predict(tx),index=tx.index) 
print('Number of outliers = ', predicted.sum())

В целом результаты выглядят многообещающе; четыре из пяти известных дат были идентифицированы. Кроме того, алгоритм определил день после Рождества, а также 26 января 2015 года, когда всем транспортным средствам было приказано убраться с улиц из-за снежной бури в Северной Америке.

Используйте функцию plot_outliers, созданную в разделе Технические требования, чтобы визуализировать выходные данные, чтобы лучше понять:

Неконтролируемый подход к алгоритму KNN вычисляет расстояние наблюдения до других соседних наблюдений. Расстоянием по умолчанию, используемым в PyOD для KNN, является расстояние Минковского (расстояние p-нормы). Вы можете использовать различные меры расстояния, такие как евклидово расстояние с евклидовым или l2 или манхэттенскоерасстояние с манхэттеном или l1.

Традиционно, когда люди слышат KNN, они сразу же предполагают, что это всего лишь алгоритм обучения с учителем. Для неконтролируемого KNN существует три популярных алгоритма: шаровое дерево, дерево KD и поиск методом грубой силы. Библиотека PyOD поддерживает все три типа ball_tree, kd_tree и brute соответственно. По умолчанию задано значение algorithm=‘auto’.

PyOD использует внутреннюю оценку, специфичную для каждого алгоритма, оценивая каждое наблюдение в тренировочном наборе. Атрибут decision_scores_ покажет эти баллы для каждого наблюдения. Более высокие баллы указывают на более высокий потенциал ненормального наблюдения, и вы можете преобразовать это в DataFrame:

knn_scores = knn.decision_scores_
knn_scores_df = (pd.DataFrame(scores,index=tx.index,
                                           columns='score'])) 
knn_scores_df

Поскольку все точки данных оцениваются, PyOD определит порог, чтобы ограничить количество возвращаемых выбросов. Пороговое значение зависит от значения загрязнения, которое вы указали ранее (доля выбросов, которые вы подозреваете). Чем выше значение загрязнения, тем ниже порог и, следовательно, возвращается больше выбросов. Чем ниже значение загрязнения, тем выше пороговое значение. Вы можете получить пороговое значение с помощью атрибута threshold_ из модели после его подгонки к обучающим данным. Вот порог для KNN, основанный на уровне загрязнения 3%:

knn.threshold_ 
>> 225.0179166666657

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

knn_scores_df[knn_scores_df['score'] >= knn.threshold_].sort_       
                                  values('score', ascending=False)

Обратите внимание, что последнее наблюдение 2014–09–27 немного превышает пороговое значение, но оно не было возвращено при использовании метода прогнозирования. Если вы используете порог загрязнения, вы можете получить лучшую отсечку:

n = int(len(tx)*0.03) 
knn_scores_df.nlargest(n, 'score')

Еще один полезный метод – predict_proba, который возвращает вероятность нормального состояния и вероятность отклонения от нормы для каждого наблюдения. PyOD предоставляет два метода определения этих процентов: линейный или унифицированный. Например, в случае linear реализация использует MinMaxScaler от scikit-learn для масштабирования оценок перед вычислением вероятностей. Метод unify использует z-показатель (стандартизация) и функцию ошибки Гаусса (erf) из библиотеки SciPy (scipy.special.erf). ).

knn_proba = knn.predict_proba(tx, method='linear') 
knn_proba_df = (pd.DataFrame(np.round(knn_proba * 100, 3),
                    index=tx.index,columns=['Proba_Normal', 
                                           'Proba_Anomaly'])) 
knn_proba_df.nlargest(n, 'Proba_Anomaly')

Для метода unify можно просто обновить method=‘unify’.

Обнаружение выбросов с использованием LOF

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

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

Легче проиллюстрировать это на примере: представьте себе человека, стоящего в очереди в маленьком, но оживленном Старбаксе, и все находятся довольно близко друг к другу; тогда мы можем сказать, что человек находится в районе с высокой плотностью населения и, более конкретно, с высокой локальной плотностью. Если человек решает подождать в своей машине на стоянке, пока очередь не ослабеет, он изолирован и находится в районе с низкой плотностью населения, поэтому считается исключением. С точки зрения людей, стоящих в очереди, которые, вероятно, не знают о человеке в машине, этот человек считается недоступным, даже если этот человек в машине может видеть всех людей, стоящих в очереди. Поэтому мы говорим, что человек в машине недоступен с их точки зрения. Поэтому мы иногда называем это обратной достижимостью (насколько далеко вы находитесь с точки зрения соседей, а не только с вашей).

Как и в KNN, вам все равно нужно определить параметр k для количества ближайших соседей. Ближайшие соседи определяются на основе расстояния, измеренного между наблюдениями (например, KNN), а затем плотности локальной достижимости (LRDили локальной плотности для краткости ) измеряется для каждой соседней точки. Эта локальная плотность является оценкой, используемой для сравнения k-х соседних наблюдений, и те, у которых локальная плотность ниже, чем у их k-х соседей, считаются выбросами (они находятся дальше от досягаемости своих соседей).

Начните с загрузки класса LOF:

from pyod.models.lof import LOF

Создайте экземпляр LOF, обновив n_neighbors=5 и contamination=0,03, сохранив для остальных параметров значения по умолчанию. Затем обучите (подойдите) модель:

lof = LOF(contamination=0.03, n_neighbors=5) 
lof.fit(tx)

Метод predict выводит либо 1, либо 0 для каждой точки данных. Значение 1 указывает на выброс. Сохраните результаты в серии pandas и отфильтруйте прогнозируемую серию, чтобы отображались только выбросы:

predicted = pd.Series(lof.predict(tx),index=tx.index) 
print('Number of outliers = ', predicted.sum())
outliers = predicted[predicted == 1] 
outliers = tx.loc[outliers.index] 
outliers

Интересно, что он зафиксировал три из пяти известных дат, но сумел определить день после Дня Благодарения и день после Рождества как выбросы. Кроме того, 31 октября выпало на пятницу, а это была ночь Хэллоуина.

LOF похож на KNN в том смысле, что мы измеряем расстояния между соседями перед вычислением локальной плотности. Локальная плотность является основой оценок решений, которые можно просмотреть с помощью атрибута decision_scores_:

timestamp   score 
2014-11-01  14.254309 
2015-01-27  5.270860 
2015-01-26  3.988552
2014-12-25  3.952827 
2014-12-26  2.295987 
2014-10-31  2.158571

Оценки сильно отличаются от KNN

Как и в случае с LOF, другим расширением алгоритма является Фактор локального выброса на основе кластера (CBLOF). CBLOF похож на LOF по концепции, поскольку он опирается на размер кластера и расстояние при расчете баллов для определения выбросов. Таким образом, вместо количества соседей (n_neighbors, как в LOF) теперь у нас есть новый параметр — количество кластеров (n_clusters). Оценщик кластеризации по умолчанию, clustering_estimator, в PyOD представляет собой алгоритм кластеризации k-средних.

from pyod.models.cblof import CBLOF 
cblof = CBLOF(n_clusters=4, contamination=0.03) 
cblof.fit(tx) 
predicted = pd.Series(lof.predict(tx),index=tx.index) 
outliers = predicted[predicted == 1] 
outliers = tx.loc[outliers.index] 
plot_outliers(outliers, tx, 'CBLOF')

Сравните рисунок выше с рисунком (LOF) и обратите внимание на сходство.

Обнаружение выбросов с помощью iForest

iForest имеет сходство с другим популярным алгоритмом, известным как Random Forests. iForest, также являющийся методом ансамблевого обучения, представляет собой неконтролируемый подход к обучению случайных лесов. Алгоритм iForest изолирует аномалии путем случайного разделения набора данных на несколько разделов. Это выполняется рекурсивно до тех пор, пока все точки данных не будут принадлежать разделу. Количество разделов, необходимых для изоляции аномалии, обычно меньше, чем количество разделов, необходимых для изоляции обычной точки. Идея состоит в том, что точка данных аномалии находится дальше от других точек и, следовательно, ее легче отделить (изолировать).

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

Начните с загрузки класса IForest:

from pyod.models.iforest import IForest

Создайте экземпляр IForest и обновите параметры загрязнения и random_state. Затем поместите новый экземпляр класса (iforest) в данные с повторной выборкой, чтобы обучить модель:

iforest = IForest(contamination=0.03,n_estimators=100,
                                             random_state=0) 
iforest.fit(nyc_daily)
predicted = pd.Series(iforest.predict(tx),index=tx.index)
print('Number of outliers = ', predicted.sum())
>> Number of outliers =  7 
outliers = predicted[predicted == 1] 
outliers = tx.loc[outliers.index] 
outliers
>>  timestamp   value 
    2014-11-01  20553.500000 
    2014-11-08  18857.333333 
    2014-11-27  10899.666667 
    2014-12-25  7902.125000 
    2014-12-26  10397.958333 
    2015-01-26  7818.979167 
    2015-01-27  4834.541667

Обнаружение выбросов с помощью машины опорных векторов одного класса (OCSVM)

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

Начните с загрузки класса OCSVM:

from pyod.models.ocsvm import OCSVM
ocsvm = OCSVM(contamination=0.03, kernel='rbf') 
ocsvm.fit(tx)
predicted = pd.Series(ocsvm.predict(tx),index=tx.index)
print('Number of outliers = ', predicted.sum())
>>  Number of outliers =  5
outliers = predicted[predicted == 1] 
outliers = tx.loc[outliers.index] 
outliers 
>>  timestamp   value 
    2014-08-09  15499.708333
    2014-11-18  15499.437500 
    2014-11-27  10899.666667 
    2014-12-24  12502.000000 
    2015-01-05  12502.750000

При изучении графика неясно, почему OCSVM выделил эти даты как выбросы. Ядро RBF может фиксировать нелинейные отношения, поэтому вы ожидаете, что оно будет надежным ядром. Причина такой неточности в том, что SVM чувствительна к масштабированию данных. Чтобы получить лучшие результаты, вам необходимо сначала стандартизировать (масштабировать) ваши данные.

from pyod.utils.utility import standardizer 
scaled = standardizer(tx) 
predicted = pd.Series(ocsvm.fit_predict(scaled),index=tx.index)
outliers = predicted[predicted == 1] 
outliers = tx.loc[outliers.index] 
outliers 
>>  timestamp   value 
    2014-07-06  11464.270833 
    2014-11-01  20553.500000 
    2014-11-27  10899.666667 
    2014-12-25  7902.125000 
    2014-12-26  10397.958333 
    2015-01-26  7818.979167 
    2015-01-27  4834.541667

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

Вы можете изучить, как разные ядра 'linear', 'poly', 'rbf' и 'sigmoid ' выполнять на том же наборе данных

Обнаружение выбросов с использованием обнаружения выбросов на основе связки (COPOD)

COPOD — захватывающий алгоритм, основанный на статье, опубликованной в сентябре 2020 года, которую вы можете прочитать здесь

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

COPOD подпадает под вероятностные модели и основан на статистических методах, что делает ее быстрой и легко интерпретируемой моделью. Алгоритм основан на копуле, функции, обычно используемой для моделирования зависимости между независимыми случайными величинами, которые не обязательно имеют нормальное распределение. В прогнозировании временных рядов копулы использовались в одномерном и многомерном прогнозировании, которое популярно в моделировании финансовых рисков. Термин «связка» происходит от функции связки, соединяющей (соединяющей) одномерные маргинальные распределения с образованием однородной многомерной функции распределения.

Начните с загрузки класса COPOD:

from pyod.models.copod import COPOD
copod = COPOD(contamination=0.03) 
copod.fit(tx)
predicted = pd.Series(copod.predict(tx),index=tx.index) 
print('Number of outliers = ', predicted.sum()) 
>>  Number of outliers =  7
outliers = predicted[predicted == 1] 
outliers = tx.loc[outliers.index] 
outliers 
>>  timestamp   value 
    2014-07-04  11511.770833 
    2014-07-06  11464.270833 
    2014-11-27  10899.666667 
    2014-12-25  7902.125000 
    2014-12-26  10397.958333 
    2015-01-26  7818.979167 
    2015-01-27  4834.541667

Чтобы получить дополнительные сведения о decision_scores_, threshold_ или predict_proba, ознакомьтесь с первым рецептом Обнаружение выбросов с помощьюKNN. код здесь

Обнаружение выбросов с помощью PyCaret

В этом рецепте вы изучите PyCaret для обнаружения выбросов. PyCaret позиционируется как библиотека машинного обучения с открытым исходным кодом на Python, которая автоматизирует рабочие процессы машинного обучения. Он действует как оболочка для PyOD, которую вы использовали ранее в предыдущих рецептах для обнаружения выбросов. Что делает PyCaret, так это упрощает весь процесс быстрого прототипирования и тестирования с минимальным объемом кода. Вы будете использовать PyCaret для проверки нескольких алгоритмов обнаружения выбросов, подобных тем, которые вы использовали в предыдущих рецептах, и увидите, как PyCaret упрощает этот процесс.

Начните с загрузки всех доступных функций из модуля pycaret.anomaly:

from pycaret.anomaly import * 
setup = setup(tx, session_id = 1, normalize=True)

Чтобы распечатать список доступных алгоритмов обнаружения выбросов, вы можете запустить models():

models()

Обратите внимание, что все они взяты из библиотеки PyOD. Как было сказано ранее, PyCaret — это надстройка над PyOD и другими библиотеками, такими как scikit-learn.

Давайте сохраним имена первых восьми алгоритмов в списке, чтобы использовать его позже:

list_of_models = models().index.tolist()[0:8]
list_of_models 
>> 
     ['abod', 'cluster', 'cof', 'iforest', 'histogram', 'knn', 'lof', 'svm']

Прокрутите список алгоритмов и сохраните вывод в словаре, чтобы вы могли ссылаться на него позже для своего анализа. Чтобы создать модель в PyCaret, вы просто используете функцию create_model(). Это похоже на функцию fit() в scikit-learn и PyOD для обучения модели. После создания модели вы можете использовать ее для прогнозирования (идентификации) выбросов с помощью функции Predict_Model(). PyCaret создаст DataFrame с тремя столбцами: столбец исходного значения, новый столбец, Аномалия, в котором результат будет сохранен как 0 или 1. , где 1 указывает на выброс, и еще один новый столбец, Anomaly_Score, в котором хранится использованная оценка (чем выше оценка, тем выше вероятность того, что это аномалия).

Вы только измените параметр загрязнения, чтобы он соответствовал более ранним рецептам, использующим PyOD. В PyCaret параметр загрязнения называется fraction, и, чтобы быть последовательным, вы установите его на 0,03 или 3% с fraction=0,03:

results = {} 
for model in list_of_models:     
    cols = ['value', 'Anomaly_Score']     
    outlier_model = create_model(model, fraction=0.03) 
    print(outlier_model)     
    outliers = predict_model(outlier_model, data=tx)     
    outliers = outliers[outliers['Anomaly'] == 1][cols]  
    outliers.sort_values('Anomaly_Score', ascending=False, 
                                                inplace=True)     
    results[model] = {'data': outliers, 'model': outlier_ model}

Словарь results содержит выходные данные (DataFrame) каждой модели.

PyCaret — отличная библиотека для автоматизированного машинного обучения, и в последнее время они расширяют свои возможности в области анализа и прогнозирования временных рядов, а также обнаружения аномалий (выбросов). PyCaret — это оболочка над PyOD, той же библиотекой, которую вы использовали в предыдущих рецептах этой статьи. код здесь