Оглавление :

  • Введение.
  • Проблема бизнеса.
  • Формулировка машинного обучения и ограничения.
  • Обзор данных
  • Показатели эффективности.
  • Предварительная обработка данных.
  • Исследовательский анализ данных
  • Разработка функций
  • Различные стратегии кодирования.
  • Обучение различных моделей.
  • Сравнение моделей.
  • Интервалы предсказания.
  • Развертывание модели
  • Будущая работа.
  • Профили
  • Использованная литература.

1. Введение:

Services Now — компания-разработчик программного обеспечения, основной деятельностью которой было управление инцидентами, проблемами и изменениями операционных событий ИТ. Текущий набор данных состоит из инцидентов, зарегистрированных в ИТ-компании с помощью платформы ServiceNow.

2. Бизнес-проблема и ограничение

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

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

3. Формулировка ML и ограничения:

У нас есть время close_at и время open_at в качестве функций, если мы возьмем разницу между обеими функциями, мы получим время, необходимое для закрытия заявки в секундах, поскольку они являются непрерывными значениями, это можно представить как проблему регрессии. В наборе данных мы должны предсказать функции resolve_at и Closed_at, поэтому это можно рассматривать как проблему регрессии с несколькими выходами.

Ограничения:

. Нет требований к задержке

. Сведите к минимуму расхождение между фактическими и прогнозируемыми значениями

4. Обзор данных

Набор данных взят из Kaggle, мы указали две целевые переменные и 34 независимые переменные. Ссылка на набор данных

  • Есть 4 логических значения, 3 целых числа, 3 даты и времени, 1 идентификатор, 23 категориальных и 2 зависимых признака, имеется 119998 точек данных.
  • Каждый инцидент записывается с уникальным идентификатором, каждый идентификатор имеет несколько журналов или строк данных, описывающих каждый журнал с несколькими функциями.
  • Данные анонимизированы в целях конфиденциальности, т.е. точной информации в данных нет, исходные данные либо скрыты, либо удалены из логов
  • Некоторые из особенностей имеют ? символ, указывающий на то, что данные неизвестны или отсутствуют, 4 объекта имеют 99% отсутствующих данных, поскольку мы не можем получить от них какую-либо информацию, мы можем удалить их. В числовых функциях нет пропущенных значений.
  • Такие функции, как caller_id, open_by, sys_updated_by, имеют идентификаторы, соответствующие пользователю или вызывающему абоненту. Мы не можем брать их как числовые данные, нам нужно брать каждый ID как отдельную категорию.
  • Зависимые функции closed_at и resolve_at сильно коррелированы.

5. Показатели производительности

Здесь у нас есть проблема регрессии, и нам нужно минимизировать потери между фактическим и прогнозируемым временем, поэтому мы можем использовать такие метрики, как MAE, MSE, RMSE и т. д. Здесь мы хотели бы больше наказывать ошибки, чтобы мы могли использовать MSE в качестве метрики.

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

6. Предварительная обработка данных

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

Здесь мы ясно видим, что у фич Problem_id, rfc,vendor,caused_by,cmdb_ci нет даже 2-3% точек данных, мы никак не можем их заполнить, поэтому удаление этих фич — единственный вариант в наших руках.

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

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

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

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

7. Исследовательский анализ данных

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

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

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

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

Из этих графиков я понял следующие ключевые моменты:

  • Есть 10–15 верхних перцентильных категорий, которым требуется больше времени для решения заявки, остальные занимают сравнительно небольшое количество времени.
  • Заявки, о которых сообщают не менее 5 идентификаторов вызывающих абонентов, разрешаются и закрываются в течение МИНУТЫ.

Теперь с помощью блочных диаграмм давайте посмотрим, как распределены целевые переменные:

Мы видим, что в данных есть выбросы. Есть шансы, что есть особые случаи, когда на закрытие или разрешение ушло больше времени, мы можем сказать, что это скорее редкие моменты, чем выбросы. поэтому мы не можем удалить эти точки.

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

Из этого можно сказать, что функция sys_mod_count наиболее коррелирована, она примерно на 60% коррелирует с целевыми переменными. Но у нас есть много категориальных признаков в наборе данных, мы можем найти корреляцию между ними с помощью модуля под названием phik. Теперь давайте создадим тепловую карту для категорийных функций с помощью этого модуля phik.

  • Мы видим, что многие функции коррелированы, активное состояние и состояние инцидента коррелированы, мы можем взять состояние инцидента, поскольку оно больше коррелирует с целевыми переменными.
  • caller_id полностью коррелирует с функциями open_by, sys_created_by, sys_updated_by, location, category, subcategory, u_symptom, группа назначения,assign_to, resolve_by, мы можем сохранить caller_id и удалить остальные функции, так как они больше коррелируют с целевыми переменными.
  • contact_type и notify коррелируют друг с другом и совершенно не коррелируют с целевыми переменными, лучше убрать эти фичи
  • влияние и срочность полностью взаимосвязаны, мы можем убрать функцию срочности.

8. Разработка функций

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

Отсюда можно сказать, что билеты, открытые в часы пик, закрываются дольше, чем билеты, открытые в нерабочее время (не с 8 до 5).

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

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

Точно так же мы можем создать функции дня и часа из функции sys_updated_at и создать аналогичные графики, которые можно найти здесь.

Мы знаем, что день недели и час имеют циклический характер, т. е. для функции часа у нас есть диапазон значений 0–23, открытый тикет на 03.02.2019 23:12 ближе к 04.02.2019 0:15, если мы рассматриваем эти часы как есть, алгоритмы могут их неправильно интерпретировать, потому что обычно разница между 0 и 23 самая большая. Для этого мы можем исследовать тригонометрические функции, такие как синус и косинус.

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

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

df2[‘updation_time’]=(df2.sys_updated_at-df2.opened_at).apply(lambda x: x.total_seconds())

Теперь давайте проверим корреляцию между этой функцией и целевыми переменными.

Мы видим, что корреляция между ними составляет примерно 48%, что довольно хорошо.

Теперь давайте посмотрим на наше целевое распределение переменных.

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

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

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

9. Различные стратегии кодирования

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

9.1 Кодирование с верхними категориями:

Именно этот метод кодирования используется в решении победителей KDD Cup Orange Challenge. Здесь мы используем обычную горячую кодировку, рассматривая только верхние категориальные признаки.

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

9.2 Двоичное кодирование:

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

Чтобы обойти описанный выше подход, у нас есть техника, называемая бинарным кодированием, которая широко используется для больших количественных признаков. Категории сначала преобразуются в числовой порядок, начиная с 1 (порядок создается по мере того, как категории появляются в наборе данных и не имеют порядкового порядка). Затем эти целые числа преобразуются в двоичный код, например, 3 становится 011, 4 становится 100. Затем цифры двоичного числа образуют отдельные столбцы.

Мы можем использовать модуль category_encoders для достижения такого рода кодирования.

Здесь мы применяем двоичный кодировщик из category_encoders к данным поезда, подгоняем и преобразовываем его к данным поезда и преобразуем только к тестовым данным.

9.3 Кодировка метки:

В этой кодировке каждой категории присваивается значение от 1 до N (здесь N — количество категорий для признака. Такие методы используются с порядковыми признаками, где между категориями существует связь. У нас есть такие признаки, как воздействие, приоритет, категории которого являются низкими, средними, высокими.Они имеют отношение как высокий›средний›низкий, поэтому мы можем использовать это кодирование для этих категориальных функций.

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

10. Обучение различных моделей:

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

Mean Train error: 126156.029 23908.546 
Mean Test error:  126611.314 23906.956

Для расчета MSE сначала нам нужно преобразовать целевые значения обратно в их исходные значения, применив экспоненциальный член и добавив 1 к этому (expm1) для предсказанных и преобразованных целевых переменных. Мы получили около 126 тысяч минут обучения и тестирования MSE, теперь мы пытаемся построить модель, которая дает MSE меньше, чем это.

Как обсуждалось выше, мы можем использовать описанные выше методы кодирования. Перед этим мы можем применить регрессор CAT Boost, который может работать с категориальными функциями как есть.

Мы создали модель регрессора повышения Cat и использовали поиск по сетке cv для настройки гиперпараметров. Теперь вычислите MSE, преобразовав преобразованные значения в фактические значения и применив MSE к этим значениям.

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

mse_scores (сетка)

Mean Train error:  3572.996   3578.531
Mean Test error:   3625.170   3565.244

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

reg=joblib.load(‘linear.pkl’)
mse_scores(reg)

Mean Train error:   93611.414  5804.664
Mean Test error:    99611.324  6301.543

grid_dt=joblib.load(‘decision_tree.pkl’)
mse_scores(grid_dt)

Mean Train error:  3049.906   3013.571
Mean Test error:   3270.910   3302.372

grid_rf=joblib.load(‘random_forest.pkl’)
mse_scores(grid_rf)

Mean Train error:  2007.350   1785.292
Mean Test error:   2921.987   2896.865

В Random Forest у нас есть атрибут feature_importances, с помощью которого мы можем узнать, насколько важны функции для прогнозирования целевой переменной, теперь мы будем использовать этот атрибут и отображать важность функций.

Ух ты!!!! update_time — самая важная функция, которую мы создали в ходе разработки функций.

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

grid_xgb=joblib.load('xgb.pkl')
mse_scores(grid_xgb)

Mean Train error:  3059.083   3151.124
Mean Test error:   9884.571   3294.099

Мы закончили с базовыми моделями, теперь мы попробуем построить пользовательскую модель регрессора CV. Здесь мы будем использовать данные поезда и разделим их на две части D1 и D2.

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

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

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

Это серьезный ущерб!! эти оценки MSE выше, чем у случайной модели, что означает, что она работает хуже, чем случайная модель. Возможно, наши данные не могут работать с более сложными моделями или по какой-либо другой причине, мы не можем это определить, но пока давайте попытаем счастья с регрессором CV от sk-learn. Это похоже на нашу пользовательскую модель регрессора.

Здесь мы рассмотрели базовые модели, такие как гребень, дерево решений, случайный лес и KNN с гребнем в качестве метарегрессора, давайте посчитаем MSE для этой модели.

grid_ds=joblib.load(‘gird.pkl’)
mse_scores(grid_ds)

Mean Train error:  2637.669   2517.925
Mean Test error:   3591.510   3374.355

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

Mean Test error:  3522.687   3076.516

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

Я реализовал и другие стратегии кодирования, но результаты не такие хорошие, как можно найти здесь

11. Сравнение моделей

Random Forest имеет наименьшую оценку MSE около 2,9k, поэтому мы можем использовать эту модель в нашем развертывании.

12. Интервалы предсказания

Диапазон оценки всегда лучше, чем точечная оценка, когда речь идет о проблеме регрессии. Интервал прогнозирования отличается от доверительных интервалов. В доверительном интервале мы вычисляем среднее значение (обычно) для фиксированных точек данных, при этом интервалы прогнозирования мы вычисляем значения для будущих значений x, а также для одной точки данных.

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

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

Теперь, если мы предположим, что наши x, y и наши остатки следуют распределению Гаусса, тогда, если мы хотим рассчитать 95% интервал прогнозирования, нам нужно рассчитать стандартное отклонение остатков.

Resolved and closed prediction intervals in seconds: 49188.693 48970.000

Здесь z равно 1,96; z определяет, сколько стандартных отклонений от точки данных. Чтобы получить 95% площади под нормальным распределением, нам нужно иметь стандартное отклонение 1,96. Мы вычтем этот интервал из фактического прогноза для нижнего предела и добавим интервал, чтобы получить верхний предел.

13. Развертывание модели

Мы будем использовать экземпляр EC2 в Amazon с помощью Flask для развертывания модели. Для этого нам нужно создать 3 файла. Первый файл будет использоваться для получения входных данных, мы можем использовать обычную html-страницу для рендеринга.

Теперь нам нужно создать еще один файл, а именно app.py, который используется для чтения входных данных со страницы index.html, предварительной обработки данных и передачи чистых данных в модель для прогнозирования. Здесь мы можем использовать случайный лес в качестве нашей модели, так как это дало нам наименьшую оценку MSE. Я использовал объявления в flask для перехода к html-страницам и создания файла app.py, посмотрите.

Теперь нам нужно создать наш окончательный файл, который будет использоваться для прогнозов, данных app.py, здесь мы также можем использовать html-файл, чтобы сделать эту работу за нас.

Наконец мы закончили с предсказаниями. Другая задача состоит в том, чтобы развернуть это в экземпляре AWS. Сначала нам нужно создать экземпляр на Amazon AWS, мы можем выбрать бесплатный сервер Ubuntu уровня, который поставляется с 1 ГБ ОЗУ. После создания инстанса нам нужно подключиться к машине командой

ssh -i case_1.pem [email protected]

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

Теперь после подключения вам нужно скопировать папку на машину, это можно сделать командой ниже

scp -r -i «case_1.pem» развертывание ubuntu@ec2–3–134–88–139.us-east-2.compute.amazonaws.com:~/

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

nohup python3 app.py &

Эта команда обязательно запустит наш app.py, даже если мы закроем нашу локальную командную строку.

Приложение находится на расстоянии одного клика: http://ec2-3-134-88-139.us-east-2.compute.amazonaws.com:7898/

14. Будущая работа

  1. Мы рассмотрели пропущенные значения в категориальных функциях как отдельную категорию, но существуют и другие методы вменения, такие как вменение на основе режима или KNN, которые могут дать некоторое преимущество в производительности.
  2. Существует множество других методов кодирования, таких как частотное кодирование, среднее кодирование и т. д.
  3. В данных есть несколько функций даты и времени, поэтому мы можем попробовать использовать модели ARIMA или глубокого обучения, такие как LSTM.
  4. При расчете интервалов прогнозирования мы предположили, что данные следуют нормальному распределению, что неверно. Регрессоры на основе квантилей можно использовать для расчета более точных интервалов прогнозирования для любого типа распределений.

15. Ссылки













Вы можете найти мой полный код здесь и не стесняйтесь подключать меня в LinkedIn.