Прогнозирование аномалий с помощью доверительных интервалов

Я читаю определения «аномалии» на всех соревнованиях и везде. В этом хаосе единственной истиной является вариативность этого определения, т.е. объяснение аномалии полностью связано с интересующей областью.

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

Именно этим мы и занимаемся в этом посте. Мы пытаемся спрогнозировать спрос на такси в Нью-Йорке в критический период времени. Мы формулируем простые и важные предположения о поведении человека, которые позволят нам найти простое решение для прогнозирования аномалий. Всю грязную работу выполняет LSTM лояльности, разработанный в Керасе, который одновременно прогнозирует и обнаруживает аномалии!

НАБОР ДАННЫХ

Набор данных для анализа я взял у сообщества Numenta. В частности, я выбрал набор данных о такси Нью-Йорка. Этот набор данных показывает спрос на такси в Нью-Йорке с 2014–07–01 по 2015–01–31 с наблюдением каждые полчаса.

В этот период присутствует 5 аномалий с точки зрения отклонения от нормального поведения. Они происходят соответственно во время нью-йоркского марафона, Дня Благодарения, Рождества, Нового года и метели.

Наша цель - заранее обнаружить эти аномальные наблюдения!

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

timeLags = np.arange(1,10*48*7)
autoCorr = [df.value.autocorr(lag=dt) for dt in timeLags]
plt.figure(figsize=(19,8))
plt.plot(1.0/(48*7)*timeLags, autoCorr)
plt.xlabel('time lag [weeks]')
plt.ylabel('correlation coeff', fontsize=12)

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

МОДЕЛЬ

Нам нужна стратегия для заблаговременного обнаружения выбросов. Для этого мы решили позаботиться о прогнозах спроса на такси. Мы хотим разработать модель, которая может прогнозировать спрос с учетом неопределенности. Один из способов сделать это - разработать квантильную регрессию. Мы ориентируемся на предсказания экстремальных значений: нижнего (10-й квантиль), верхнего (90-й квантиль) и классического 50-го квантиля. Вычисляя также 90-й и 10-й квантили, мы покрываем наиболее вероятные значения, которые может принять реальность. Ширина этого диапазона может быть очень глубокой; мы знаем, что он маленький, когда наша модель уверена в будущем, и он может быть огромным, когда наша модель не может увидеть важные изменения в интересующей нас области. Мы воспользовались этим поведением и позволили нашей модели кое-что сказать об обнаружении выбросов в области прогнозирования спроса на такси. Мы ожидаем получить крошечный интервал (диапазон квантилей 90–10), когда наша модель будет уверена в будущем, потому что в ней все находится под контролем; с другой стороны, мы ожидаем получить аномалию, когда интервал станет больше. Это возможно, потому что наша модель не обучена обрабатывать такой сценарий, который может привести к аномалии.

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

inputs = Input(shape=(X_train.shape[1], X_train.shape[2]))
lstm = Bidirectional(LSTM(64, return_sequences=True, dropout=0.5))(inputs, training = True)
lstm = Bidirectional(LSTM(16, return_sequences=False, dropout=0.5))(lstm, training = True)
dense = Dense(50)(lstm)
out10 = Dense(1)(dense)
out50 = Dense(1)(dense)
out90 = Dense(1)(dense)
model = Model(inputs, [out10,out50,out90])

Управлять квантильной регрессией в Keras очень просто (я черпал вдохновение из этого поста). Мы легко определяем пользовательскую функцию потерь квантиля, которая штрафует ошибки на основе квантиля и того, была ли ошибка положительной (фактическая ›прогнозируемая) или отрицательной (фактическая› прогнозируемая). Наша сеть имеет 3 выхода и 3 потери, по одному на каждый квантиль, который мы пытаемся предсказать.

def q_loss(q,y,f):
    e = (y-f)
    return K.mean(K.maximum(q*e, (q-1)*e), axis=-1)
losses = [lambda y,f: q_loss(0.1,y,f), lambda y,f: q_loss(0.5,y,f), lambda y,f: q_loss(0.9,y,f)]
model.compile(loss=losses, optimizer='adam', loss_weights = [0.3,0.3,0.3])

ПРОБЛЕМА КРОССОВЕРА

При работе с нейронной сетью в Keras одной из утомительных проблем является неопределенность результатов из-за инициализации внутренних весов. С его формулировкой наша проблема, кажется, особенно страдает от такого рода проблем; т.е. вычисляя квантильные прогнозы, мы не можем допустить перекрытия квантилей, это не имеет смысла! Чтобы избежать этой ловушки, я использую начальную загрузку на этапе прогнозирования: я повторно активирую отключение моей сети (trainable: true в модели), повторяю прогноз 100 раз, сохраняю их и, наконец, вычисляю желаемые квантили ( Эту хитрую технику я использую и в этом посте).

pred_10, pred_50, pred_90 = [], [], []
NN = K.function([model.layers[0].input, K.learning_phase()], 
                [model.layers[-3].output,
                 model.layers[-2].output,
                 model.layers[-1].output])
for i in tqdm.tqdm(range(0,100)):
    predd = NN([X_test, 0.5])
    pred_10.append(predd[0])
    pred_50.append(predd[1])
    pred_90.append(predd[2])

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

ПОЛУЧЕННЫЕ РЕЗУЛЬТАТЫ

Как я уже упоминал ранее, я использовал первые 5000 наблюдений для обучения, а оставшиеся (около 5000) для тестирования.

Наша модель достигает отличных результатов при прогнозировании спроса на такси с помощью 50-го квантиля. Среднеквадратическая ошибка журнала около 0,055 - отличный результат! Это означает, что сеть LSTM может понять основные правила, определяющие спрос на такси. Итак, наш подход к обнаружению аномалий звучит великолепно ... Мы вычислили разницу между прогнозами 90-го квантиля и прогноза 10-го квантиля и посмотрим, что произошло.

Диапазон квантильных интервалов (синие точки) выше в период неопределенности. В других случаях, как мы и ожидали, модель имеет тенденцию к хорошему обобщению. Идя глубже, мы начинаем исследовать эти периоды высокой неопределенности. Мы заметили, что они совпадают с нашими первоначальными предположениями. Оранжевые круги, изображенные ниже, представляют собой соответственно: марафон Нью-Йорка, День Благодарения, Рождество, Новый год и метель.

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

РЕЗЮМЕ

В этом посте я воспроизвожу хорошее решение для обнаружения и прогнозирования аномалий. Мы используем сеть LSTM, чтобы узнать о динамике спроса на такси в Нью-Йорке. Мы использовали то, что узнали, чтобы делать прогнозы и одновременно оценивать неопределенность. Мы неявно определяем аномалию как непредсказуемое наблюдение, то есть с большой степенью неопределенности. Это простое предположение позволяет нашему LSTM делать всю работу за нас.

ПРОВЕРИТЬ РЕПО НА GITHUB

Оставайтесь на связи: Linkedin