Система мониторинга активности сотрудников ИТ-компаний
Отчет по
преддипломной практике на тему:
«Разработка
автоматизированной системы мониторинга активности сотрудников в ИТ компаниях»
Хурамшин Бахтияр
Илнурович ИИСМ-1-23
Казань 2025
Оглавление. 2
Введение. 3
Проектная часть «Система оценки активности пользователя ПК». 11
Выбор и обоснование методов и инструментальных средств
управления IT-проектами. 11
Техническое задание на реализацию IT-проекта в соответствии
с требованиями стандартов и регламентов разработки программного обеспечения. 12
Аннотация к техническому заданию.. 12
Введение в техническое задание. 12
2 Основания для разработки. 13
3 Назначение разработки. 13
4 Требования к «Разработка автоматизированной системы
мониторинга активности сотрудников в ИТ компаниях». 13
5 Требования к программной документации. 14
6 Технико-экономические показатели. 15
7 Стадии и этапы разработки. 15
8 Порядок контроля и приемки. 16
9 Примечания. 16
Разработка алгоритма для решения задач по теме исследования. 17
Представление системы.. 65
Бизнес-процессы.. 70
Заключение. 72
Списокиспользуемойлитературы.. 73
Тема работы
является актуальной по причинам, описанным далее. Работа является актуальным в
соответствии с задачами распоряжения о стратегическом направлении в области
цифровой трансформации здравоохранения [13]. Сбор, анализ и оценка данных об активности
пользователей ИТ-работников крайне важны для понимания производительности и
цифрового благополучия на современном рабочем месте в силу влияния
технологического стресса. Технологический стресс оказывается в случае когда
сотрудники нагружены излишним объемом информации и задач, которые им необходимо
решать с помощью технологий, в частности информационных[9]. Технологический стресс оказывает следующие
эффекты: эмоциональное истощение и выгорание, вызов конфликтов между работой и
членами семьей [9, 20, 22]. Стратегиями преодоления такого вида
стресса являются ограничение проводимого времени с источником стресса,
организация расписания доступа к источнику стресса, распределение часов доступа
к источнику стресса на более длинные отрезки времени, например на выходные[14, 18, 37]. Разработанная автоматизированная система
мониторинга активности сотрудников в ИТ компаниях позволит в дальнейшем
справляться с технологическим стрессом, влиять на состояние сотрудника.
Степень
разработанности темыразработки автоматизированной системы мониторинга
активности людей достаточно глубокая чтобы утверждать, что есть некоторая
теоретическая база, от которой можно отталкиваться в исследованиях, однако
недостаточна чтобы утверждать, что тема представлена во всех перспективах и
раскрыта во всех деталях. Например, не представлено множество работ,
исследующих особенности различных социальных групп, их особенности в контексте
обозначенной автоматизированной системы, с применением различных комбинаций
подходов к сбору, анализу и оценке данных.
Цель –
разработать автоматизированную информационную систему мониторинга активности
сотрудников в ИТ компаниях.
Задачи:
Изучить научный
дискурс по теме разработки автоматизированной системы мониторинга активности
людей.
Спроектировать
автоматизированную систему мониторинга активности сотрудников в ИТ компаниях.
Реализовать
программный код автоматизированной системы мониторинга активности сотрудников в
ИТ компаниях.
Объект темы
–мониторинга активности людей.
Предмет темы -
автоматизированная информационная система мониторинга активности сотрудников в
ИТ компаниях.
Избранные методы
исследования: анализ, синтез, сравнение, индукция, дедукция, абстрагирование, формализация,
измерение.
Теоретическая
основарасполагается на научной литературе, представленной в виде книг, статей,
патентах.
Нормативная
основа располагается на нормах этики сообществ информационных технологий,
законах об персональных данных, авторском праве, информационной безопасности в
рамках текущей юрисдикции[38–42].
Эмпирическая
основа располагается на измерении результатов работы разработанной
автоматизированной системы.
Научная новизна
заключается в специализации автоматизированной системы на целевой аудитории
представленной в виде сотрудников ИТ компаний и в применении новой композиции
средств сбора, анализа и оценки данных.
Прикладная
ценность заключается в том, что данная автоматизированная система предполагает
свое применение в последующей регуляции уровня цифрового благополучия
сотрудника и, в частности, эффективности.
Анализ
современных методов и средств информатики для решения прикладных задач
различных классов по теме исследования
На действия сотрудников влияют окружающая среда и
действующие системы. Рассмотрим, как системамониторинга
влияет на тех, за кем происходит мониторинг и на тех, кто получает результаты
мониторинга. Наличие систем мониторинга может удержать сотрудников от
непродуктивного или неэтичного поведения [10]. Однако контроль сотрудника
компании, пользователя компьютера, через супервизора вызывает снижение вовлеченности,
но не усталость от работы [12]. Поэтому следует применять
информационную систему оценки активности пользователя в контексте высокой
вовлеченности и низкой усталости от работы чтобы избежать выгорания. Мониторинг
улучшает выполнение задач, обеспечивая обратную связь в реальном времени и
соблюдение рабочих процессов [7]. Аналогичным образом, программное
обеспечение для мониторинга производительности может помочь организациям
ставить четкие цели и отслеживать прогресс, способствуя формированию культуры,
ориентированной на производительность [31]. Но несмотря на формирование
культуры, ориентированной на производительность, электронный мониторинг может
препятствовать социальному обмену между лидерами и членами общества, что
приводит к снижению доверия и сотрудничества, а сотрудничество является
фактором эффективности компании[43].Чтобы избежать разобщенности
и других негативных эффектов организации приводят системы мониторинга в
соответствие со своей культурой и решают проблемы конфиденциальности в
частности путем проведения ликбеза о работе системы мониторинга, таким образом
они большей вероятностью добиваются положительных результатов [2, 27]. Таким образом мониторинг
оказывает эффекты отчуждения труда, формализации отношений между исполнителями
и управляющими в компании. В случае применения мониторинга активности
сотрудников стоит взвешивать все потенциальные выгоды и потенциальный ущерб. Перечисленные
негативные эффекты нивелируются при индивидуальном применении системы так как
при личном применении систем мониторинга пользователи обычно лучше контролируют
ситуацию, что позволяет им адаптировать инструменты к своим потребностям. Эта
автономия может повысить их мотивацию и сосредоточенность [10, 34]. Мониторинг при личном
использовании помогает выявлять привычки тратить время впустую, оптимизировать
рабочие процессы [5, 19].
Рассмотрим особенности сотрудников ИТ компаний от
сообществ людей других работ. Труд в секторе информационных технологий носит
специализированный характер и отличается от других видов интеллектуального
труда. Эти работники, в том числе разработчики программного обеспечения,
инженеры по поддержке, системные администраторы и управляющие базами данных,
работают в динамичных, зачастую кризисных средах, требующих быстрого решения
проблем и многозадачности. Сотрудники сферы информационных технологий сталкиваются
с уникальными проблемами из-за реактивного и разнообразного характера
выполняемых ими задач. Их работа часто прерывается, поэтому им приходится
одновременно управлять несколькими проектами. Эти перерывы приводят к
невыполненным работам, которые работники возобновляют, когда у них появляется
необходимое время, силы. Сложность их работы еще больше усугубляется
необходимостью детальной организации работы и умения эффективно переключаться
между задачами.[26, 44]. Еще одним важным аспектом их
работы является то, как работники сферы информационных технологий
систематизируют информацию на своих компьютерах и получают к ней повторный
доступ. Исследования показали, что иерархическая система папок, хотя и широко
используется, имеет ограничения в организации и извлечении информации. Многие
ИТ-работники предпочитают просматривать папки для повторного доступа к
информации, используя поиск в крайнем случае[1]. Сотрудники сферы
информационных технологий обладают большими умениями связанными с компьютером,
однако улучшение умений в сфере цифровых технологий все еще позволяет
продолжать повышать эффективность труда [15]. Таким образом особенностями
сотрудников сферы информационных технологий является повышенный технологический
стресс, частое переключение внимания, систематизация файлов в компьютере.
Предполагается, что разрабатываемая информационная система мониторинга будет
уменьшать технологический стресс, избегать излишнего переключения между
задачами.
Рассмотрим современныеподходы в рамках информационных
систем мониторинга активности людей. Проведем анализ перечисленных далее систем,
сравним их детали и соберем новую композицию элементов в единую информационную
автоматизированную систему мониторинга активности.
Данные можно собирать из носимых устройств в виде
физиологических данных. Носимые устройства, такие как умные часы и
фитнес-трекеры, предоставляют физиологические данные, включая частоту сердечных
сокращений, качество сна и уровень стресса, которые могут быть связаны с
качеством жизни, связанной с работой (WRQoL). Эти устройства обеспечивают
неинвазивный способ мониторинга благополучия сотрудников, но могут вызвать
проблемы с конфиденциальностью [8, 32]. Такие системы, в частности,
измеряют уровень стресса, усталости, чтобы вовремя применять определённые
действия, нацеленные на повышение эффективности сотрудника путем улучшения его
физического, психического благополучия [13].
Данные также можно собирать из компьютера, которым
пользуется сотрудник. Данные о цифровом взаимодействии, такие как активность
клавиатуры и мыши, использование электронной почты и взаимодействие с
приложениями, обычно собираются для оценки производительности и вовлеченности.
Для этой цели широко используются такие инструменты, как ActiveTrack, Time
Doctor и HubStaff. Перечисленные инструменты собирают данные и делают свои
оценки на основе статистики без применения машинного обучения[6].В дополнение к данным с
устройств ввода некоторые также собирают данные сетевого трафика [45]. В дополнение к измерению
активного времени пользования устройствами ввода, собирали данные о количестве
написанных слов, количестве опечаток в словах, количестве прокручиваний
колесика мыши в разных контекстах и пр. [46].
Также можно получать данные из таких источников как
видеокамеры и микрофоны. Примером применения являются технологии компьютерного
зрения, такие как YoloV8, используются для мониторинга присутствия и активности
сотрудников на рабочих местах, например, офисы, личные рабочие пространства при
удаленном формате работы. Эти системы могут автоматически отслеживать
присутствие сотрудника на рабочем месте [11]. Также можно определять не
только само присутствие на рабочем месте, но и другие данные, например,
эмоциональное состояние по мимике, тону голоса, содержанию речи [25]. Сбор данных из таково
источника данных,в формате не личного применения системы мониторинга, является ярко
отторгаемым для наблюдаемых, так как нарушается личное пространство.
Также можно получать данные из датчиков, встроенных в
рабочее место. Трибоэлектрические и пьезоэлектрические датчики с автономным
питанием могут отслеживать действия на рабочем месте, такие как набор текста и
использование мыши. Эти датчики экономичны и нетребовательны к работе, но могут
потребовать первоначальной настройки и калибровки[29].Эти датчики, накладываемые на
указательный палец, могут улавливать выходные электрические сигналы во время
выполнения обычных офисных задач, таких как набор текста, прокрутка мыши и
написание текста. Собранные данные затем анализируются с помощью сверточных
нейронных сетей (CNN) для точного разграничения различных видов деятельности и
достижения точности классификации более 98% [30]. Интеграция
трибоэлектрических и пьезоэлектрических механизмов повышает чувствительность и
производительность этих датчиков, на примере приложения для мыши, которое
обнаруживает различные операции мыши по различным схемам напряжения,
обеспечивая эффективный мониторинг поведения пользователя и сбор энергии [47]. Кроме того,
пьезоэлектрические датчики используются в условиях удаленной работы для
ненавязчивого мониторинга рабочей нагрузки и уровня стресса сотрудников, что
свидетельствует об их способности собирать долгосрочные данные без причинения
дискомфорта [28]. Эти качества подчеркивают
потенциал трибоэлектрических и пьезоэлектрических датчиков в улучшении
мониторинга рабочих мест, обеспечивая ненавязчивое, эффективное и точное
средство оценки деятельности и благополучия ИТ-сотрудников.
Для получения обратной связи по эффективности работы
системы мониторинга можно использовать опросы и самоотчеты.Это достаточно традиционные
методы сбора данных. Опросы и самоотчеты, например те, которые были использованы
в исследовании Pazioetal., дают представление об уровне физической активности
ИТ-работников. Они показывают, что значительная часть сотрудников сообщала о
недостаточной физической активности во время пандемии COVID-19, и многие
считают, что пандемия негативно сказалась на их образе жизни, разрабатываемая
система может рассматриваться для дальнейшей адаптации к обстоятельствам при
которых может быть недостаток физической активности [24]. Хотя они дают субъективную
информацию, они склонны к предвзятости и высоким процентам отсева. Самоотчеты
могут быть предвзяты, например, люди часто завышают свои навыки в сфере ИКТ
из-за предвзятого отношения к социальной привлекательности [23].Это говорит о том, что, хотя
самоотчеты могут содержать ценные данные, их следует интерпретировать с
осторожностью. Напротив, электронные инструменты мониторинга, такие как Net
Monitor forEmployees, представляют собой более объективное средство отслеживания
компьютерной активности, позволяя руководителям отслеживать производительность
и вовлеченность, не полагаясь исключительно на данные, сообщаемые сами [48]. Есть успешный, для повышения
качества жизни через уравновешивание влияния работы и отдыха от него, пример
совмещения самоотчетов и машинного мониторинга активности [17]. Поэтому данный источник
информации можно применить в дальнейших исследованиях, когда разработанная в
данной работе автоматизированная система будет применяться для влияния на
уровень технологического стресса и цифрового благополучия, но с определенным
упреждениям в силу обозначенных обстоятельств. Множество систем, используют
несколько видов источников данных: телеметрия компьютера, невербальный язык
пользователя компьютера и пр. [3, 13].
Некоторые системы собирали данные о действиях
пользователя и на основании ключевых слов, количества слов и подобных типов
данных делали выводы о состоянии пользователя [35]. Также использовали историю
поиска для расчета дальнейших действий и сбор обратной связи как напрямую, так
и косвенно для отладки поведения программы. В будущем проекте так же можно
собирать историю браузера для определения состояния активности пользователя в
зависимости от его роли, например посещение социальных сетей для SMM
специалиста является естественным, в то время как для бухгалтера это не
является подразумеваемой чертой. Так же можно собирать данные обратной связи,
например, при блокировке сессии для проведения перерыва от компьютера, ожидать
признаки фрустрации, например, множественные нажатия на клавиатуре или дергание
курсором мыши, что может означать негативную обратную связь и неверную оценку активности
пользователя.
Используют окружающий звук и свет для определения
простоя, отвлеченного состояния человека [3, 13, 49]. Возможно использовать
веб-камеру или датчик света для определения недостаточного освещения, что может
привести к пониженной эффективности [33]. Также использовать микрофон,
в частности встроенный в веб-камеру для определения зашумленности звукового
окружения пользователя компьютера. Окружающий шум и разговоры соседей могут
понижать эффективность пользователя компьютера, однако некоторые виды шумов без
резких звуков имеют обратный эффект [21].
Эмоциональный окрас содержимого в компьютере влияет на
эмоциональное состояние пользователя компьютера что может влиять на его
продуктивность [50]. При возможности
анализировать эмоциональные окрас содержимого можно использовать это как один
из косвенных признаков того, что активность пользователя определенного уровня и
какую оценку стоит дать его активности.
Waterfall (Каскадная модель). Выбран по причине того, что
это линейный подход, где каждая фаза проекта (анализ, проектирование,
разработка, тестирование, внедрение) выполняется последовательно. Проект с
четкими требованиями, нет требования в гибком изменении требований.
Kanban. Выбран потому что это визуальный метод управления
задачами, где работа перемещается по этапам выполнения из одного статуса в
другой что дает наглядное представление о состоянии проекта.
Yougile. Выбран по причине того что является неподсанкционным
инструментом для управления проектами и задачами в них, включает в себя
функционал канбан доски. Функционал управления командой оказался невостребован.
GitHub. Выбран потому что позволяет бесплатно хранить
приватный репозиторий кодовой базы проекта. Включает в себя функционал
версионирования проекта.
Данное техническое задание составлено на разработку
«Разработка автоматизированной системы мониторинга активности сотрудников в ИТ
компаниях». Данная система будет содержать следующий функционал:
Модуль анализа списка запущенных процессов;
Модуль анализа данных с устройств ввода;
Модуль разработки и хранения документации;
Модуль сертификации.
Настоящее техническое задание распространяется на
разработку программы «Разработка автоматизированной системы мониторинга
активности сотрудников в ИТ компаниях», используемой для мониторинга активности
сотрудников, активно пользующихся компьютерами
Целью является получить готовую автоматизированную
систему мониторинга активности сотрудников в ИТ компаниях.
Задачами являются: определить и разработать средства
сбора и обработки данных компьютера и подключенных к нему устройств ввода.
Программа является актуальной, так как:
1. Позволяет уменьшить фрустрацию путем подбора более
оптимального момента для прерывания пользовательской сессии на некоторый
промежуток времени с целью отдыха
2. Позволяет
увеличить эффективность сотрудников в ИТ компаниях путем оптимизации режима
работы за компьютерами
«Разработка автоматизированной системы мониторинга
активности сотрудников в ИТ компаниях» разрабатывается в соответствии с
запросом на увеличение эффективности сотрудников и улучшения их самочувствия.
Основное назначение «Разработка автоматизированной системы
мониторинга активности сотрудников в ИТ компаниях» заключается в определении
состояния сотрудника за компьютером с целью дальнейшего реагирования, например,
прерыванием сессии с целью перерыва.
4.1 Требования к функциональным характеристикам
4.1.1 Выполняемые функции
4.1.1.1 Для пользователя:
- Временная блокировка компьютера
- Временная разблокировка компьютера
- Уведомление о перерыве
4.1.2 Исходные данные:
- Вводятся пользователем
- Собираются системой
4.1.3 Результаты
- Отсутствие доступа к компьютеру
- Наличие доступа к компьютеру некоторое спустя время
4.2 Требования к надежности
4.2.1 Предусмотреть контроль вводимой информации.
4.2.2 Предусмотреть защиту от некорректных действий
пользователя.
4.3 Условия эксплуатации
4.3.1 Условия эксплуатации в соответствие с СанПин
2.2.2.542 — 96.
4.4 Требования к составу и параметрам технических средств
4.4.1 Программное обеспечение должно функционировать на
IВМ-совместимых персональных компьютерах.
4.4.2 Минимальная конфигурация технических средств:
4.4.2.1 Тип процессора архитектура x86-x64.
4.4.2.2 Объем ОЗУ 512Мб.
4.5 Требования к информационной и программной
совместимости
4.5.1 Программное обеспечение должно работать под
управлением операционных систем.
4.5.2 Входные данные должны быть представлены в виде
формы для регистрации
4.5.3 Результаты должны быть представлены в следующем
формате:
одобрение проекта
4.5.4 Программное обеспечение windows 10-11, (желательно
применение keras, sklearn, pandas, .net6+), языки программирования c# и\или
python.
4.6 Требования к маркировке и упаковке
Требования к маркировке и упаковке не предъявляются.
4.7 Требования к транспортированию и хранению
Требования к транспортировке и хранению не предъявляются
4.8 Специальные требования
Сгенерировать установочную версию программного
обеспечения.
5.1 Разрабатываемые программные модули должны быть
самодокументированы, т.е. тексты программ должны содержать все необходимые
комментарии.
5.2 Разрабатываемое программное обеспечение должно
включать справочную систему.
5.3 В состав сопровождающей документации должны входить:
5.3.1 Техническое задание.
5.3.2 Инструкция пользователя.
Технико-экономическое обоснование разработки не выполняется.
|
№
|
Название этапа
|
Срок, дни
|
Отчётность
|
|
1
|
Разработка технического задания
|
10.10.2024, 10
|
Техническое задание
|
|
2
|
Анализ требований и уточнение спецификаций
|
20.10.2024, 10
|
|
|
3
|
Проектирование структуры программного обеспечения,
проектирование компонентов (технический проект)
|
10.10.2024, 10
|
Алгоритм программы
|
|
4
|
Реализация компонент и автономное тестирование компонентов.
Сборка и комплексное тестирование. Оценочное тестирование и (рабочий проект)
|
15.11.2024, 26
|
Текст программы. Программа и методика испытаний
|
|
5
|
Разработка программной документации
|
25.11.2024, 10
|
Описание программы. Руководство оператора
|
8.1 Порядок контроля
Контроль выполнения осуществляется заказчиком.
9.1 В процессе выполнения работы возможно уточнение
отдельных требования технического задания по взаимному согласованию
руководителя и исполнителя.
Опишем подбор оптимального варианта решения искусственного
интеллекта для классификации состояния активности пользователя ПК на основе
данных с устройств ввода.
У нас имеются данные подобной структуры[Листинг 1].
Каждая подсессия пользователя записывается в виде структуры, которая включает в
себя целевой признак состояния активности и список действий с устройств ввода.
Листинг 1 - Тип данных записей с устройств
ввода.
|
{
mode: 0 | 1,
list: [{buttonKey: number, dateTime: Timestamp}]
}
|
Ключ с каждого типа устройств учтен таким образом, чтобы
они не пересекались между собой с применением словаря в python скрипте,
ответственном за сбор этих данных. Mode содержит в себе множество числовых значений,
обозначающих определенное состояние активности пользователя. Datetime является
записью даты и времени.
Опишем ряд вариантов реализации модуля классификатора на
основе такой структуры данных.
Статистическийанализ (FeatureEngineering + Threshold). Это простейший подход среди
рассматриваемых — выделить признаки (features) из list и применить пороговые
правила для них.
Данный метод классификации, основанный на
featureengineering и применении пороговых правил, обладает рядом преимуществ,
связанных с его простотой и интерпретируемостью. Поскольку алгоритм опирается
на статистические метрики, такие как среднее и медианное время между событиями,
частотные характеристики нажатий и экстремальные значения признаков, его
реализация не требует сложных вычислительных процедур. Это делает метод
эффективным для задач, где важна скорость обработки данных и прозрачность
принятия решений. Кроме того, благодаря использованию детерминированных правил,
специалист может легко корректировать классификатор, опираясь на предметную
область, что особенно полезно в условиях ограниченного объема данных или
необходимости быстрого прототипирования. Однако данный подход имеет
существенные ограничения, связанные с его линейностью и зависимостью от ручной
настройки. Если распределение признаков для разных классов (mode 0 и mode 1)
перекрывается или имеет сложную структуру, пороговые правила могут
демонстрировать низкую точность. Кроме того, метод не учитывает возможные
взаимодействия между фичами, что снижает его обобщающую способность. Еще одним
недостатком является чувствительность к выбросам: такие метрики, как среднее
арифметическое, могут искажаться под воздействием аномальных значений, что
потребует дополнительной предобработки данных.
Статистический подход с пороговой классификацией
целесообразно применять в случаях, когда данные обладают выраженной
разделимостью по ключевым признакам, чего не предвидеться в нашем случае, а
также когда критична скорость работы алгоритма, что является требованием не
настолько строгим. Этот метод особенно эффективен в условиях, где допустима
ручная настройка и где интерпретируемость модели важнее её абсолютной точности,
что тоже не является для нас необходимым.
Наши данные характеризуются нелинейными зависимостями и
высокой степенью пересечения классов, поэтому предпочтительнее использовать
методы машинного обучения. Например, логистическая регрессия позволяет
учитывать взвешенное влияние нескольких признаков, а деревья решений
автоматически находят оптимальные пороги разбиения. Мы рассмотрим их далее. В
более сложных случаях, когда требуется учет взаимодействий между множеством
переменных, могут применяться ансамблевые алгоритмы, такие как RandomForest или
градиентный бустинг, например XGBoost, которые демонстрируют высокую точность
за счет комбинирования множества слабых классификаторов их мы тоже рассмотрим
далее. В нашем случае данные содержат выраженные временные закономерности,
требующие анализа последовательностей, более подходящими могут оказаться модели
глубокого обучения, например, свёрточные (CNN), графовые (GNN) или рекуррентные
нейронные сети (RNN или как частные случаи– LSTM и GRU).
Составим краткое описание возможной реализации в
контексте описанного ранее подхода.
Признаки. Количество записей в list, не должно иметь
решающую роль, изначально калибровка классификатора должна происходить
независимо от размера файла лог записей; Среднее/медианное время между
нажатиями (dateTime), необходимо учесть особые случаи, когда пользователь может
работать, будучи внимательно изучающим содержимое экрана без активного
использования устройств ввода и наоборот;Частота нажатий (например, сколько раз
buttonKey встречается в определенном диапазоне), так же надо учесть особые
случаи как с признаков выше, например, при множестве прокруток колеса мыши вниз
или применении связок кнопка типа Alt+Tab.
Классификация.Если list пуст, тоmodeравензначению по
умолчанию.Если среднее время между нажатиями меньше заданного порога, то modeравен
определенному значению.Если частота нажатий определенной кнопки больше
определенного порога, то modeравен иному значению.
Ниже представлен пример реализации с применением
статистического подхода с пороговой классификацией [Листинг 2]. Решение извлекает 6 ключевых признаков из списка
событий: count – общее количество нажатий; mean_time_diff – среднее время между
нажатиями (в мс); median_time_diff – медианное время (устойчиво к выбросам);min_key, max_key – диапазон
значений кнопок; freq_low – доля нажатий кнопок с buttonKey< 5 (пример
категоризации).Временные метки могут приходить в произвольном порядке.
Сортировка гарантирует корректное вычисление интервалов. Присутствуют проверки,
например защита от ошибок, если list пуст. Используются медианы, т.к. медиана
устойчива к выбросам (например, если было одно очень долгое нажатие).
Используется вычисленное свойство freq_low
из-за предположения что если есть много нажатий на кнопки с малыми номерами, то
это может указывать на определенное значение целевого свойства. Можно было
добавить стандартное отклонение временных интервалов (метрика
"разброса"). Можно было считать частоту конкретных кнопок (например,
buttonKey=3). Но это усложнило бы модель без явной необходимости. Объясним
используемые правила классификации. Если count меньше 3 значит mode равен 0,
т.е. если мало данных, тогда выбираем консервативный вариант (0). Еслиmean_time_diffбольше 1000 илиmedian_time_diffбольше 800, тогдаmodeравен 1, т.е. если
интервалы между нажатиями большие, возможно, mode равен 1. Если freq_low больше
0.7, тогда mode равен 0, т.е. если больше 70 процентов нажатий на кнопки с
условно маленьким номеров, тогда склоняемся к тому, что mode равен 0. Если
разница между кнопкой с наибольшим номером и наименьшим больше 10, тодаmodeравен 1, т.е. если кнопки
очень разные, возможно, mode равен 1.
Листинг 2 - Пример реализации статистического подхода
с пороговой классификацией.
|
import
time
import tracemalloc
from typing import List, Dict, Union
import numpyas np
from sklearn.metricsimport classification_report
from device_input.device_log_loaderimport load_device_logs
def extract_features(data: Dict[str, Union[int, List[Dict[str, int]]]]) ->Dict[str,
float]:
"""
Извлекаетстатистическиепризнакиизвходныхданныхдляпоследующейклассификации.
Args:
data: Входныеданныевформате {'mode': int, 'list': [{'buttonKey': int,
'dateTime': int}, ...]}
Returns:
Словарьсвычисленнымипризнаками:
- count: количествозаписей
- mean_time_diff: среднеевремямеждунажатиями (всекундах)
- median_time_diff: медианноевремямеждунажатиями
- min_key: минимальноезначениеbuttonKey
- max_key: максимальноезначениеbuttonKey
- freq_low: долянажатийсbuttonKey< 5
"""
events = data['list']
timestamps = sorted([e['dateTime'] for e in events])
button_keys= [e['buttonKey'] for e in events]
# Вычислениевременныхпромежутковмеждусобытиями
time_diffs= np.diff(timestamps) if len(timestamps)
>1 else [0]
features = {
'count': len(events),
'mean_time_diff': np.mean(time_diffs),
'median_time_diff': np.median(time_diffs),
'min_key': min(button_keys) if button_keyselse 0,
'max_key': max(button_keys) if button_keyselse 0,
'freq_low': sum(k <5 for kin button_keys) / len(button_keys) if button_keyselse 0
}
return features
def classify_by_thresholds(features: Dict[str, float]) ->int:
"""
Классифицирует mode
наосновеизвлеченныхпризнаковипороговыхправил.
Args:
features: Словарьсизвлеченнымипризнаками
Returns:
Предсказанный mode
(0 или 1)
"""
# Эмпирическиопределенныепороговыезначения
if features['count']
<3:
return 0
if (features['mean_time_diff'] >1000 or
features['median_time_diff'] >800):
return 1
if features['freq_low']
>0.7:
return 0
if features['max_key'] - features['min_key']
>10:
return 1
# Поумолчаниювозвращаем 0
return 0
# Примериспользования
if __name__ == "__main__":
# Примервходныхданных
sample_data = load_device_logs(1000)
# Измерениеиспользованияпамятидо
tracemalloc.start()
start_inf = time.time()
# Предсказаниенатестовыхданныхсзамеромвремени
y_pred = []
for item in sample_data:
# Извлекаемпризнаки
features = extract_features(item)
# Классифицируем
y_pred.append(classify_by_thresholds(features))
end_inf = time.time()
inference_time = end_inf - start_inf
# Измерениепамятипослеобучения
current, peak =
tracemalloc.get_traced_memory()
max_ram_usage = peak / (1024 ** 2) # в MB
tracemalloc.stop()
y_test = [sample_data['mode'] for sample_datain sample_data]
print(classification_report(y_test, y_pred, zero_division=0))
print(f"Max RAM Usage: {max_ram_usage:.2f} MB")
print(f"Inference time: {inference_time:.4f} s")
|
Оценкаэффективностирешениясприменениемстатистическогоподходаспороговой
классификацией представлена ниже [Рисунок
1].
Рисунок 1 - Скриншот результата измерения
эффективности решения с применением статистического подхода.
Классическое машинное обучение (ML). Далее мы рассмотрим
несколько классических моделей: Случайный лес (RandomForest), XGBoost,
CatBoost, Логистическая регрессия (LogisticRegression).
Логистическая регрессия представляет собой статистический
метод классификации, обладающий рядом преимуществ в контексте предложенной
задачи. Одним из достоинств является высокая интерпретируемость модели.
Поскольку логистическая регрессия вычисляет весовые коэффициенты для каждого
признака, это позволяет аналитику оценить вклад отдельных факторов, таких как
частота нажатий определённых кнопок или дисперсия временных интервалов, в
определение целевого свойстваmode.С вычислительной точки зрения, данный метод является
достаточно эффективным. Алгоритм быстро сходится даже на относительно больших
выборках, а время получения инференса, то есть конечный результат обработки
данных, для новых данных минимально, что делает его пригодным для систем,
работающих в реальном времени. Кроме того, логистическая регрессия
демонстрирует устойчивую работу в условиях линейной разделимости классов. Если
извлечённые признаки действительно содержат линейно разделяющие закономерности,
что, к сожалению, мы не можем обеспечить этого в нашем случае, модель достигнет
удовлетворительной точности без переобучения, особенно при использовании L1-
или L2-регуляризации. Регуляризация ограничивает величину весовых значений
модели, добавляя штраф для весов к функции ошибки модели. В L1-регуляризации
используется сумма абсолютных значений весовых значений, а в L2-регуляризации —
сумма квадратов весовых значений.
Метод имеет существенные ограничения, связанные с его
линейной природой. В случае, если зависимость между признаками и целевой
переменной носит нелинейный характер (например, если свойство mode определяется
сложными комбинаторными или временными паттернами), предсказательная
способность модели может оказаться недостаточной. Кроме того, логистическая
регрессия требует тщательного проектирования признакового пространства.
Неудачный выбор или отсутствие информативных признаков, таких как временные
производные или частотные метрики, приведёт к снижению качества классификации.
Ещё одним ограничением является чувствительность модели к дисбалансу классов.
При значительном преобладании одного из классов (например, если mode равен 0
встречается в 90% случаев) алгоритм склонен к смещению в сторону мажоритарного,
то есть более частотного, класса. Для коррекции этого эффекта необходимо
применять методы балансировки, такие как взвешивание классов или синтетическое
увеличение выборки миноритарного класса (SMOTE).Логистическая регрессия также
не учитывает потенциальные временные зависимости между наблюдениями внутри
списка list. Хотя такие признаки, как средний интервал между событиями или
дисперсия времени, частично отражают временную структуру, они не способны
моделировать сложные последовательные закономерности, для которых более
подходящими могли бы быть рекуррентные нейронные сети (RNN) или трансформеры.В
условиях мультиколлинеарности признаков, то есть, когда наблюдается сильная
корреляция между признаками, например, при высокой корреляции между
"количеством нажатий кнопки 5" и "долей нажатий кнопки 5",
оценки коэффициентов регрессии становятся неустойчивыми, что может потребовать
дополнительной обработки данных, такой как отбор признаков или применение
методов уменьшения размерности.Логистическая регрессия оправдана в качестве
базового решения, если предварительный анализ данных подтверждает линейную разделимость
классов, а также если интерпретируемость модели является критически важным
требованием. Таким образом логистическая регрессия не является для нас лучшим
вариантом.
Ниже представлен пример реализации решения с использование
логистической регрессии [Листинг
3]. Опишем представленное решение. Происходит преобразование
сырых данных (последовательность нажатий) в числовые признаки. Вычисляются
следующие свойства. Свойство session_length, т.к. длина сессии может
коррелировать с классом, не используютсяmin/maxиз-за недостатка информации.
Свойство time_mean, т.к. среднее время между нажатиями может быть важным
паттерном. Свойство btn_ratio, т.к. относительная частота определенной кнопкиможет
быть маркером. Свойство rapid_clicks, количество быстрых нажатий может быть
важным паттерном. Используются относительные частоты для свойств btn_ratio, а
не абсолютные counts, т.к. благодаря этому модель не зависит от длины сессии. Добавлены
временные характеристики, т.к. логистическая регрессия не умеет работать с
последовательностями без предобработки, т.е. с последовательностями с
переменной длиной, и с временными зависимости между элементами. Для предобработки используется StandardScaler, потому что логистическая
регрессия чувствительна к масштабу признаков, ион необходим, когда признаки
разных единиц, например время и частота. Для классификатора выбраны следующие
значения параметров и вот почему. Параметр class_weight равен 'balanced' т.к. в
данных может быть дисбаланс, например, 70 на 30. Параметр penalty равен 'l2',
потому что так обычно работает лучше, чем 'l1' для "гладких" данных, т.е. данных, которые имеют
небольшие, постепенные изменения, не содержат резких выбросов или скачков,
коррелируют друг с другом плавно, и L2-регуляризация штрафует большие веса, но
не обнуляет их полностью (в отличие от L1). Это работает хорошо, когда все
признаки вносят небольшой вклад и между признаками есть корреляции. Параметр
max_iterравен 1000, потому что на сложных данных стандартных 100 итераций может
не хватить итераций.
Листинг 3- Реализация решения с применением
логистической регрессиию
|
import
time
import tracemalloc
import numpyas np
import pandas as pd
from sklearn.linear_modelimport LogisticRegression
from sklearn.preprocessingimport StandardScaler
from sklearn.pipelineimport make_pipeline
from sklearn.model_selectionimport train_test_split
from sklearn.metricsimport classification_report
from device_input.device_log_loaderimport load_device_logs
class ButtonPatternClassifier:
def __init__(self):
"""Инициализацияпайплайнасмасштабированиемилогистическойрегрессией"""
self.model = make_pipeline(
StandardScaler(),
LogisticRegression(
penalty='l2',
C=1.0,
solver='lbfgs',
class_weight='balanced',
max_iter=1000,
random_state=42
)
)
def prepare_dataset(self, json_data):
X = []
y = []
for item in json_data:
X.append(item['list'])
y.append(item['mode'])
return X, y
def _extract_features(self, dataset):
"""Извлечениепризнаковизсырыхданных"""
features = []
for events in dataset:
# Базовыестатистики
num_events= len(events)
button_keys= [e['buttonKey'] for e in events]
timestamps = [e['dateTime'] for e in events]
# Временныехарактеристики
time_diffs= []
if len(timestamps) >1:
time_diffs= [
(timestamps[i] - timestamps[i+ 1])
for iin range(len(timestamps) - 1)
]
# Частотныехарактеристикикнопок
button_counts= {i: 0 for iin range(1, 81)}
for btnin button_keys:
if btnin button_counts:
button_counts[btn] += 1
# Формированиевекторапризнаков
feature_vec= {
'session_length': num_events,
'time_mean': np.mean(time_diffs) if time_diffselse 0,
'time_std': np.std(time_diffs) if time_diffselse 0,
**{f'btn{i}_ratio': button_counts[i] / num_eventsfor iin range(1, 81)},
'rapid_clicks': sum(1 for diff in time_diffsif diff <1.0)
}
features.append(feature_vec)
return pd.DataFrame(features)
def fit(self, X, y):
"""Обучениемоделинаразмеченныхданных"""
X_features= self._extract_features(X)
self.model.fit(X_features, y)
return self
def predict(self, X):
"""Предсказаниеклассовдляновыхданных"""
X_features= self._extract_features(X)
return self.model.predict(X_features)
def predict_proba(self, X):
"""Предсказаниевероятностейклассов"""
X_features= self._extract_features(X)
return self.model.predict_proba(X_features)
def evaluate(self, X, y):
"""Оценкакачествамодели"""
X_features= self._extract_features(X)
y_pred= self.model.predict(X_features)
return classification_report(y, y_pred, output_dict=True)
# Примериспользования
if __name__ == "__main__":
sample_data = load_device_logs(1000)
classifier =
ButtonPatternClassifier()
X_data, y_labels = classifier.prepare_dataset(sample_data)
X_train, X_test, y_train, y_test = train_test_split(X_data, y_labels, test_size=0.2, random_state=42)
# Измерениеиспользованияпамятидообучения
tracemalloc.start()
start_train = time.time()
classifier.fit(X_train, y_train)
end_train = time.time()
training_time = end_train - start_train
# Измерениепамятипослеобучения
current, peak =
tracemalloc.get_traced_memory()
max_ram_usage = peak / (1024 ** 2) # в MB
tracemalloc.stop()
# Оценкакачества
sample_data = X_test
start_inf = time.time()
y_pred = classifier.predict(sample_data)
end_inf = time.time()
inference_time = end_inf - start_inf
print(classification_report(y_test, y_pred))
print(f"Max RAM Usage: {max_ram_usage:.2f} MB")
print(f"Inference time: {inference_time:.4f} s")
|
Оценкаэффективностирешениясприменениемлогистическойрегрессиипредставленаниже[Рисунок2].
Рисунок2- Скриншототчетаизмеренияэффективностирешениясприменениемлогистическойрегрессии.
Случайныйлес. Данныйподходобладаетвысокой интерпретируемостью, поскольку
извлекаемые признаки (такие как количество записей, временные интервалы между
событиями и частотность нажатий кнопок) имеют четкую семантику. Это позволяет
анализировать вклад каждого признака в предсказание целевого свойства mode.
RandomForest также обеспечивает оценку важности признаков (featureimportance),
что помогает выявить наиболее значимые факторы, влияющие на классификацию, это
может оказаться полезным для дальнейших работ, но не является необходимым для
текущей.Алгоритм демонстрирует устойчивость к переобучению благодаря
ансамблевому характеру работы: агрегация предсказаний множества деревьев
снижает шанс ошибки. Кроме того, RandomForest эффективно работает с
разнородными данными, включая как числовые (временные метки, статистики), так и
категориальные (идентификаторы кнопок) признаки, без необходимости сложной
предварительной обработки.Метод автоматически учитывает взаимодействия
признаков за счет построения множества решающих деревьев, каждое из которых
может выявлять нелинейные зависимости. Например, модель может обнаружить, что
комбинация частого нажатия кнопки 5 и малой дисперсии временных интервалов
коррелирует с mode равной 1.С точки зрения масштабируемости, после
обучения модель быстро обрабатывает новые данные, поскольку предсказание
требует лишь однократного вычисления признаков и прохода по ансамблю деревьев.
Однако эффективность модели существенно зависит от объема
и репрезентативности данных. В случае малого количества обучающих примеров или
сильного дисбаланса классов (например, если один mode встречается
значительно чаще другого) качество классификации может снижаться из-за
смещенного обучения. Для борьбы с дисбалансом классов можно применять методы
ресемплинга: oversampling (дополнять данные к миноритарному классу), undersampling
(убирать данные от мажоритарного класса), или использовать взвешивание классов
в функции потерь.Ключевым ограничением является необходимость ручной разработки
признаков (featureengineering). Качество предсказаний напрямую определяется
тем, насколько удачно выбраны и сконструированы признаки. Например, если
целевая переменная зависит от сложных временных паттернов (таких как
определенные последовательности нажатий кнопок), модель может не выявить эти
зависимости без явного кодирования соответствующих признаков.Важным недостатком
является игнорирование временной последовательности событий. Поскольку
RandomForest оперирует агрегированными статистиками, он не учитывает порядок
элементов в list. Если mode зависит от последовательности
нажатий (например, "кнопка 1, затем кнопка 2"), потребуется
дополнительная разработка признаков или переход к методам, специализированным
для временных рядов.Еще одной проблемой может стать разреженность
категориальных признаков. Редко встречающиеся значения buttonKey (например,
уникальные или малоповторяющиеся кнопки) могут не оказывать значимого влияния
на модель, что потребует их группировки или использования альтернативных
методов кодирования.При больших объемах данных вычисление агрегированных признаков
(таких как дисперсия временных интервалов) может стать вычислительно затратным,
что замедлит как обучение, так и предсказание.Для повышения качества
классификации целесообразно экспериментировать с дополнительными признаками,
такими как порядковые характеристики (например, первая или последняя нажатая
кнопка) и комбинаторные паттерны (например, частотность определенных
последовательностей кнопок), что приведет к трудозатратному перебору списка
оптимальных признаков, который может изменяться от пользователя к пользователю.Свойство
mode зависит от временных зависимостей, поэтому рассмотрим данный вариант
модели как не фаворит следующим вариантам.
Ниже представлен пример реализации решения с использованием
randomforest [Листинг
3]. Опишем реализацию. Начнем с вычисляемых свойств.
Свойство count, общее количество событий, показатель активности, может
коррелировать с mode. Свойства time_diff_meanи time_diff_stdпоказывают
"ритм" взаимодействий , например если есть быстрые клики, тогда mode
равен 1. Свойства time_diff_maxи time_diff_min, выявляют аномалии, например
если есть долгие паузы, тогда, возможно , mode равен 0. Абсолютные, например key_{i}_count,
и относительные, например key_{i}_ratio, частоты кнопок. Ограничение до x кнопок (range(1,x)), из-за предположения о ограниченном
количестве членов множества кнопок. Свойство fast_events фиксирует
"бурные" сессии, напримеркогда больше 3 кликов за 5 секунд, тогдаmode
равен 1.Опишем параметры модели. Параметр n_estimators равен 100, потому что
этого достаточно для большинства задач. Параметр max_depth равен 10, это дает
ограничение сложности деревьев. Параметр class_weight равен 'balanced ', потому что один mode может
встречаться чаще другого.
Листинг 4- Реализация решения с применением randomforest.
|
import
time
import tracemalloc
import numpyas np
import pandas as pd
from sklearn.ensembleimport RandomForestClassifier
from sklearn.metricsimport classification_report
from sklearn.model_selectionimport train_test_split
from device_input.device_log_loaderimport load_device_logs
def extract_features(data):
"""Извлекаетпризнакиизспискасобытий"""
features = {}
# Базовыепризнаки
features['count'] = len(data)
# Временныепризнаки
timestamps = [x['dateTime'] for x in data]
time_diffs= np.diff(timestamps)
if len(time_diffs) >0:
features['time_diff_mean'] = np.mean(time_diffs)
features['time_diff_std'] = np.std(time_diffs)
features['time_diff_max'] = np.max(time_diffs)
features['time_diff_min'] = np.min(time_diffs)
else:
features.update({
'time_diff_mean': 0,
'time_diff_std': 0,
'time_diff_max': 0,
'time_diff_min': 0
})
# Частотныепризнаки
button_keys= [x['buttonKey'] for x in data]
unique_keys, counts = np.unique(button_keys, return_counts=True)
key_counts= dict(zip(unique_keys, counts))
# Добавляемколичествонажатийдлякаждойкнопки (до 10)
for iin range(1, 11):
features[f'key_{i}_count'] = key_counts.get(i, 0)
# Относительныечастоты
total_presses= len(button_keys)
for iin range(1, 11):
features[f'key_{i}_ratio'] = features[f'key_{i}_count'] / total_pressesif total_presses>0 else 0
# Временныепаттерны
if len(time_diffs) >0:
features['fast_events_5s'] = np.sum(np.array(time_diffs) <= 5)
features['fast_events_10s'] = np.sum(np.array(time_diffs) <= 10)
else:
features.update({
'fast_events_5s': 0,
'fast_events_10s': 0
})
return features
def prepare_dataset(json_data):
"""Подготавливаетдатасетизсырых JSON данных"""
X = []
y = []
for item in json_data:
# Извлекаемцелевойпризнак
y.append(item['mode'])
# Извлекаемпризнакиизспискасобытий
features = extract_features(item['list'])
X.append(features)
# ПреобразуемвDataFrame
feature_df= pd.DataFrame(X)
return feature_df, np.array(y)
# Примериспользования
if __name__ == "__main__":
sample_data = load_device_logs(1000)
# Подготовкаданных
X, y = prepare_dataset(sample_data)
# Разделениена train/test
X_train, X_test, y_train, y_test =
train_test_split(X, y, test_size=0.3, random_state=42)
# Измерениеиспользованияпамятидообучения
tracemalloc.start()
start_train = time.time()
# Обучениемодели
model = RandomForestClassifier(
n_estimators=100,
max_depth=10,
random_state=42,
class_weight='balanced' # Длянесбалансированныхданных
)
model.fit(X_train, y_train)
end_train = time.time()
training_time = end_train - start_train
# Измерениепамятипослеобучения
current, peak =
tracemalloc.get_traced_memory()
max_ram_usage = peak / (1024 ** 2) # в MB
tracemalloc.stop()
# Предсказаниенатестовыхданныхсзамеромвремени
y_pred = []
# Оценкакачества
start_inf = time.time()
y_pred = model.predict(X_test) # вызывать predict дляотдельныхстрок
end_inf = time.time()
inference_time = end_inf - start_inf
print(classification_report(y_test, y_pred))
print(f"Max RAM Usage: {max_ram_usage:.2f} MB")
print(f"Inference time: {inference_time:.4f} s")
|
Оценкаэффективностирешениясприменениемrandomforestпредставленаниже[Рисунок1].
Рисунок3 - Скриншотизмеренияреализациисприменениемrandomforest.
Градиентныйбустинг. Однимиздостоинствданногоподхода, какиунекоторыхрассматриваемыхвданнойработеявляетсявысокаяинтерпретируемостьпризнаков. Посколькупризнакиформируютсянаосновеявныхстатистическихивременныхметрик (такихкакколичествозаписей, разницамеждувременнымиотметками, частотностьнажатийкнопок), ихвлияниенамодельможетбытьпроанализированоспомощьюметодовоценкиважностипризнаков (featureimportance). Этопозволяетнетолькоулучшатьмодель, ноипонимать, какиепаттернывданныхнаиболеезначимыдляклассификации.Другимважнымпреимуществомявляетсяэффективностьработыалгоритмовбустинганаотносительнонебольшихобъемахданных. Вотличиеотглубокогообучения, котороетребуетзначительныхвычислительныхресурсовибольшихдатасетов,
методывродеXGBoostиCatBoostдемонстрируютвысокуюточностьдаженавыборкахразмеромвтысячипримеров.
Крометого, эти алгоритмы хорошо справляются с разнотипными признаками, включая
категориальные переменные (например, buttonKey), что делает их
универсальным инструментом для задач классификации.Скорость обучения и
предсказания также является существенным плюсом. Бустинговые модели
оптимизированы для быстрой обработки данных и требуют меньше вычислительных
мощностей по сравнению с нейросетевыми архитектурами. Это особенно важно в
сценариях, где необходимо оперативное развертывание или частый ретроспективный
анализ. Наконец, встроенные механизмы регуляризации в XGBoost и CatBoost
снижают риск переобучения, что критично при работе с ограниченными или
зашумленными данными.
Однако данный подход имеет ряд существенных ограничений.
Основным из них является зависимость от ручного конструирования признаков
(featureengineering). Поскольку модель работает только с агрегированными
статистиками, качество классификации напрямую зависит от того, насколько удачно
выбраны и сконструированы признаки. Это требует глубокого понимания предметной
области и может быть трудоемким процессом, особенно если в данных присутствуют
сложные временные или последовательностные зависимости.Еще одним ограничением
является неспособность классических ML-методов эффективно учитывать порядок
элементов в последовательности. В то время как нейросетевые подходы (например,
RNN или Transformer) могут анализировать временные ряды с учетом их структуры,
бустинговые модели оперируют лишь агрегированными характеристиками. Это может
привести к потере важных паттернов, особенно если целевой показатель (mode)
зависит от динамики нажатий, а не только от их суммарных статистик.Проблемы
также могут возникать при работе с разреженными данными. Например, если
переменная buttonKey принимает множество уникальных значений,
частотные признаки могут стать слишком разреженными, что негативно скажется на
обобщающей способности модели. Кроме того, если разметка данных содержит шум
или несбалансирована, это может привести к смещению предсказаний и ухудшению
метрик качества.Наконец, классические ML-модели плохо адаптируются к изменениям
в распределении данных, conceptdrift (когда происходит эволюция данных, которая
делает модель данных недействительной). Если со временем пользовательское
поведение меняется (например, частотность нажатий определенных кнопок
возрастает), модель потребует периодического переобучения на актуальных данных.
Подберем подходящий алгоритм градиентного бустинга среди
современных: CatBoost, XGBoost и LightGBM. CatBoost демонстрирует
исключительную эффективность при работе с категориальными признаками благодаря
встроенным механизмам их обработки. Алгоритм использует инновационный подход
orderedboosting, который минимизирует смещение оценок через специальную схему
перестановок. Эта особенность делает CatBoost особенно ценным в задачах, где
преобладают категориальные переменные или когда требуется минимальная
предварительная обработка данных. Кроме того, CatBoost показывает устойчивые
результаты на относительно небольших выборках и обладает эффективной
реализацией для GPU-ускорения. XGBoost (eXtremeGradientBoosting) сохраняет
лидирующие позиции в задачах, требующих максимальной предсказательной точности.
Его ключевое преимущество заключается в комплексной системе регуляризации,
включающей L1 (лассо) и L2 (ридж) нормализацию, что значительно снижает риск
переобучения. Алгоритм поддерживает различные виды целевых функций и
обеспечивает превосходную масштабируемость через механизмы распределенных
вычислений. Однако стоит отметить, что XGBoost требует более тщательной
подготовки категориальных признаков по сравнению с CatBoost. LightGBM (Light
GradientBoosting Machine) оптимизирован для обработки крупномасштабных данных.
В его основе лежат два ключевых алгоритмических усовершенствования:
Gradient-based One-Side Sampling (GOSS) для эффективного отбора объектов и
ExclusiveFeatureBundling (EFB) для оптимального использования признакового
пространства. Эти инновации позволяют LightGBM значительно превосходить
конкурентов по скорости обучения при работе с большими объемами данных, хотя
это может сопровождаться несколько меньшей устойчивостью на малых выборках.
Ниже представлен пример реализации решения с использованием
градиентного бустингаXGBoost [Листинг
5].
Опишем далее реализацию решения. Начнем с вычисляемых свойств. Свойство count,
общее количество нажатий,свойство важно, так как разные mode могут иметь разную
активность. Выполняется нормализация по общему количеству,свойству count, это делает
признаки сравнимыми между сессиями разной длины.Свойство unique_buttons,
количество уникальных кнопок, показывает разнообразие взаимодействия.
Происходит динамическое вычисление свойств для каждой кнопки, button_X_freq,что
позволяет модели выявлять важные комбинации. Вычисляются также такие свойства
как среднее, mean, общий темп взаимодействия, стандартное отклонение, std,
неравномерность активности, экстремальные значения, max и min, показывает
выбросы в поведении, медиана ,median, это устойчивая к выбросам оценка темпа.
Свойство rapid_clicks как и в других решениях определяет поведенческий паттерн
частых кликов. В предобработке данных
происходит постепенное накопление признаков через pd.concat, это эффективнее
чем предварительное создание массива, параметр ignore_index равный True
гарантирует последовательную нумерацию, а операция fillna(0) обрабатывает
случаи с одним нажатием, когда временные разницы не вычисляются. Опишем
параметры модели. Параметр n_estimators равен 100, это дает баланс между
временем обучения и качеством. Параметр max_depth равный 5 предотвращает
переобучение при сохранении выразительности. Параметр subsample и
colsample_bytree дают дополнительную регуляризацию. Параметр eval_metric равный
'logloss' оптимален для бинарной классификации.
Листинг 5- Реализация решения с применением XGBoost.
|
import
time
import tracemalloc
import numpyas np
import pandas as pd
from sklearn.metricsimport classification_report
from sklearn.model_selectionimport train_test_split
from xgboostimport XGBClassifier
from device_input.device_log_loaderimport load_device_logs
# Функциядляизвлеченияпризнаковизсырыхданных
def extract_features(data):
"""ПреобразуетсырыеданныевDataFrameспризнаками"""
features = {
'count': len(data), # Общееколичествонажатий
'unique_buttons': len(set(d['buttonKey'] for din data)), # Уникальныекнопки
}
# Частотныепризнакидлякнопок
button_counts= {}
for din data:
button = d['buttonKey']
button_counts[button] = button_counts.get(button, 0) + 1
# Временныехарактеристики
timestamps = [d['dateTime'] for din data]
# Use timestamps directly
timestamps.sort()
if len(timestamps) >1:
time_diffs= [timestamps[i+ 1] - timestamps[i]
for iin range(len(timestamps) - 1)]
features.update({
'time_mean': np.mean(time_diffs),
'time_std': np.std(time_diffs),
'time_max': max(time_diffs),
'time_min': min(time_diffs),
'time_median': np.median(time_diffs)
})
features['rapid_clicks'] = sum(1 for diff in time_diffsif diff <2)
else:
# Default values when not enough
timestamps
features.update({
'time_mean': 0,
'time_std': 0,
'time_max': 0,
'time_min': 0,
'time_median': 0,
'rapid_clicks': 0
})
return pd.DataFrame([features])
# Подготовкадатасета
def prepare_dataset(json_data):
"""Преобразуетмассив JSON объектоввобучающийдатасет"""
X = pd.DataFrame()
y = []
for item in json_data:
features = extract_features(item['list'])
X = pd.concat([X, features], ignore_index=True)
y.append(item['mode'])
# Заполнениепропусков (есливременныепризнакиотсутствуют)
X = X.fillna(0)
return X, np.array(y)
# Обучениемодели
def train_xgboost_model(X_train, y_train):
"""ОбучаетклассификаторXGBoost"""
# Инициализациямодели
model = XGBClassifier(
n_estimators=100,
max_depth=5,
learning_rate=0.1,
subsample=0.8,
colsample_bytree=0.8,
random_state=42,
eval_metric='logloss'
)
# Обучение
model.fit(X_train, y_train)
return model
# Примериспользования
if __name__ == "__main__":
# Примервходныхданных
sample_data = load_device_logs(1000)
# Подготовкаданных
X, y = prepare_dataset(sample_data)
print("Извлеченныепризнаки:\n", X.head())
# Разделениенаобучающуюитестовуювыборки
X_train, X_test, y_train, y_test =
train_test_split(
X, y, test_size=0.2, random_state=42)
# Измерениеиспользованияпамятидо
tracemalloc.start()
start_train = time.time()
# Обучениемодели
model = train_xgboost_model(X_train,
y_train)
end_train = time.time()
training_time = end_train - start_train
# Измерениепамятипослеобучения
current, peak = tracemalloc.get_traced_memory()
max_ram_usage = peak / (1024 ** 2) # в MB
tracemalloc.stop()
# Оценка
start_inf = time.time()
y_pred = model.predict(X_test)
end_inf = time.time()
inference_time = end_inf - start_inf
print(classification_report(y_test, y_pred))
print(f"Max RAM Usage: {max_ram_usage:.2f} MB")
print(f"Inference time: {inference_time:.4f} s")
|
ОценкаэффективностирешениясприменениемXGBoostпредставленаниже [Рисунок4].
Рисунок4 - СкриншототчетаизмеренияэффективностирешениясприменениемXGBoost.
Графовыенейронныесети (GNN – graphneuralnetworks). Графовыенейронныесети (GNN) демонстрируютвысокуюэффективностьвзадачах, гдеданныеобладаютструктурнымизависимостями. Вданномслучае, еслимеждуэлементамисписка list существуютнеявныесвязи, такиекаквременныезакономерности (dateTime) илисемантическиевзаимовлияния (buttonKey), GNNспособнывыявлятьэтивзаимосвязиблагодарясвоейархитектуре, ориентированнойнаобработкуграфов. Например, есликлассификация mode зависитотпоследовательностивзаимодействийиливременныхинтерваловмеждусобытиями, GNNмогутсмоделироватьтакиезависимостизасчетагрегацииинформацииотсоседнихузловграфа.
Крометого, GNNавтоматически
извлекают значимые признаки, устраняя необходимость ручного конструирования
фичей, что особенно полезно при наличии сложных нелинейных зависимостей.
Современные архитектуры, такие как GraphSAGE или GAT (GraphAttention Networks),
обеспечивают масштабируемость, позволяя обрабатывать списки переменной длины и
адаптироваться к динамическим данным.
Однако применение GNN может оказаться избыточным, если
элементы в list статистически независимы или если целевая переменная mode определяется
простыми агрегированными показателями, такими как частота появления
определенных buttonKey. В таком случае, более простые методы, такие как
логистическая регрессия или ансамбли деревьев решений, могут продемонстрировать
сопоставимую точность при меньших вычислительных затратах.Еще одним
ограничением является требовательность GNN к объему обучающих данных. При
недостаточном количестве размеченных примеров возникает риск переобучения или
неустойчивости модели. Кроме того, интерпретируемость решений, принимаемых GNN,
остается низкой по сравнению с традиционными ML-моделями, что может быть
критично в сценариях, требующих объяснимости.Сложность также представляет
корректное определение топологии графа. Если связи между элементами списка
неочевидны или отсутствуют, производительность GNN может оказаться не выше, чем
у базовых методов. Использование GNN оправдано при наличии обоснованной
гипотезы о графовой природе данных, обоснований же о графовой природе данных
нет за исключением порядка нажатия кнопок устройств ввода вне зависимости от
точной даты и времени.
Ниже представлен пример реализации решения с
использованием GNN [Листинг
6]. Опишем решение. Каждое событие в списке становится
узлом графа с тремя признаками. Признак buttonKey, это идентификатор
кнопки,нормализованный. Признак delta_time, это время между текущим и
предыдущим событием в секундах. Признак normalized_ts, это время от начала
последовательности, нормализованное. Опишем вычисленные из узлов признаки.
Признак buttonKey, это прямая информация о действии пользователя. Признак
delta_time, нужен когда временные паттерны могут быть важны, например, при
быстрых и медленных последовательностях нажатий. Признак normalized_ts дает учет
абсолютного времени внутри последовательности. Опишем топологию графа модели.
Используется полносвязный граф, т.к. благодаря этому модель может выявить любые
зависимости между событиями, но при этом вычислительно затратно для длинных
последовательностей. В случае если mode зависит от глобальных паттернов, например,
комбинаций кнопок, что вполне вероятно, тогда полносвязный граф
предпочтительнее, поэтому выбрана такая топология. Опишем архитектуру графа.
Выбрана архитектура GCN, потому что это базовая и хорошо изученная архитектура
и она хорошо работает даже на небольших графах. Используется 2 слоя GCN, потому что 1 слой скорее приведет к недообучению, а 3 и более
дают риск переобучения. Операция global_mean_pool объединяет информацию со всех
узлов.Бинарная кросс-энтропия, BCELoss, используется для классификации. Функция выходного сигнала сигмоида
для получения вероятности класса 1, а не softmax, т.к. она используется для
многоклассовой классификации, когда классов больше чем 2.
Листинг 6 - Пример реализации решения с
применением GNN.
|
import
time
import tracemalloc
import torch
import torch.nnas nn
import torch.nn.functionalas F
from sklearn.metricsimport classification_report
from sklearn.model_selectionimport train_test_split
from tensorflow.python.data.util.nestimport flatten
from torch_geometric.dataimport Data, DataLoader
from torch_geometric.nnimport GCNConv, global_mean_pool
from device_input.device_log_loaderimport load_device_logs
class EventGNN(nn.Module):
def __init__(self, hidden_channels=64):
super(EventGNN, self).__init__()
# Учитываем 3 признаканаузел: buttonKey, временныедельты, нормализованный timestamp
self.node_encoder = nn.Linear(3, hidden_channels)
# Дваслоя GCN сактивациейReLU
self.conv1 = GCNConv(hidden_channels, hidden_channels)
self.conv2 = GCNConv(hidden_channels, hidden_channels)
# Классификатор
self.classifier = nn.Sequential(
nn.Linear(hidden_channels, hidden_channels),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(hidden_channels, 1)
)
def forward(self, x, edge_index, batch):
# Проходчерез GNN
x = self.node_encoder(x)
x = F.relu(self.conv1(x, edge_index))
x = F.relu(self.conv2(x, edge_index))
# Глобальныйпулингдляполучения graph-level представления
x = global_mean_pool(x, batch)
# Классификация
return torch.sigmoid(self.classifier(x)).squeeze(1)
def prepare_graph_data(sequences, labels):
data_list= []
for seq, label in zip(sequences, labels):
# Извлекаем features
button_keys= torch.tensor([e['buttonKey'] for e in seq], dtype=torch.float)
timestamps = [e['dateTime'] for e in seq]
deltas = torch.tensor([(timestamps[i] - timestamps[i- 1])
if i>0 else 0 for iin range(len(seq))], dtype=torch.float)
normalized_ts= torch.tensor([(ts- timestamps[0]) for tsin timestamps], dtype=torch.float)
# Собираем node features
x = torch.stack([button_keys, deltas, normalized_ts], dim=1)
# Строимполносвязныйграф (можноизменитьнадругуютопологию)
num_nodes= len(seq)
edge_index= torch.tensor([[i, j] for iin range(num_nodes)
for j in range(num_nodes) if i!= j], dtype=torch.long).t()
# Создаемобъект Data
data= Data(x=x, edge_index=edge_index, y=torch.tensor([label], dtype=torch.float))
data_list.append(data)
return data_list
# Примериспользования
if __name__ == "__main__":
sample_data = load_device_logs(10)
# Подготовкаданных
X = [item['list'] for item in sample_data]
y = [item['mode'] for item in sample_data]
graph_data = prepare_graph_data(X, y)
# Разделениена train/test
train_data, test_data =
train_test_split(graph_data, test_size=0.2, random_state=42)
train_loader = DataLoader(train_data, batch_size=2, shuffle=True)
test_loader = DataLoader(test_data, batch_size=2)
# Инициализациямодели
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = EventGNN().to(device)
optimizer =
torch.optim.Adam(model.parameters(), lr=0.001)
criterion = nn.BCELoss()
# Измерениеиспользованияпамятидообучения
tracemalloc.start()
start_train = time.time()
# Обучение
for epoch in range(10):
model.train()
total_loss = 0
for data in train_loader:
data = data.to(device)
optimizer.zero_grad()
out = model(data.x,
data.edge_index, data.batch)
loss = criterion(out,
data.y)
loss.backward()
optimizer.step()
total_loss += loss.item()
# Валидация
model.eval()
correct = 0
for data in test_loader:
data = data.to(device)
pred = (model(data.x,
data.edge_index, data.batch) >0.5).float()
correct += (pred ==
data.y).sum().item()
acc = correct / len(test_data)
print(f'Epoch{epoch}, Loss: {total_loss:.4f}, Test Acc: {acc:.4f}')
end_train = time.time()
training_time = end_train - start_train
# Измерениепамятипослеобучения
current, peak =
tracemalloc.get_traced_memory()
max_ram_usage = peak / (1024 ** 2) # в MB
y_pred = []
inference_time = 0
tracemalloc.stop()
with torch.no_grad():
start_inf = time.time()
for data in test_loader:
data = data.to(device)
pred = (model(data.x, data.edge_index,
data.batch) >0.5).float()
y_pred.extend(pred.cpu().numpy())
end_inf = time.time()
inference_time = end_inf - start_inf
y_test = (list(data.y) for data in test_loader)
y_test = [
x
for xsin y_test
for x in xs
]
print(classification_report(y_test, y_pred))
print(f"Max RAM Usage: {max_ram_usage:.2f} MB")
print(f"Inference time: {inference_time:.4f} s")
|
ОценкаэффективностирешениясприменениемGNN [Рисунок5].
Рисунок5 - Скриншотрезультатаизмерения
эффективности решения с применением GNN.
Свёрточнаянейроннаясеть
(CNN - convolutional neural network). Демонстрируютвысокуюэффективностьвзадачахавтоматическогораспознавания
паттернов, что может быть полезно при классификации mode на основе
последовательностей buttonKey и dateTime. Однако их применение
должно быть обосновано структурой данных и характером зависимостей. CNN способны
автоматически извлекать пространственные и временные признаки из
структурированных данных без явного featureengineering. Если зависимость
между mode и последовательностью list определяется
комбинаторными или локальными временными паттернами (например, определенные
сочетания buttonKey или характерные интервалы между событиями),
сверточные слои могут эффективно их детектировать. Кроме того, CNN обладают
устойчивостью к зашумленным данным за счет механизма фильтрации признаков через
ядра свертки. При соответствующей предобработке данные могут быть преобразованы
в тензорную форму, например, в виде матрицы, где строки соответствуют событиям,
а столбцы — признакам (buttonKey, временные дельты и др.). В таком случае
1D-свертки способны анализировать последовательности, а 2D-архитектура —
выявлять более сложные пространственно-временные корреляции.
Однако CNN не всегда являются оптимальным решением. Если
классификация mode зависит от простых правил (например, наличия
конкретного buttonKey в list), то избыточная параметризация CNN
приведет к переобучению, и более эффективными окажутся классические модели,
описанные ранее.Еще одним ограничением является обработка данных переменной
длины. В отличие от рекуррентных архитектур (LSTM, GRU), CNN требуют
фиксированного размера входа, что вынуждает применять паддинг или сегментацию,
что может исказить исходные временные зависимости, это вносит ограничение в
виде отрезков, в рамках которых происходит классификация, что не является
критичным для нашей работы. Кроме того, CNN хуже справляются с долгосрочными
временными связями, поскольку их рецептивное поле ограничено размером ядра
свертки. Предварительный анализ данных показывает наличие сложных нелинейных
паттернов, CNN может быть оправдан, особенно при большом объеме данных. Однако
зависимость между list и mode может определяться и
глобальными временными тенденциями, поэтому может быть предпочтительнее
использовать рекуррентные сети.
Ниже представлен пример реализации решения с использованием
CNN [Листинг 7].Опишем данное решение. Начнем с
предобработки. Последовательности имеют разную длину, фиксированная длина
требуется для работы CNN в Keras, поэтому произведем дополнение нулями, padding,
до фиксированной длины, max_sequence_length, нулевое дополнение выбрано как
простейший метод. Временные метки в строковом формате, поэтому произведем преобразование
в datetime и произведем вычисление временных дельт между событиями. Опишем
архитектуру сети. Использованы 1D-свертки, а не 2D или 3D, потому что данные
представляют собой временные последовательности и каждый временной шаг содержит
2 признака, это номер кнопки и временная дельта. Параметры сверточных слое
выбраны таким образом, что увеличение количества фильтров, сначала 64 потом 128
потом 256, позволяет выявлять сначала простые, затем сложные паттерны, параметр
kernel_size равен 3 потому что это оптимально для анализа локальных
последовательностей, padding равен 'same' что сохраняет длину последовательности.
Применяется BatchNormalization, потому что это стабилизирует обучение и
позволяет использовать более высокую частоту обучения. Применяется
GlobalAveragePooling1D вместо Flatten, потому что это уменьшает количество
параметров и этот вариант имеет лучшую обобщающую способность. Применяется Dropout
0.5 в первом Dense-слое как стандартное значение, 0.3 во втором для баланса
между регуляризацией и сохранением информации. Опишем подход к обучению.
Применяется оптимизатор Adam т.к. он дает автоматическую адаптация частоты
обучения и хорошо работает по умолчанию. Выбрана функция потерь
binary_crossentropy потому что это стандартный выбор для бинарной
классификации, альтернативой является focal_loss для несбалансированных данных,
однако мы можем сбалансировать данные иными способами. Для подбора
гиперпараметровиспольуются метрики Accuracy, т.к. это интуитивно понятная
метрика и AUC, потому что он лучше отражает качество на несбалансированных
данных. Выбрано 20 эпох что является разумным компромиссом между временем
обучения и качеством. А Batchsize равен 32 т.к. это стандартное значение для
средних наборов данных.
Листинг 7- Решение с применением CNN.
|
import
time
import tracemalloc
import numpyas np
import pandas as pd
import tensorflowas tf
from sklearn.metricsimport classification_report
from sklearn.model_selectionimport train_test_split
from sklearn.preprocessingimport StandardScaler
from tensorflow.kerasimport layers, models
from device_input.device_log_loaderimport load_device_logs
# 1. Предобработкаданных
def preprocess_data(data, max_sequence_length=100):
"""
Преобразуетсырыеданныевформат, пригодныйдляобучения CNN.
Args:
data: Списоксловарейвформате {'mode': int, 'list': [{'buttonKey': int,
'dateTime': str}]}
max_sequence_length: Максимальнаядлинапоследовательности (дополняетсянулями)
Returns:
X: Тензорформы (n_samples, max_sequence_length, n_features)
y: Массивметок
"""
X = []
y = []
for item in data:
# Извлекаемметку
y.append(item['mode'])
sequence = item['list']
features = []
# Обрабатываемкаждоесобытиевпоследовательности
for i, event in enumerate(sequence):
if i>= max_sequence_length:
break
# Извлекаемпризнакиизкаждогособытия
button_key= event['buttonKey']
timestamp = pd.to_datetime(event['dateTime'])
# Вычисляемвременнуюразницуспредыдущимсобытием
if i>0:
prev_time= pd.to_datetime(sequence[i- 1]['dateTime'])
time_diff= (timestamp - prev_time).total_seconds()
else:
time_diff= 0.0
features.append([button_key, time_diff])
# Дополняемпоследовательностьнулями, еслионакорочеmax_sequence_length
while len(features) <max_sequence_length:
features.append([0, 0.0])
X.append(features)
return np.array(X), np.array(y)
# 2. Создание
модели CNN
defcreate_cnn_model(input_shape, num_classes=1):
"""
Создает модель CNN для обработки
временных последовательностей.
Args:
input_shape: Форма входных данных (max_sequence_length, n_features)
num_classes: Количество классов (1 для бинарной классификации)
Returns:
Модель Keras
"""
model= models.Sequential([
#
Нормализация входных данных
layers.BatchNormalization(input_shape=input_shape),
#
Первый сверточный блок
layers.Conv1D(64, kernel_size=3, activation='relu', padding='same'),
layers.BatchNormalization(),
layers.MaxPooling1D(pool_size=2),
#
Второй сверточный блок
layers.Conv1D(128, kernel_size=3, activation='relu', padding='same'),
layers.BatchNormalization(),
layers.MaxPooling1D(pool_size=2),
#
Третий сверточный блок
layers.Conv1D(256, kernel_size=3, activation='relu', padding='same'),
layers.BatchNormalization(),
layers.GlobalAveragePooling1D(),
#
Полносвязные слои
layers.Dense(128, activation='relu'),
layers.Dropout(0.5),
layers.Dense(64, activation='relu'),
layers.Dropout(0.3),
#
Выходной слой
layers.Dense(num_classes, activation='sigmoid')
])
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy',
tf.keras.metrics.AUC()]
)
returnmodel
#
3. Обучение модели
deftrain_model(X, y, epochs=20, batch_size=32):
"""
Обучает модель CNN на
предоставленных данных.
Args:
X: Входные данные
y: Метки
epochs: Количество эпох обучения
batch_size: Размер батча
Returns:
Обученная модель и история
обучения
"""
# Создание модели
model= create_cnn_model(input_shape=X.shape[1:])
#
Обучение модели
history= model.fit(
X, y,
validation_data=(X_test,
y_test),
epochs=epochs,
batch_size=batch_size,
verbose=1
)
returnmodel, history
#
Пример использования
if__name__ == "__main__":
sample_data = load_device_logs(1000)
#
Предобработка данных
X, y = preprocess_data(sample_data, max_sequence_length=50)
#
Разделение данных на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
#
Нормализация данных
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train.reshape(-1,
X_train.shape[-1])).reshape(X_train.shape)
X_test = scaler.transform(X_test.reshape(-1, X_test.shape[-1])).reshape(X_test.shape)
#
Измерение использования памяти до обучения
tracemalloc.start()
start_train = time.time()
#
Обучение модели
model, history = train_model(X_train, y_train, epochs=10)
end_train = time.time()
training_time = end_train - start_train
#
Измерение памяти после обучения
current, peak = tracemalloc.get_traced_memory()
max_ram_usage = peak / (1024 ** 2) # в MB
tracemalloc.stop()
#
Сохранение модели
model.save("button_sequence_classifier.h5")
#
Оценка качества
start_inf = time.time()
y_pred = model.predict(X_test) # вызывать
predict для отдельных строк
end_inf = time.time()
inference_time = end_inf - start_inf
y_pred = [round(num) forsublistiny_predfornuminsublist]
print(classification_report(y_test,
y_pred))
print(f"Max
RAM Usage: {max_ram_usage:.2f} MB")
print(f"Inferencetime:
{inference_time:.4f} s")
|
Оценка эффективности решения с применением CNN [Рисунок 6].
Рисунок 6- Скриншот измерения эффективности
решения с применением CNN.
LSTM (Long Short-Term Memory) демонстрирует высокую
эффективность при обработке последовательностей данных, таких как временные
ряды или событийные логгирования, благодаря своей архитектуре, способной
улавливать долгосрочные зависимости. В контексте задачи классификации mode на
основе последовательности buttonKey и соответствующих временных
меток dateTime, ключевым преимуществом LSTM является его способность
автоматически выявлять сложные паттерны без необходимости ручного
конструирования признаков. Это особенно важно, если зависимость между
последовательностью событий и целевой переменной нелинейна или включает скрытые
временные корреляции.Кроме того, LSTM обладает устойчивостью к проблеме
исчезающих градиентов, что позволяет эффективно обучаться на длинных
последовательностях. Модель способна обрабатывать входные данные переменной
длины, что делает её гибкой в условиях нефиксированного размера list. При
наличии достаточного объёма размеченных данных LSTM может достичь высокой
точности, превосходя традиционные алгоритмы машинного обучения, особенно в
задачах, где временная динамика играет ключевую роль.
Однако применение LSTM сопряжено с рядом ограничений.
Основным из них является высокая вычислительная сложность обучения, требующая
значительных ресурсов, включая использование GPU или TPU для ускорения
процесса. Это делает LSTM менее предпочтительным в условиях ограниченных
вычислительных мощностей или необходимости быстрого инференса.Другим
существенным недостатком является требование к большому объёму обучающих
данных. При недостаточном количестве примеров модель склонна к переобучению,
что приводит к плохой обобщающей способности. Кроме того, интерпретируемость
LSTM остаётся низкой: внутренние механизмы работы модели представляют собой
"чёрный ящик", что затрудняет анализ принятия решений и делает её
менее применимой в областях, где требуется объяснимость.
Ниже представлен пример реализации решения с использованием
RNN-LSTM [Листинг
8].Опишем данное решение. Как и в предыдущем решении с
применением нейронных сетей мы масштабируем данные и приводим их к необходимому
виду, используем MinMaxScaler, pad_sequences. Опишем слои сети. Входной Masking
игнорирует нулевые дополнения ,mask_value равен 0. , чтобы модель не
обрабатывала "пустые" события, добавленные при паддинге, и без
Maskingсеть училась бы на нулевых значениях, что снижает качество
классификации. Далее идет один LSTM-слой в 64 узла, в котором return_sequences
равен False, он возвращает только последний выход последовательности потому что
задачей стоит бинарная классификация всей последовательности,modeравен 0 или 1,
а не прогноз для каждого шага. Выбран размер в 64 нейрона, потому что это
компромисс между скоростью и способностью улавливать сложные паттерны. Применяется
Dropout (0.2), это регуляризация для предотвращения переобучения, значение 0.2
выбрано эмпирически. Выходной слой это Dense с sigmoid, функция активации
sigmoid выбрана по той же причине что и в решении с нейронной сетью выше,
оптимизатор функция потерь, метрики, размер батча, количество эпох подобрано по
тем же соображениям что и ранее.
Листинг 8 - Пример реализации решения с
применением RNN-LSTM.
|
import
time
import tracemalloc
import numpyas np
from sklearn.metricsimport classification_report
from sklearn.model_selectionimport train_test_split
from sklearn.preprocessingimport MinMaxScaler
from tensorflow.keras.layersimport LSTM, Dense, Masking, Dropout
from tensorflow.keras.modelsimport Sequential
from tensorflow.keras.optimizersimport
Adam
from tensorflow.keras.preprocessing.sequenceimport pad_sequences
from device_input.device_log_loaderimport load_device_logs
def prepare_dataset(json_data):
"""Подготавливаетдатасетизсырых JSON данных"""
X = []
y = []
for item in json_data:
# Извлекаемцелевойпризнак
y.append(item['mode'])
# Извлекаемпризнакиизспискасобытий
X.append(item['list'])
return X, y
# Преобразованиеданныхвnumpy-массивы
def prepare_data(X, y):
# ИзвлекаемbuttonKeyиdateTimeизкаждойпоследовательности
X_processed= []
for seq in X:
seq_data= []
for event in seq:
seq_data.append([event['buttonKey'], event['dateTime']])
X_processed.append(seq_data)
# Приводимкnumpyинормализуем
X_processed= np.array(X_processed, dtype='float32')
scaler = MinMaxScaler()
X_reshaped= X_processed.reshape(-1, 2) # Объединяемвсесобытиядлянормализации
X_scaled= scaler.fit_transform(X_reshaped)
X_scaled= X_scaled.reshape(X_processed.shape) # Возвращаемисходнуюструктуру
# Дополняемпоследовательностидоодинаковойдлины (еслинужно)
max_len= max(len(seq) for seq in X)
X_padded= pad_sequences(X_scaled, maxlen=max_len, padding='post', dtype='float32')
y = np.array(y, dtype='float32')
return X_padded, y
# Примериспользования
if __name__ == "__main__":
sample_data = load_device_logs(1000)
X, y = prepare_dataset(sample_data)
X_prepared, y_prepared = prepare_data(X, y)
# Разделениена train/test
X_train, X_test, y_train, y_test =
train_test_split(X_prepared, y_prepared, test_size=0.2, random_state=42)
# Созданиемодели LSTM
model = Sequential([
Masking(mask_value=0., input_shape=(X_train.shape[1],
X_train.shape[2])), # Игнорируетнулевоедополнение
LSTM(64, activation='tanh', return_sequences=False),
Dropout(0.2),
Dense(1, activation='sigmoid') # Бинарнаяклассификация
])
model.compile(
optimizer=Adam(learning_rate=0.001),
loss='binary_crossentropy',
metrics=['accuracy']
)
# Измерениеиспользованияпамятидообучения
tracemalloc.start()
start_train = time.time()
# Обучение
history = model.fit(
X_train, y_train,
validation_data=(X_test, y_test),
epochs=20,
batch_size=32
)
end_train = time.time()
training_time = end_train - start_train
# Измерениепамятипослеобучения
current, peak =
tracemalloc.get_traced_memory()
max_ram_usage = peak / (1024 ** 2) # в MB
tracemalloc.stop()
# Оценкакачества
start_inf = time.time()
y_pred = model.predict(X_test)
end_inf = time.time()
inference_time = end_inf - start_inf
y_pred = [round(num) for sublistin y_predfor num in sublist]
print(classification_report(y_test, y_pred))
print(f"Max RAM Usage: {max_ram_usage:.2f} MB")
print(f"Inference time: {inference_time:.4f} s")
|
Оценка эффективности решения с применением RNN-LSTM [Рисунок 7].
Рисунок 7 - Скриншот результата измерения
эффективности решения с применением RNN-LSTM.
GatedRecurrent Unit (GRU) является эффективной
архитектурой рекуррентных нейронных сетей (RNN) для обработки последовательных
данных с временными зависимостями. В контексте задачи
классификации mode на основе временного ряда нажатий кнопок
(buttonKey) и соответствующих временных меток (dateTime), GRU демонстрирует ряд
преимуществ.Во-первых, благодаря наличию механизмов управляемых ворот
(updategate и resetgate), GRU способна выявлять долгосрочные зависимости в
данных, что критически важно для корректной классификации, если целевой
признак mode зависит от порядка или временных интервалов между
событиями. Во-вторых, по сравнению с Long Short-Term Memory (LSTM), GRU
обладает меньшим количеством обучаемых параметров, что снижает риск
переобучения при ограниченном объеме данных. В-третьих, модель автоматически
извлекает значимые признаки из сырых последовательностей, устраняя
необходимость ручного конструирования фичей, таких как статистические агрегаты
или временные дельты.
Несмотря на преимущества, применение GRU сопряжено с рядом
ограничений. Основной проблемой является высокая чувствительность к объему
обучающих данных: при недостаточном количестве примеров модель склонна к
переобучению, особенно если временные зависимости слабо выражены или
нерелевантны для классификации. Кроме того, интерпретируемость GRU остается
низкой из-за ее "черного ящика", что затрудняет анализ значимости
отдельных временных шагов или признаков.С точки зрения предобработки данных,
GRU требует тщательной нормализации временных меток (например, преобразования в
относительные интервалы) и корректного представления категориальных признаков
(например, использования embedding слоев для buttonKey). Вычислительная
сложность обучения также выше по сравнению с традиционными методами машинного
обучения, такими как ансамбли деревьев, что может быть критично в условиях
ограниченных ресурсов.
Ниже представлен пример реализации решения с использованием
RNN-GRU [Листинг
9].
Листинг 9- Реализация решения с применением RNN-GRU.
|
import
time
import tracemalloc
from datetime import datetime
import numpyas np
import tensorflowas tf
from sklearn.metricsimport classification_report
from sklearn.model_selectionimport train_test_split
from tensorflow.keras.layersimport (GRU, Dense, Dropout, Embedding,
Masking, Lambda, Concatenate, Reshape, Input)
from tensorflow.keras.modelsimport Model
from tensorflow.keras.optimizersimport
Adam
from tensorflow.keras.preprocessing.sequenceimport pad_sequences
from device_input.device_log_loaderimport load_device_logs
def prepare_dataset(json_data):
"""Подготавливаетдатасетизсырых JSON данных"""
X = []
y = []
for item in json_data:
# Извлекаемцелевойпризнак
y.append(item['mode'])
# Извлекаемпризнакиизспискасобытий
X.append(item['list'])
return X, y
class GRUClassifier:
def __init__(self, max_sequence_length=100, num_button_keys=100):
self.max_sequence_length = max_sequence_length
self.num_button_keys = num_button_keys
self.model = self._build_model()
def _build_model(self):
"""Построениеархитектурымоделисисправленнойобработкойтиповданных"""
# Входнойслой
input_layer= Input(shape=(self.max_sequence_length, 2))
# Маскировка
masked = Masking(mask_value=0.)(input_layer)
# Разделениевходныхданных
button_key= Lambda(lambda x: x[:, :, 0])(masked)
time_delta= Lambda(lambda x: x[:, :, 1])(masked)
# ПреобразованиеbuttonKeyвцелочисленныйтип
button_key_int= Lambda(lambda x: tf.cast(x,
'int32'))(button_key)
# Embedding слойсявнымуказаниемтипа
embedded = Embedding(
input_dim=self.num_button_keys + 1,
output_dim=16,
input_length=self.max_sequence_length,
mask_zero=True
)(button_key_int)
# Обработкавременныхметок
time_processed= Reshape((self.max_sequence_length, 1))(time_delta)
# Объединениепризнаков
concatenated = Concatenate(axis=-1)([embedded, time_processed])
# GRU слои
gru1 = GRU(64, return_sequences=True, dropout=0.2, recurrent_dropout=0.2)(concatenated)
gru2 = GRU(32, dropout=0.2, recurrent_dropout=0.2)(gru1)
# Полносвязныеслои
dense1 = Dense(32, activation='relu')(gru2)
dropout = Dropout(0.5)(dense1)
output = Dense(1, activation='sigmoid')(dropout)
model = Model(inputs=input_layer, outputs=output)
model.compile(
optimizer=Adam(learning_rate=0.001),
loss='binary_crossentropy',
metrics=['accuracy']
)
return model
def _preprocess_data(self, X_raw, y_raw):
"""Исправленнаяпредобработкаданныхсконтролемтипов"""
processed_sequences= []
for sequence in X_raw:
# Обработкавременныхметок
timestamps = [event['dateTime'] for event in sequence]
if isinstance(timestamps[0], str):
timestamps = [datetime.strptime(ts, '%Y-%m-%d
%H:%M:%S').timestamp() for tsin timestamps]
time_deltas= [0] + [timestamps[i] - timestamps[i- 1] for iin range(1, len(timestamps))]
max_delta= max(time_deltas) if max(time_deltas) >0 else 1
normalized_deltas= [delta / max_deltafor delta in time_deltas]
# ГарантируемцелочисленныйтипдляbuttonKey
sequence_features= [
[int(event['buttonKey']), float(normalized_deltas[i])]
for i, event in enumerate(sequence)
]
processed_sequences.append(sequence_features)
# Паддингсявнымуказаниемтипа float32
X_padded= pad_sequences(
processed_sequences,
maxlen=self.max_sequence_length,
dtype='float32',
padding='post',
truncating='post',
value=0.0
)
y_array= np.array(y_raw, dtype='float32')
return X_padded, y_array
# Остальныеметодыклассаостаютсябезизменений
def train(self, X_train, y_train, X_val=None, y_val=None, epochs=20, batch_size=32):
X_processed, y_processed= self._preprocess_data(X_train, y_train)
if X_valis not None:
X_val_processed, y_val_processed= self._preprocess_data(X_val, y_val)
validation_data= (X_val_processed, y_val_processed)
else:
validation_data= None
history = self.model.fit(
X_processed, y_processed,
validation_data=validation_data,
epochs=epochs,
batch_size=batch_size,
verbose=1
)
return history
def evaluate(self, X_test, y_test):
X_processed, y_processed= self._preprocess_data(X_test, y_test)
loss, accuracy = self.model.evaluate(X_processed, y_processed, verbose=0)
y_pred= (self.model.predict(X_processed) >0.5).astype("int32")
print(f"Test Accuracy: {accuracy:.4f}")
print(classification_report(y_processed, y_pred))
return y_pred
def predict(self, X_new):
X_processed, _ = self._preprocess_data(X_new, [0] * len(X_new))
return (self.model.predict(X_processed) >0.5).astype("int32")
# Примериспользования
if __name__ == "__main__":
sample_data = load_device_logs(1000)
X, y = prepare_dataset(sample_data)
# Разделениена train/test
X_train, X_test, y_train, y_test =
train_test_split(X, y, test_size=0.2, random_state=42)
# Измерениеиспользованияпамятидообучения
tracemalloc.start()
start_train = time.time()
# Инициализацияитестированиемодели
classifier = GRUClassifier(max_sequence_length=50, num_button_keys=80)
classifier.train(X_train, y_train, epochs=5)
end_train = time.time()
training_time = end_train - start_train
# Измерениепамятипослеобучения
current, peak =
tracemalloc.get_traced_memory()
max_ram_usage = peak / (1024 ** 2) # в MB
tracemalloc.stop()
# Оценкакачества
start_inf = time.time()
y_pred = classifier.predict(X_test)
end_inf = time.time()
inference_time = end_inf - start_inf
y_pred = [round(num) for sublistin y_predfor num in sublist]
print(classification_report(y_test, y_pred))
print(f"Max RAM Usage: {max_ram_usage:.2f} MB")
print(f"Inference time: {inference_time:.4f} s")
|
ОценкаэффективностирешениясприменениемRNN-GRU [Рисунок8].
Рисунок8 - СкриншотрезультатаизмеренияэффективностирешениясприменениемRNN-GRU.
Сделаемпромежуточныевыводыпомодулюоценкиданныхсустройстввводадляреализациифинальноговарианта
[Таблица1].Вданнойтаблицепредставленырезультатысравненияразличныхметодовмашинногообученияистатистическогоподходапоключевымметрикамклассификациидляцелевогопризнакаввидедвухклассов.
Рассматриваемыемоделивключаютстатистическийподход (базовыйметод), логистическуюрегрессию,
случайныйлес, графовыенейронныесети (GNN), сверточныенейронныесети (CNN), рекуррентныенейронныесети(RNN) сLSTMирекуррентныенейронныесетисGRU. Оценкакачествамоделейпроводиласьпотакимметрикам, какPrecision (точность), Recall (полнота), F1-score (гармоническоесреднееPrecisionиRecall), Support (количествообъектоввкаждомклассе), Accuracy (общаяточность), атакжеMacroAvgиWeightedAvg (усредненныезначенияPrecision, RecallиF1-score). Дополнительно приведены данные о максимальном
использовании оперативной памяти (RAM) и времени инференса (Inferencetime) для
каждой модели.Анализ данных показывает, что наивысшую точность (Accuracy =
0.90) демонстрируют три модели: случайный лес, CNN и RNN-LSTM. Логистическая
регрессия показывает средний результат (Accuracy = 0.70), в то время как GNN и
статистический подход работают на уровне случайного угадывания (Accuracy =
0.50). Наихудший результат у GRU (Accuracy = 0.30). По метрикам Precision, Recall
и F1-score также лидируют случайный лес, CNN и LSTM, показывая стабильно
высокие значения (F1-score для класса 0 составляет 0.89–0.93, для класса 1 —
0.80–0.86). При этом GNN полностью проваливается в предсказании класса 1
(Precision и Recall = 0.00), а GRU демонстрирует крайне низкий Precision для
класса 0 (0.00) и низкий F1-score для класса 1 (0.46).С точки зрения скорости
работы и потребления памяти случайный лес оказывается наиболее эффективным: он
самый быстрый (0.0040 с) и экономичный по RAM (0.21 МБ). Глубокие нейросети
(CNN, LSTM, GRU), напротив, требуют значительно больше памяти (14–24 МБ) и
работают медленнее (0.4–2.5 с). GNN, хотя и медленнее случайного леса (0.4063
с), показывает плохое качество предсказаний, что делает его применение нецелесообразным.Исходя из этих
данных, можно сделать вывод, что случайный лес является оптимальным выбором для
данной задачи, так как сочетает высокую точность с низкими вычислительными
затратами. CNN и LSTM могут быть полезны в случаях, когда важна максимальная точность,
несмотря на повышенные требования к ресурсам. Логистическая регрессия
представляет собой компромиссный вариант при ограниченных вычислительных
возможностях. В то же время GNN и GRU в данном контексте демонстрируют
неудовлетворительные результаты и не рекомендуются к использованию. Таким
образом, выбор модели зависит от конкретных требований к точности и доступным
ресурсам, но случайный лес выглядит наиболее сбалансированным решением.
Таблица 1- Сравнение результатов измерения
эффективности решений.
|
Метри-ка
|
Класс
|
Статисти-ческий
подход
|
Логисти-ческая
регрессия
|
Случай-ный лес
|
GNN
|
CNN
|
RNN-LSTM
|
RNN-GRU
|
|
Precision
|
0
|
0.00
|
0.90
|
0.86
|
0.50
|
0.88
|
0.88
|
0.00
|
|
1
|
0.50
|
0.50
|
1.00
|
0.00
|
1.00
|
1.00
|
0.30
|
|
Recall
|
0
|
0.00
|
0.64
|
1.00
|
1.00
|
1.00
|
1.00
|
0.00
|
|
1
|
1.00
|
0.83
|
0.75
|
0.00
|
0.67
|
0.67
|
1.00
|
|
F1-score
|
0
|
0.00
|
0.75
|
0.92
|
0.67
|
0.93
|
0.93
|
0.00
|
|
1
|
0.67
|
0.62
|
0.86
|
0.00
|
0.80
|
0.80
|
0.46
|
|
Support
|
0
|
50
|
14
|
18
|
14
|
14
|
14
|
14
|
50
|
6
|
12
|
6
|
6
|
6
|
6
|
|
Accuracy
|
-
|
0.50
|
0.70
|
0.90
|
0.50
|
0.90
|
0.90
|
0.30
|
|
Macro
Avg
|
Precision
|
0.25
|
0.70
|
0.93
|
0.25
|
0.94
|
0.94
|
0.15
|
|
Recall
|
0.50
|
0.74
|
0.88
|
0.50
|
0.83
|
0.83
|
0.50
|
|
F1-score
|
0.33
|
0.69
|
0.89
|
0.33
|
0.87
|
0.87
|
0.23
|
|
Weighted
Avg
|
Precision
|
0.25
|
0.78
|
0.91
|
0.25
|
0.91
|
0.91
|
0.09
|
|
Recall
|
0.50
|
0.70
|
0.90
|
0.50
|
0.90
|
0.90
|
0.30
|
|
F1-score
|
0.33
|
0.71
|
0.90
|
0.33
|
0.89
|
0.89
|
0.14
|
|
Max RAM
Usage
|
0.05
MB
|
0.92
MB
|
0.21
MB
|
0.24
MB
|
14.59
MB
|
23.77
MB
|
23.53 MB
|
|
Inference
time
|
0.0442
s
|
0.0160
s
|
0.0040
s
|
0.4063
s
|
0.4023
s
|
2.5004
s
|
1.3299 s
|
Перейдем к разработкеалгоритмамодуляоценкиактивностинаоснованиипереданныхсписковзапущенныхпроцессовнакомпьютере.
Нижепредставленамодельдляоценкиактивностипользователякомпьютера, котораяработаетстакимиданнымикак:
датаивремя, списокназванийзапущенныхпроцессов, меткавидаактивностипользователядляобучениямодели
[Листинг9].
Листинг10 – Кодмоделиоценкипоспискупроцессов
|
model
= Sequential()
amount_of_different_words
= (len(tokenizer.word_index) + 1)
model.add(
Embedding(input_dim=amount_of_different_words,
output_dim=amount_of_different_words, input_length=max_length))
model.add(LSTM(amount_of_different_words))
model.add(Dense(2,
activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='adam', metrics=['accuracy'])
|
Модель, представленная в коде, представляет собой
последовательную (Sequential) архитектуру искусственной нейронной сети, которая
включает в себя слой Embedding, слой LSTM (Long Short-Term Memory) и
полносвязный слой (Dense) с функцией активации softmax (Приложение 1). Данная архитектура предназначена для задач
классификации текстов, где на выходе ожидается два класса. Рассмотрим
достоинства, недостатки и области применения данной модели с точки зрения
машинного обучения, статистики и математики. Данную модель целесообразно
применять в задачах бинарной классификации текстов, где важны контекст и
порядок слов, в нашей ситуации мы имеем текст в виде набора текстовых названий
процессов, что может является аналогичным видом данных. Слой Embedding
позволяет преобразовать дискретные токены (слова) в плотные векторы
фиксированной размерности. Далее идет LSTM, это рекуррентная нейронная сеть
(RNN), которая способна запоминать долгосрочные зависимости в
последовательностях данных. Для нас контекст и порядок названий процессов
играют ключевую роль. LSTM эффективно справляется с проблемой исчезающего
градиента, что делает его предпочтительным выбором для работы с длинными
последовательностями. Но несмотря на то, что LSTM способен захватывать сложные
зависимости в данных, его внутренние механизмы трудно интерпретировать. Это
может быть недостатком в задачах, где важно понимать, как модель принимает
решения, в нашем случае это не является решающим фактором. Качество данной
модели сильно зависит от качества токенизации и предобработки текста. Например,
если текст содержит много шума или стоп-слов, это может негативно сказаться на
результатах, в нашем же случае такого фактора нет, так как все части данных
являются валидными. В модели идет использование функции активации softmax на
выходном слое, что позволяет интерпретировать выходы модели как вероятности
принадлежности к каждому из двух классов. Это подходит для нашей задачи
классификации, так как позволяет не только предсказать класс, но и оценить
уверенность модели в своем предсказании. Оптимизатор Adam сочетает в себе
преимущества методов адаптивной градиентной оптимизации (например, RMSprop) и
метода моментов. Это позволяет модели быстро сходиться и эффективно работать
даже на неоднородных данных. Adam также автоматически настраивает скорость
обучения, что упрощает процесс тренировки. Модель использует фиксированную
длину входных последовательностей (max_length), что может привести к потере
информации, если текст слишком длинный, или к избыточному заполнению нулями,
если текст слишком короткий. Выбор максимальной длина списка названий процессов
выбирается исходя из минимальной длины запущенных процессов, в предобработке
идет сортировка списка по загрузке процессора и иным косвенным признакам
использования, что позволяет иметь валидную часть списка для целевой работы с
ней.
Для ранее описанной модели используется предобработка
данных, в том числе токенизация названий процессов (Приложение 8). Результат токенизации сохраняется в отдельный
стойки источник информации, файл, что позволяет возвращаться к нему между
сессиями обучения модели. Новые уникальные слова дополняют словарь токенизации
что способствует более стабильной работе модели [Листинг 10].
Листинг 11 - Токенизация словаря названий
процессов
|
def process_tokenization(texts: [str],
filename='tokens_dictionary.json'):
# Загружаем или создаем
токенизатор
tokenizer = load_or_create_tokenizer()
# Обновляем токенизатор
новыми текстами
update_tokenizer(tokenizer, texts,
filename)
# Выводимтекущийсловарьтокенов
# print("Словарьтокенов:", tokenizer.word_index)
returntokenizer
|
Также для сбора данных используется скрипты для сбора списков
запущенных процессов и сбора данных с устройств ввода (Листинг 11,
Приложение
4, Приложение
5).
Листинг 12- Сбор данных с устройств ввода
|
def save_processes_to_file(dir_to_logs,
is_working_mode_target_value):
processes = []
processes_seen = set() #
Use a set to track seen (name, pid) tuples.
for p in
psutil.process_iter(attrs=['name', 'pid', 'cpu_percent']):
if hasattr(p,'info'):
try:
# Получаем нагрузку на CPU
p.cpu_percent(interval=0) # Для
получения текущего значения в будущем
if p.info['name'] not in processes_seen:
processes_seen.add(p.info['name']) # Mark
this process as seen
processes.append((p.info['name'], p.info['pid'],
p.cpu_percent(interval=0)))
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
#
Сортируем процессы по нагрузке на CPU и по id процесса в порядке убывания
sorted_processes =
sorted(processes, key=lambda x: (x[2], x[1]), reverse=True)
Рисунок 3- Сбор данных о
запущенных процессах
def log_event(button_key, is_working_mode):
timestamp = datetime.now().isoformat()
# Беремтекущеевремя
log_entry = {
"timestamp": timestamp,
"buttonKey": button_key,
"isWorkingMode": is_working_mode
}
logs.append(log_entry)
with open('device_logs.json',
'w', encoding='utf-8') as f:
json.dump(logs,
f, indent=4)
|
Далее рассмотрим модель для работы с собранными данными с устройств
ввода, такими как клавиатура и мышь (Error! Referencesourcenotfound.).
Листинг 13 – Код модели оценки по данным
с устройств ввода
|
model = RandomForestClassifier()
model.fit(X_train, y_train)
|
Представленный код демонстрирует процесс подготовки данных
и обучения модели классификации с использованием метода RandomForest (случайный
лес) (Приложение
2). Мы не используем дополнительных инструментов модели
так как данная настройка является достаточной для эффективной оценки активности
пользователя. Рассмотрим достоинства и недостатки данного подхода, а также
ситуации, когда его применение является целесообразным. В случае работы с
разнородными данными RandomForest может быть хорошим выбором, поэтому он
использован. Необходим анализ важности признаков, устройства ввода разные, вид
ввода так же отличается, необходимо учитывать данное обстоятельство. Низкая
размерность данных позволяет избегать повышенной нагрузки на вычислительную
систему. Тяжело интерпретировать обученную модель, однако в нашем случае это не
является обязательным требованием.
Основной частью является функция, где запускаются обученные
модели и получается их усредненный результат [Листинг 14,
Приложение
3]. Обученные модели загружаются из сохраненных файлов,
созданных при обучении моделей (Приложение
6, Приложение
7).
Листинг 14- Запуск обученных моделей и
усреднение их предсказаний
|
def main():
print('predict_device_input.predict()')
print(predict_device_input.predict())
process_names_prediction =
predict_process.predict()[0][0]
device_input_prediction =
calculate_true_proportion(predict_device_input.predict())
ret = process_names_prediction
/ 2 + device_input_prediction / 2
returnret
|
Опишем систему и
ее особенности. Начнем со схемы прецедентов[Рисунок 9].Сотрудник является пользователем
персонального компьютера (ПК). Сотрудник может как работать, так и отвлекаться.
Менеджер может сменять доступ к ПК сотрудника, в том числе прерывать сеанс.
Разрабатываемое приложение может обрабатывать активность сотрудника и
классифицировать его. Приложение может автоматически прерывать сеанс
пользования ПК сотрудника в зависимости от классификации его активности.
Рисунок 9 - Схема прецедентов
Опишем порядок передачи
информации [Рисунок 10]. Сотрудник взаимодействует с ПК.
Приложение собирает данные о взаимодействии сотрудника, пользователя ПК, с
самим ПК. Приложение классифицирует на основе собранных данных состояние
активности пользователя ПК. Информация о классификации передается менеджеру. Менеджер
принимает решение о смене режима доступа к ПК. Передается информация о решении
менеджера приложению. Приложение сменяет режим доступа к ПК. ПК применяет
изменения, вызванные приложением для обеспечения режима доступа к ПК.
Рисунок 10 - Схема порядка
передачи информации
Опишем на разных
уровнях систему. Начнем с верхнего уровня [Рисунок 11].Контроль регулируется на основе данных с устройств ввода и
запущенных процессов. Управляется акторами в виде пользователя ПК и менеджера.
Контроль сеанса следует правилам СанПин и регламенту компании. Результатом
работы контроллера является отчет об активности и регуляция доступа к ПК
сотрудника.
Рисунок
11–Верхний уровень
представления контроллера доступа сеанса к ПК сотрудника А0
Рассмотрим
подробнее контроллер [Рисунок 12]. Контроллер включает в себя процессы сбора
данных, анализа данных, решении о смене доступа к ПК, генерации отчета об
активности.
Рисунок 12 - Схема
представления контроллера доступа сеанса к ПК сотрудника A0
Рассмотрим
подробнее узел принятия решения о смене доступа к ПК [Рисунок 13]. Узел включает в себя комбинатор данных, вычислитель
вероятностей на основе вероятностного классификатора. В случае когда комбинатор
выдает две истины, тогда происходит принятие решения о смене доступа без
расчета вероятности правильных результатов.
Рисунок 13- Схема
представления узла принятия решения о смене доступа к ПК сотрудника А3.1.
Опишем узел
принятия решений[Рисунок 14]. Узел принимает данные о классификации
источников данных и сигнал о старте обработки данных. Узел представляет собой
не модульную функцию, а более комплексную сущность, поэтому нам необходимо
передавать сигнал о начале обработки.
Рисунок
14 - Схема
представления узла принятия решения А2.1.
Рассмотрим схему
принятия решений подробнее [Рисунок 15].Узел включает в себя булевы функции: если есть сигнал начала
обработки и все классификации выдают полную вероятность в результате, то выдать
истину, иначе если некоторая классификация не выдает полную вероятность, то
сравнить сумму вероятностей по нижнему порогу.
Рисунок 15- Схема
представления принятия решения узла 5.1.
Опишем структуру
сущностей системы [Рисунок 16].Система мониторинга включает в себя сбор
данных, обработку данных, принятие решения о смене доступа, создание отчета.
Узел сбора данных включает в себя накопление пакета данных, группировку записей
по дате, отправку синхронизированных по времени пакетов данных. Узел принятия
решения о смене доступа включает в себя классификацию данных, расчет
вероятности истинности классификации. Узел расчета вероятности истинности
классификации включает в себя определение суммы вероятностей классификации.
Узел определения суммы вероятностей классификации включает в себя сравнение
суммы вероятностей классификации с нижним порогом и исполнение действий по
смене доступа к ПК сотрудника.
Рисунок 16 – Верхний
уровень схемы представления структуры сущностей системы.
Основная
деятельность организации: «Мониторинг активности пользователей».
Объекты
обработки: данные о активности пользования устройствами ввода пользователей на
компьютере; информация о запущенных процессах.
Документы для
обработки:логи активности пользователей; статистические отчёты по использованию
ПК.
Описание
процессов.
Обработка
данных: сбор данных о времени работы в приложениях; анализ собранной информации
и её предоставление; генерация отчётов о продуктивности пользователей.
Механизмы
обработки: клиентское приложение на C# WPF взаимодействует со скриптами на Python для обработки данных; обработка логов производится на
сервере или локально пользователем.
Способы
управления: прерывание сессии при классификации активности как не продуктивной.
Сбор, хранение и
распространение информации: данные собираются и хранятся в видео файлов
логирования; отчёты и настройки вызываются через UI, доступные для пользователей.
Перечень задач.
Систематизация и
структуризация задач: задачи мониторинга активности; задачи анализа данных; задачи
генерации отчётов.
Описание задач.
Исходные данные:
логиc устройств ввода; данные о запущенных
процессах.
Результаты: отчёты
по активности, регулирующийся режим доступа к ПК.
Форматы данных:
для логов – JSON, для отчетов – JSON.
Сроки
поступления/выдачи: сбор данных происходит в реальном времени; генерация
отчётов — по запросу.
Данные,
обрабатываемые задачами: статистика по активности пользования устройствами
ввода, категории активности (продуктивная/непродуктивная).
Потоки данных и
задач.
Потоки данных: данные
о времени эксплуатации ПК преобразуются в статистику по каждому пользователю; данные
смены доступа к ПК.
Потоки задач: обработанные
данные используются для создания отчетов; обработанные данные используются для
определения действий по смене доступа к ПК.
Изменения во
времени и пространстве: данные о активности и производительности пользователи
должны обновляться в реальном времени, синхронизируясь с сервером по заданным
интервалам; результаты обработки данных отображаются через интерфейс приложения
и могут быть экспортированы пользователем для дальнейшего анализа.
В данной работе была создана
информационная система оценки активности пользователя компьютера. Для
достижения этой цели были решены следующие задачи:
Проведено теоретико-методическое исследование предметной
области
Выбраны и обоснованы методы и инструментальные средства
управления IT-проектами
Разработано техническое задание на реализацию IT-проекта
в соответствии с требованиями стандартов и регламентов разработки программного
обеспечения
Разработан алгоритм для решения задач по теме
исследования
1. Zhang H. Personal information
organization and re-access in computer folders: an empirical study of
information workers 2011.
2.
Sherif K., Jewesimi O. Electronic performance monitoring friend or foe? Empowering
employees through data analytics 2018.
3.
Patwardhan A., Knapp G. EmoFit: Affect Monitoring System for Sedentary Jobs //
2016.
4. Nepal
S. [идр.]. From User
Surveys to Telemetry-Driven Agents: Exploring the Potential of Personalized
Productivity Solutions // 2024.
5. Женило К. [и др.]. Радіоелектроніка та молодь у XXI
столітті. Т. 6?: Конференція «Інформаційні інтелектуальні системи» / К. Женило,
О. Гриньова, А. Шабанова, С. Жаркіх, К. Дукельська, [и др.]., Press of the Kharkiv National
University of Radioelectronics, 2024.
6. Женило К. [и др.]. Радіоелектроніка та молодь у XXI
столітті. Т. 6?: Конференція «Інформаційні інтелектуальні системи» / К. Женило,
О. Гриньова, А. Шабанова, С. Жаркіх, К. Дукельська, [и др.]., Press of the Kharkiv National University
of Radioelectronics, 2024.
7. Al
Samman A. M., Althawaini F. The Impact of Electronic Monitoring on Employee
Performance: Enhancing Transparency, Accountability, and Productivity 2024.C.
1–6.
8. Arora
S. Enhancing Employee Well-being with Machine Learning: Predictive Models for
Health and Wellness Programs // Journal of Informatics Education and Research.
2024. № 3 (4).
9.
Azpiroz-Dorronsoro C. [идр.]. Technostress and work-family conflict in ICT-user employees during
the COVID-19 pandemic: the role of social support and mindfulness // Behaviour
& Information Technology. 2024.
10. Baek
I. G., Ko Y. H. Effects of an Electronic Monitoring System on Employees’
Productivity in Telecommuting Arrangements // Academy of Management
Proceedings. 2022.
11. Das
A. K. [идр.]. Enhancing
Workplace Efficiency and Security Through Intelligent Employee Surveillance //
International Journal of Innovative Science and Research Technology (IJISRT).
2024. C. 2357–2370.
12.
Demerouti E. [идр.].
The job demands-resources model of burnout // Journal of Applied Psychology.
2001. № 3 (86). C. 499–512.
13.
Donati M. [идр.].
RT-PROFASY: Enhancing the Well-being, Safety and Productivity of Workers by
Exploiting Wearable Sensors and Artificial Intelligence 2022.C. 69–74.
14.
Dowrie S., Belle J.-P. V., Turpin M. Employee Technostress in South Africa’s
Hybrid Workplaces: Causes and Coping Mechanisms 2023.C. 943–947.
15. Du
P. Research on the training system of enterprise employees’ digital skills
enhancement // Advances in Economics and Management Research. 2023. № 1 (7). C.
260–260.
16.
Dutta D., Mishra S. K. “Technology is killing me!”: the moderating effect of
organization home-work interface on the linkage between technostress and stress
at work // Information Technology & People. 2023. № 6 (37). C.
2203–2222.
17.
Fellmann M., Lambusch F., Schmidt A. C. Combining Computer-Based Activity
Tracking with Human Energy and Sentiment Self-assessment for Continuous
Work-Life Reflection подред. M. Kurosu, A. Hashizume, Cham: Springer Nature Switzerland, 2023.C.
164–181.
18.
Harunavamwe M., Kanengoni H. Hybrid and virtual work settings; the interaction
between technostress, perceived organisational support, work-family conflict
and the impact on work engagement // African Journal of Economic and Management
Studies. 2023. № 2 (14). C. 252–270.
19.
Helman V., Cherep О.,
Bexhter L. INCREASE THE EFFICIENCY OF PERSONNEL MONITORING BASED ON THE USE OF
SOFTWARE // Herald of Khmelnytskyi National University. Economic sciences.
2024. № 1 (326). C. 434–438.
20.
Khedhaouria A. [идр.].
Consequences of technostress for users in remote (home) work contexts during a
time of crisis: The buffering role of emotional social support // Technological
Forecasting and Social Change. 2024. (199). C. 123065.
21. Kolbeinsson
O. [идр.]. No sound is
more distracting than the one you’re trying not to hear: delayed costs of
mental control of task-irrelevant neutral and emotional sounds // BMC
Psychology. 2022. № 1 (10). C. 33.
22.
Mordi C., Akanji B., Ajonbadi H. Exploring the impact of technostress on the
work–life boundary of UK academics during the coronavirus pandemic //
Information Technology & People. 2025. № ahead-of-print
(ahead-of-print).
23.
Palczynska M., Rynko M. ICT skills measurement in social surveys: Can we trust
self-reports? // Quality & Quantity. 2021. № 3 (55). C. 917–943.
24.
Pazio O. [идр.].
Assessment of physical activity of people employed in the IT sector during the
COVID-19 pandemic // Folia Cardiologica. 2022. № 6 (17). C. 323–328.
25.
Reddy Katam B. AI-Driven Mood Analysis for Employee Wellbeing: A Proactive
Approach to Enhancing Workplace Productivity // International Journal of
Innovative Science and Research Technology (IJISRT). 2024. C. 2833–2836.
26.
Schmidt B. Information Work Support based on Activity Data.
27.
Sherif K., Jewesimi O., El-Masri M. Empowering employees: the other side of
electronic performance monitoring // Journal of Information, Communication and
Ethics in Society. 2020. № 2 (19). C. 207–221.
28.
Tajitsu Y. [идр.]. A
Prototype Sensor System Using Fabricated Piezoelectric Braided Cord for
Work-Environment Measurement during Work from Home // Micromachines. 2021. № 8
(12). C. 966.
29.
Tariq Beigh F. [идр.].
Intelligent Workplace Activity Monitoring and Detection Using Self-Powered
Triboelectric/Piezoelectric Sensor Augmented Machine Learning // IEEE Sensors
Letters. 2023. № 6 (7). C. 1–4.
30.
Tariq Beigh F. [идр.].
Intelligent Workplace Activity Monitoring and Detection Using Self-Powered
Triboelectric/Piezoelectric Sensor Augmented Machine Learning // IEEE Sensors
Letters. 2023. № 6 (7). C. 1–4.
31.
Vinith M. K., Pinto M. D. E. INFORMATION TECHNOLOGY IN SURVEILLANCE OF EMPLOYEE
PERFORMANCE // EPRA International Journal of Environmental Economics, Commerce
and Educational Management. 2023. № 9 (10). C. 1–1.
32.
Voigt J. [идр.].
Conceptional Framework for the Objective Work-Related Quality of Life
Measurement Through Multimodal Data Integration from Wearables and Digital
Interaction 2024.C. 61–68.
33. Xia
T. [идр.]. Exploring the
Effect of Red and Blue on Cognitive Task Performances // Frontiers in
Psychology. 2016. (7).
34. Zhou
Q., Flinchbaugh C. Stop Watching Me! Potential Negative Effects of Electronic
Monitoring on Employees’ Job Performance // Academy of Management Proceedings.
2023.
35.
(PDF) Browsing Pattern Analysis: What user browsing Patterns Indicate //
ResearchGate. 2024.
36. Об утверждении стратегического направления в области
цифровой трансформации здравоохранения от 17 апреля 2024 - docs.cntd.ru
[Электронный ресурс]. URL:
https://docs.cntd.ru/document/1305703645 (датаобращения: 26.03.2025).
37. The
Dark Side of Technology Use: The Relationship Between Technostress Creators,
Employee Work-Life Balance, and Job Burnout While Working Remotely During the
COVID-19 Lockdown | SpringerLink [Электронныйресурс]. URL:
https://link.springer.com/chapter/10.1007/978-3-031-09928-1_8 (дата обращения:
29.03.2025).
38. Федеральный закон «О персональных данных» от
27.07.2006 N 152-ФЗ (последняя редакция) \ КонсультантПлюс [Электронный
ресурс]. URL: https://www.consultant.ru/document/cons_doc_LAW_61801/ (дата
обращения: 29.03.2025).
39. Федеральный закон «О техническом регулировании» от
27.12.2002 N 184-ФЗ (последняя редакция) \ КонсультантПлюс [Электронный
ресурс]. URL: https://www.consultant.ru/document/cons_doc_LAW_40241/ (дата
обращения: 29.03.2025).
40. Федеральный закон «Об информации, информационных
технологиях и о защите информации» от 27.07.2006 N 149-ФЗ (последняя редакция)
\ КонсультантПлюс [Электронный ресурс]. URL: https://www.consultant.ru/document/cons_doc_LAW_61798/
(дата обращения: 29.03.2025).
41. IEEE Code of Ethics [Электронный ресурс]. URL:
https://www.ieee.org/about/corporate/governance/p7-8.html (дата обращения:
29.03.2025).
42. The
Code affirms an obligation of computing professionals to use their skills for
the benefit of society. [Электронный ресурс]. URL:
https://www.acm.org/code-of-ethics (дата обращения: 29.03.2025).
43.
Trouble with big brother: Counterproductive consequences of electronic
monitoring through the erosion of leader?member social exchange - Thiel - 2023
- Journal of Organizational Behavior - Wiley Online Library [Электронныйресурс]. URL:
https://onlinelibrary.wiley.com/doi/10.1002/job.2748 (датаобращения: 29.03.2025).
44.
Understanding and supporting personal activity management by IT service workers
| Proceedings of the 2nd ACM Symposium on Computer Human Interaction for
Management of Information Technology [Электронныйресурс]. URL:
https://dl.acm.org/doi/10.1145/1477973.1477976 (датаобращения: 29.03.2025).
45.
Workplace Surveillance in Canada: A survey on the adoption and use of employee
monitoring applications - Thompson - 2023 - Canadian Review of Sociology/Revue
canadienne de sociologie - Wiley Online Library [Электронныйресурс]. URL: https://onlinelibrary.wiley.com/doi/10.1111/cars.12448
(датаобращения:
29.03.2025).
46.
Examining workweek variations in computer usage patterns: An application of
ergonomic monitoring software | PLOS One [Электронныйресурс]. URL:
https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0287976 (дата
обращения: 16.03.2025).
47. A
Mousepad Triboelectric-Piezoelectric Hybrid Nanogenerator (TPHNG) for
Self-Powered Computer User Behavior Monitoring Sensors and Biomechanical Energy
Harvesting [Электронныйресурс]. URL: https://www.mdpi.com/2073-4360/15/11/2462 (датаобращения: 10.04.2025).
48.
Monitoring Aktivitas Komputer Jaringan LAN Menggunakan Net Monitor For
Employees Berbasis Android | DoubleClick: Journal of Computer and Information
Technology [Электронныйресурс]. URL:
https://e-journal.unipma.ac.id/index.php/doubleclick/article/view/5360 (дата
обращения: 10.04.2025).
49. U.S.
Patent Application for EFFECTIVE UTILIZATION OF IDLE CYCLES OF USERS Patent
Application (Application #20180032945 issued February 1, 2018) - Justia Patents
Search [Электронныйресурс].
URL: https://patents.justia.com/patent/20180032945 (датаобращения: 16.03.2025).
50.
Web-browsing patterns reflect and shape mood and mental health | Nature Human
Behaviour [Электронныйресурс]. URL: https://www.nature.com/articles/s41562-024-02065-6 (дата
обращения: 17.03.2025).
Приложение1
train_model_mode_by_processes.py
import pandas as pd
from sklearn.model_selectionimport train_test_split
from keras.preprocessing.textimport Tokenizer
from keras_preprocessing.sequenceimport pad_sequences
from keras.modelsimport Sequential,
load_model
from keras.layersimport Dense,
Embedding, LSTM
import json
import os
import process_name_tokenizing.process_name_tokens_manageras process_name_tokenizing
module_dir = os.path.dirname(os.path.abspath(__file__))
log_data = []
log_directory = module_dir + './processes_logs'
# Загрузкаданных
for filename in os.listdir(log_directory):
if filename.endswith('.json'): # Проверяем, чтофайлимеетрасширение .json
file_path = os.path.join(log_directory, filename) # Полныйпутькфайлу
try:
with open(file_path, 'r') as file:
data =
json.load(file) # Загружаемданныеиз JSON-файла
# Проверяемструктуру JSON
if (
isinstance(data, dict) and
'is_working_mode' in data and
'timestamp' in data and
'processes' in data and
isinstance(data['processes'], list)
):
log_data.append(data) # Добавляемданныевсписок
except (json.JSONDecodeError, IOError) as e:
print(f"Ошибкаприобработкефайла{filename}: {e}")
data = log_data
df = pd.DataFrame(data)
# Подготовка
max_length = 64 # Максимальнаядлинапоследовательности
tokenizer = process_name_tokenizing.process_tokenization(df['processes'])
X = tokenizer.texts_to_sequences(df['processes'])
X = pad_sequences(X, maxlen=max_length)
y = pd.get_dummies(df['is_working_mode']).values # one-hot encoding
# Разделениенаобучающуюитестовуювыборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# Модель
model = None
try:
model = load_model(module_dir + './predict_processes.h5')
except OSError:
print("Saved model not found")
if not model:
model = Sequential()
amount_of_different_words = (len(tokenizer.word_index) + 1)
model.add(
Embedding(input_dim=amount_of_different_words,
output_dim=amount_of_different_words, input_length=max_length))
model.add(LSTM(amount_of_different_words))
model.add(Dense(2, activation='softmax'))
# Компиляция
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
# Обучение
model.fit(X_train, y_train, epochs=10, batch_size=32)
model.save(module_dir + './predict_processes.h5')
# Оценка
test_loss, test_accuracy = model.evaluate(X_test, y_test)
print(f'Test accuracy: {test_accuracy}')
Приложение2
train_model_mode_by_device_input.py
import json
import os
import pandas as pd
from sklearn.model_selectionimport train_test_split
from sklearn.ensembleimport RandomForestClassifier
from sklearn.metricsimport classification_report
import joblib
module_dir = os.path.dirname(os.path.abspath(__file__))
directory_path = module_dir + './device_input_logs'
# Путькдиректориис JSON-файлами
model_path = module_dir + './predict_device_input.h5' # Путькмодели
# Считываемвселоги
all_logs = []
for filename in os.listdir(directory_path):
if filename.endswith('.json'):
file_path = os.path.join(directory_path, filename)
with open(file_path, 'r') as file:
data = json.load(file)
all_logs.extend(data['deviceLogs'])
# Подготовкаданных
df = pd.DataFrame(all_logs)
# Преобразуем timestamp вчисловойформат
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['timestamp_seconds'] = df['timestamp'].astype('int64') // 10**9 # Конвертациявсекунды
# Выбираемнеобходимыестолбцы
df = df[['timestamp_seconds', 'buttonKey', 'isWorkingMode']]
prepared_data = df
model = None
try:
model = joblib.load(model_path)
except OSError:
print("Saved model not found")
# Обучениемодели
# Разделениеданныхнапризнакиицелевуюпеременную
X = prepared_data[['timestamp_seconds', 'buttonKey']]
y = prepared_data['isWorkingMode']
# Разделениеданныхнатренировочныеитестовые
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
if not model:
# Созданиеиобучениемодели
model = RandomForestClassifier()
model.fit(X_train, y_train)
# model.save(model_path)
joblib.dump(model, model_path)
if __name__ == "__main__":
# Оценкамодели
predictions = model.predict(X_test)
print(classification_report(y_test, predictions))
Приложение3
process.py
import process_names.predict_mode_by_processesas predict_process
import device_input.predict_mode_by_device_inputas predict_device_input
import user_session_manipulator.lock_sessionas lock_session
def calculate_true_proportion(lst):
# Подсчитываемколичество True всписке
true_count = sum(lst)
# Вычисляемобщееколичествоэлементоввсписке
total_count = len(lst)
# Возвращаемдолю True
return true_count / total_countif total_count>0 else 0
def main():
print('predict_device_input.predict()')
print(predict_device_input.predict())
process_names_prediction = predict_process.predict()[0][0]
device_input_prediction = calculate_true_proportion(predict_device_input.predict())
ret = process_names_prediction / 2 +
device_input_prediction / 2
return ret
if __name__ == "__main__":
main()
Приложение4
listenProcessesList.py
import psutil
import json
import argparse
from datetime import datetime
import threading
import signal
import sys
import os
import time
is_working_mode = True
module_dir = os.path.dirname(os.path.abspath(__file__))
def set_interval(func, sec):
def func_wrapper():
set_interval(func, sec)
func()
t = threading.Timer(sec,
func_wrapper)
t.start()
return t
def save_processes_to_file(dir_to_logs,
is_working_mode_target_value):
processes = []
processes_seen = set() # Use a set to
track seen (name, pid) tuples.
for p in psutil.process_iter(attrs=['name', 'pid', 'cpu_percent']):
if hasattr(p,'info'):
try:
# Получаемнагрузкуна CPU
p.cpu_percent(interval=0) # Дляполучениятекущегозначениявбудущем
if p.info['name'] not in processes_seen:
processes_seen.add(p.info['name']) # Mark this
process as seen
processes.append((p.info['name'], p.info['pid'],
p.cpu_percent(interval=0)))
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
# Сортируемпроцессыпонагрузкена CPU ипо id процессавпорядкеубывания
sorted_processes = sorted(processes, key=lambda x: (x[2], x[1]), reverse=True)
# Формируеммассивсназваниямипроцессовинагрузкойнасистему
# result = [f"{name} (нагрузка: {cpu}% )" for name, pid, cpu in
sorted_processes]
timestamp = datetime.now().isoformat()
result = {
'is_working_mode': is_working_mode_target_value,
'timestamp': timestamp,
'processes': []
}
for name, pid, cpuin sorted_processes:
if name.endswith(".exe"):
clean_process_name = name[:-4] # Убираемпоследние 4 символа ".exe"
else:
clean_process_name = name
if not clean_process_namein result and not clean_process_name.endswith(".json"): # Недобавляемповторыи (json файлы?)
result['processes'].append(clean_process_name)
# Формируемимяфайлавпапке
"logs_folder"
clean_timestamp = time.strftime("%Y-%m-%d_%H-%M-%S") # Убранынеправильныесимволыдляназванияфайлав windows
logs_file_name = os.path.join(dir_to_logs, f"{clean_timestamp}.json")
# Убеждаемся, чтопапкасуществует
os.makedirs(dir_to_logs, exist_ok=True)
# Записываеммассивназванийпроцессоввуказанныйфайл
print(logs_file_name)
with open(logs_file_name, 'w') as json_file:
# Записываемобъект `result` вфайлвформате JSON
json.dump(result, json_file, ensure_ascii=False, indent=4)
print(f"Названияпроцессовснагрузкойуспешнозаписаныв{dir_to_logs}.")
def signal_handler(sig, frame):
loggingInterval.cancel()
print("Прерываниепроцесса. Сохранениеданныхивыход.")
sys.exit(0)
if __name__ == "__main__":
# Создаемпарсераргументовкоманднойстроки
parser = argparse.ArgumentParser(description='Записываетназваниязапущенныхпроцессоввфайлы JSON.')
# Add an argument for the working mode
parser.add_argument('--working-mode', type=str, default='false',
choices=['true', 'false', '1', '0', 'yes', 'no'],
help='Run in
working mode (true/1/yes) or not (false/0/no).')
parser.add_argument('--dir-to-log', type=str, default=module_dir + '.\processes_logs',
help='Имявыходногофайла (поумолчаниюprocesses_logs.json)')
parser.add_argument('--log-interval-sec', type=str,
default='5',
help='Какчастопроизводитьзапись')
# Parse the arguments
args = parser.parse_args()
is_working_mode = args.working_mode.lower() in ['true', '1', 'yes']
logs_folder_name = args.dir_to_log
time_interval = int(args.log_interval_sec)
loggingInterval = set_interval(lambda: save_processes_to_file(logs_folder_name,
is_working_mode), time_interval)
signal.signal(signal.SIGINT, signal_handler)
Приложение5
listenDeviceInput.py
import json
import sys
import signal
from datetime import datetime
import keyboard # Убедитесь, чтоэтабиблиотекаустановлена
import mouse # Убедитесь, чтоэтабиблиотекаустановлена
# Mouse buttons map
mouse_buttons_map = {
'left': 151,
'right': 152,
'middle': 153,
'wheel': 154,
'x': 155,
'x2': 156,
'up': 157,
'down': 158,
'double': 159,
'vertical': 160,
'horizontal': 161,
'deltaPlus': 162,
'deltaMinus': 163,
}
logs = []
is_working_mode = True
def log_event(button_key, is_working_mode):
timestamp = datetime.now().isoformat() # Беремтекущеевремя
log_entry = {
"timestamp": timestamp,
"buttonKey": button_key,
"isWorkingMode": is_working_mode
}
logs.append(log_entry)
with open('device_logs.json', 'w', encoding='utf-8') as f:
json.dump(logs, f, indent=4)
def on_key_event(event):
global is_working_mode
try:
print(event.name,
event.scan_code)
log_event(event.scan_code, is_working_mode)
except:
print("Pressed
button out from processing range")
def on_mouse_event(event):
global is_working_mode
try:
if isinstance(event, mouse.ButtonEvent) and event.buttonin mouse_buttons_map:
print(event.button,
mouse_buttons_map[event.button])
log_event(mouse_buttons_map[event.button], is_working_mode)
elifisinstance(event, mouse.WheelEvent) and event.deltais not None:
if event.delta>0:
log_event(mouse_buttons_map["deltaPlus"],
is_working_mode)
else:
log_event(mouse_buttons_map["deltaMinus"],
is_working_mode)
except:
print("Pressed
button out from processing range")
def signal_handler(sig, frame):
print("Прерываниепроцесса. Сохранениеданныхивыход.")
sys.exit(0)
if __name__ == "__main__":
if len(sys.argv) >1:
is_working_mode = sys.argv[1].lower() in ['true', '1', 'yes']
signal.signal(signal.SIGINT, signal_handler)
keyboard.hook(on_key_event) # Слушаемсобытияклавиатуры
mouse.hook(on_mouse_event) # Слушаемсобытиямыши
keyboard.wait() # Ожидаемзавершения
mouse.wait() # Ожидаемзавершения
Приложение6
predict_mode_by_processes.py
import pandas as pd
from tensorflow.keras.preprocessing.sequenceimport pad_sequences
from tensorflow.keras.modelsimport Sequential,
load_model
import json
import os
# import process_name_tokenizing.process_name_tokens_manager as
pn_token_manager
from .process_name_tokenizingimport process_name_tokens_manageras pn_token_manager
module_dir = os.path.dirname(os.path.abspath(__file__))
def predict_by_process_names(df: pd.DataFrame, sequence_max_len=64, tokenizer_file=pn_token_manager.tokens_dict_filename):
max_length= sequence_max_len# Максимальнаядлинапоследовательности
# Загрузитьтокенайзериобновитьего
tokenizer = pn_token_manager.process_tokenization(df['processes'])
# Выносимданныедляпредсказания
X = tokenizer.texts_to_sequences(df['processes'])
X = pad_sequences(X, maxlen=max_length)
# y = pd.get_dummies(df['is_working_mode']).values # one-hot encoding
# Модель
model = load_model(module_dir + './predict_processes.h5')
ret = model.predict(X)
return ret
def load_dataframe_process_names(amount_of_records=10):
log_data= []
log_directory= module_dir + './processes_logs'
# Загрузкаданных
for filename in os.listdir(log_directory):
if amount_of_records<1:
break
if filename.endswith('.json'): # Проверяем, чтофайлимеетрасширение .json
file_path= os.path.join(log_directory, filename) # Полныйпутькфайлу
try:
with open(file_path, 'r') as file:
data = json.load(file)
# Загружаемданныеиз JSON-файла
# Проверяемструктуру JSON
if (
isinstance(data, dict) and
'is_working_mode' in data and
'timestamp' in data and
'processes' in data and
isinstance(data['processes'], list)
):
log_data.append(data) # Добавляемданныевсписок
except (json.JSONDecodeError, IOError) as e:
print(f"Ошибкаприобработкефайла{filename}: {e}")
amount_of_records-= 1
data = log_data
df =
pd.DataFrame(data)
return df
def predict():
df = load_dataframe_process_names(amount_of_records=1)
return predict_by_process_names(df)
if __name__ == "__main__":
ret = predict()
json.dumps(ret)
Приложение7
predict_mode_by_device_input.py
import json
import os
import pandas as pd
import joblib
module_dir = os.path.dirname(os.path.abspath(__file__))
directory_path = module_dir + './device_input_logs'
# Путькдиректориис JSON-файлами
model_path = module_dir + './predict_device_input.h5' # Путькмодели
def predict_by_device_input(df: pd.DataFrame):
# Преобразуем timestamp вчисловойформат
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['timestamp_seconds'] = df['timestamp'].astype('int64') // 10**9 # Конвертациявсекунды
# Сортировкапо timestamp
df = df.sort_values('timestamp')
# Выбираемнеобходимыестолбцы
df = df[['timestamp_seconds', 'buttonKey', 'isWorkingMode']]
prepared_data= df
model = joblib.load(model_path)
X = prepared_data[['timestamp_seconds', 'buttonKey']]
y = prepared_data['isWorkingMode']
# Оценкамодели
ret = model.predict(X)
return ret
def load_dataframe_device_input(amount_of_records=128):
# Считываемвселоги
all_logs= []
for filename in os.listdir(directory_path):
if amount_of_records<1:
break
if filename.endswith('.json'):
file_path= os.path.join(directory_path, filename)
with open(file_path, 'r') as file:
data = json.load(file)
all_logs.extend(data['deviceLogs'])
amount_of_records-= 1
# Подготовкаданных
df = pd.DataFrame(all_logs)
return df
def predict():
df = load_dataframe_device_input(amount_of_records=128)
return predict_by_device_input(df)
if __name__ == "__main__":
ret = predict()
json.dumps(ret)
Приложение8
process_name_tokens_manager.py
import os
import json
from collections import defaultdict
from keras.preprocessing.text import Tokenizer
tokens_dict_filename = 'tokens_dictionary.json'
def load_or_create_tokenizer(filename='tokens_dictionary.json'):
# Еслифайлсуществует, загружаемтокенизатор
if os.path.exists(filename):
with open(filename, 'r',
encoding='utf-8') as file:
tokenizer_data = json.load(file)
tokenizer = Tokenizer()
tokenizer.word_index = tokenizer_data.get('word_index', {})
tokenizer.index_word = {int(k): v for k, v in tokenizer_data.get('index_word',
{}).items()}
tokenizer.word_counts = defaultdict(int, tokenizer_data.get('word_counts', {}))
tokenizer.word_docs = defaultdict(int, tokenizer_data.get('word_docs', {}))
tokenizer.index_docs = defaultdict(int, {int(k): v for k, v in
tokenizer_data.get('index_docs', {}).items()})
else:
# Еслифайлнесуществует, создаемновыйтокенизаторисохраняемеговфайл
tokenizer = Tokenizer()
with open(filename, 'w',
encoding='utf-8') as file:
json.dump({
'word_index':
tokenizer.word_index,
'index_word':
tokenizer.index_word,
'word_counts':
dict(tokenizer.word_counts),
'word_docs': dict(tokenizer.word_docs),
'index_docs':
dict(tokenizer.index_docs)
}, file, ensure_ascii=False,
indent=4)
return tokenizer
def update_tokenizer(tokenizer: Tokenizer, texts: [str], filename='tokens_dictionary.json'):
# Обновляемтокенизаторновымитекстами
tokenizer.fit_on_texts(texts)
# Сохраняемобновленныйтокенизаторвфайл
with open(filename, 'w',
encoding='utf-8') as file:
json.dump({
'word_index':
tokenizer.word_index,
'index_word': tokenizer.index_word,
'word_counts':
dict(tokenizer.word_counts),
'word_docs':
dict(tokenizer.word_docs),
'index_docs':
dict(tokenizer.index_docs)
}, file, ensure_ascii=False,
indent=4)
def process_tokenization(texts: [str], filename='tokens_dictionary.json'):
# Загружаемилисоздаемтокенизатор
tokenizer =
load_or_create_tokenizer()
# Обновляемтокенизаторновымитекстами
update_tokenizer(tokenizer, texts, filename)
# Выводимтекущийсловарьтокенов
# print("Словарьтокенов:", tokenizer.word_index)
return tokenizer
def text_to_sequences(texts: [str], tokenizer: Tokenizer,
filename='sequenced_texts.json'):
print(tokenizer)
ret =
tokenizer.texts_to_sequences(texts)
with open(filename, 'w',
encoding='utf-8') as file:
json.dump({
"seq": ret
}, file, ensure_ascii=False,
indent=4)
return ret
# Примерприменения:
# process_tokenization(["новыйтекстк ", "другойтекстик", "текст"])
# process_tokenization(["новыйтекстдляобработки ", "ещеодиндругойтекст"])
# text_to_sequences(["текстобработки"], load_or_create_tokenizer())
# ---