Обнаружение выбросов может быть выполнено с помощью пакета DBSCAN R, известный алгоритм, используемый для идентификации кластера (подробности см. на WIKIPEDIA).
Эта функция имеет три важных входа:
- x: ваши данные (только числовое значение)
- eps: целевое максимальное расстояние
- minPts: количество минимальных точек, чтобы рассматривать их как кластер
Оценить eps можно с помощью функций knndist(...) и knndistplot(...):
- knndistplot будет отображать значения eps в вашем наборе данных для заданного k (т.е. minPts) ==> вы можете визуально выбрать эффективное значение eps (обычно в части кривой колена)
- knndist оценит значения eps и вернет их в матрицу из. ввод k будет генерировать оценки 1: 1: k, и вы можете использовать результат для программного определения точных значений eps и k
Далее вам нужно просто использовать dbscan(yourdata, eps, k) для получения объекта dbscan со следующими компонентами:
- eps: количество eps, используемое для расчетов
- minPts: минимальное количество точек для идентификации кластера
- кластер: целочисленный вектор, определяющий точки, которые принадлежат кластеру (=1) или нет (=0). Последние соответствуют выбросам, которые вы хотите устранить.
Обратите внимание на следующие ограничения для dbscan:
- dbscan использует евклидово расстояние, поэтому он подвергается «Проклятию измерений». Этого можно избежать с помощью PCA.
- dbscan устраняет наложенные точки, которые могут создавать неопознанные точки. Это можно решить либо путем слияния результатов с вашими данными с помощью левого внешнего соединения, либо с помощью функции дрожания (...), которая добавляет шум к вашим данным. Согласно представленным вами данным, я думаю, что это может иметь место для ваших данных.
Зная об этих ограничениях, пакет dbscan предлагает два альтернативных метода: LOF и OPTICS (расширение DBSCAN).
Редактировать 25 января 2016 г.
Следуя ответу @rawr, я привожу пример, основанный на наборе данных mtcars
, чтобы показать, как использовать dbscan
для выявления выбросов. Обратите внимание, что мой пример будет использовать отличный пакет data.table
вместо классического data.frame
.
Во-первых, я начинаю копировать подход rawr для иллюстрации использования data.table.
require(data.table)
require(ggplot2)
require(dbscan)
data(mtcars)
dt_mtcars <- as.data.table(mtcars)
# based on rawr's approach
plot(wt~mpg, data=dt_mtcars)
lo <- loess.smooth(dt_mtcars[,mpg], dt_mtcars[,wt])
lines(lo$x,lo$y, lwd=3)
lines(lo$x,lo$y * 1.2, lwd=3 , col=2 )
lines(lo$x,lo$y / 1.2, lwd=3 , col=2 )
![введите здесь описание изображения](https://i.stack.imgur.com/IgITb.png)
Таким образом, мы можем оценить, что получаем одинаковые результаты независимо от базовой поддержки.
Во-вторых, следующий код иллюстрирует подход DBSCAN, который начинается с определения eps
и k
, необходимого количества точек для идентификации кластера:
res_knn = kNNdist( dt_mtcars[, .(wt, mpg)] , k = 10)
dim_knn = dim(res_knn)
x_knn = seq(1, dim_knn[1])
ggplot() +
geom_line( aes( x = x_knn , y = sort(res_knn[, 1]) , col = 1 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 2]) , col = 2 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 3]) , col = 3 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 4]) , col = 4 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 5]) , col = 5 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 6]) , col = 6 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 7]) , col = 7 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 8]) , col = 8 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 9]) , col = 9 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 10]) , col = 10 ) ) +
xlab('sorted results') +
ylab('kNN distance')
Результаты представлены на следующем графике:
![введите здесь описание изображения](https://i.stack.imgur.com/drPy8.png)
Он показывает, что рассчитанное расстояние kNN чувствительно к фактору k
, однако точное значение eps
для разделения выбросов находится в коленной части кривых ==> подходящее eps
расположено между 2 и 4. Это визуальная оценка, которая может быть автоматизированы с помощью соответствующих алгоритмов поиска (например, см. эту ссылку). Что касается k
, необходимо определить компромисс, зная, что чем ниже k, тем менее строгие результаты.
В следующей части мы параметризуем dbscan с помощью eps = 3
(на основе визуальной оценки) и k = 4
для получения слегка строгих результатов. Мы построим эти результаты с помощью кода rawr:
eps = 3
k = 4
res_dbscan = dbscan( dt_mtcars[, .(wt, mpg)] , eps , k )
plot(wt~mpg, data=dt_mtcars, col = res_dbscan$cluster)
lo <- loess.smooth(dt_mtcars[res_dbscan$cluster>0,mpg], dt_mtcars[res_dbscan$cluster>0,wt])
lines(lo$x,lo$y, lwd=3)
lines(lo$x,lo$y * 1.2, lwd=3 , col=2 )
lines(lo$x,lo$y / 1.2, lwd=3 , col=2 )
![введите здесь описание изображения](https://i.stack.imgur.com/d5dCK.png)
мы получили эту цифру, где мы можем оценить, что мы получили разные результаты из подхода rawr, где точки, расположенные в mpg = [10,13]
, считаются выбросами.
Эти результаты можно рассматривать как странные по сравнению с решением rawr, которое работает в предположении наличия двумерных данных (Y ~ X). Однако mtcars
представляет собой многомерный набор данных, в котором взаимосвязь между переменными может быть (или нет) линейной... Чтобы оценить эту точку, мы могли бы построить диаграмму рассеивания этого набора данных, отфильтрованную, например, по числовым значениям.
pairs(dt_mtcars[, .(mpg, disp, hp, drat, wt, qsec)])
![введите здесь описание изображения](https://i.stack.imgur.com/OTsjF.png)
Если мы сосредоточимся только на результате wt ~ mpg
, на первый взгляд мы можем подумать, что это антилинейная зависимость. Но с другими отношениями на графике это может быть не так, и поиск выбросов в среде N-Dim немного сложнее. Действительно, одна точка может рассматриваться как выброс при проецировании в конкретном 2D-сравнении... но наоборот, если мы добавим новое измерение сравнения. Действительно, у нас могла бы быть коллинеарность, которую можно было бы идентифицировать и, таким образом, усилить связь кластера или нет.
Друзья мои, я согласен, что это много if
и чтобы проиллюстрировать эту ситуацию, мы перейдем к dbscan
анализу числовых значений mtcars
.
Поэтому я повторю процесс, представленный ранее, и начнем с анализа расстояния kNN:
res_knn = kNNdist( dt_mtcars[, .(mpg, disp, hp, drat, wt, qsec)] , k = 10)
dim_knn = dim(res_knn)
x_knn = seq(1, dim_knn[1])
ggplot() +
geom_line( aes( x = x_knn , y = sort(res_knn[, 1]) , col = 1 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 2]) , col = 2 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 3]) , col = 3 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 4]) , col = 4 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 5]) , col = 5 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 6]) , col = 6 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 7]) , col = 7 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 8]) , col = 8 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 9]) , col = 9 ) ) +
geom_line( aes( x = x_knn , y = sort(res_knn[, 10]) , col = 10 ) ) +
xlab('sorted results') +
ylab('kNN distance')
![отсортированные расстояния kNN](https://i.stack.imgur.com/f8XCx.png)
По сравнению с анализом, проведенным на wt ~ mpg
, мы видим, что kNNdist(...)
дает гораздо более важное расстояние kNN (например, до 200 с k = 10
). Однако у нас все еще есть часть колена, которая помогает нам оценить подходящее значение eps
.
В следующей части мы будем использовать eps = 75
и k = 5
и
# optimal eps value is between 40 (k=1) and 130 (k=10)
eps = 75
k = 5
res_dbscan = dbscan( dt_mtcars[, .(mpg, disp, hp, drat, wt, qsec)] , eps , k )
pairs(dt_mtcars[, .(mpg, disp, hp, drat, wt, qsec)] , col = res_dbscan$cluster+2L)
![введите здесь описание изображения](https://i.stack.imgur.com/tHb3H.png)
Таким образом, диаграмма рассеяния этого анализа показывает, что выявление выбросов может быть затруднено в среде N-Dim из-за сложных взаимосвязей между переменными. Но обратите внимание, что в большинстве случаев выбросы расположены в угловой части 2D-проекции, что усиливает результаты, полученные с помощью wt ~ mpg
.
person
Bruno Sarrant
schedule
19.01.2016