close

Вход

Забыли?

вход по аккаунту

Козлов Александр Александрович. Программное обеспечение системы определения психотипа пользователя web-сайта: подсистема анализа данных

код для вставки
Powered by TCPDF (www.tcpdf.org)
Powered by TCPDF (www.tcpdf.org)
АННОТАЦИЯ
ВКР 112 с., 20 рис., 3 табл., 15 источников, 1 прил.
СБОР ПАРАМЕТРОВ, НАБЛЮДЕНИЕ ПОВЕДЕНИЯ ПОЛЬЗОВАТЕЛЕЙ,
ТАРГЕТИРОВАННАЯ
WEB-ПРИЛОЖЕНИЕ,
РЕКЛАМА,
ПСИХОТИП,
НЕЙРОННАЯ СЕТЬ, ПЕРЕДАЧА ДАННЫХ, КЛАССИФИКАЦИЯ
Выпускная квалификационная работа посвящена разработке подсистемы
сбора данных пользователя web-сайта для системы определения психотипа.
В первой главе выпускной квалификационной работы приведено описание
психологических типов и их применение в психологической рекламе. Проведен
анализ и выбор наблюдаемых параметров. Рассмотрены возможные методы
анализа информации пользователя веб-сайта. Перечислены и проанализированы
аналогичные
решения.
Выявлены
функциональные
и
нефункциональные
требования к системе.
Во второй главе была разработана архитектура системы определения
психотипа. Составлена функциональная и информационные модели подсистемы
анализа данных. Выявлены особенности организации взаимодействия с внешним
ПО.
В третьей главе приведено описание модулей подсистемы анализа данных,
разобрана
специфика
работы
основных
алгоритмов,
а
также
описаны
основополагающие структуры данных.
В
четвертой
компонентов
главе
представлены
подсистемы
анализа
тонкости
данных.
реализации
Показана
основных
статистика
функционирования подсистемы анализа данных в режиме обучения нейронной
сети.
Графическая
часть
выпускной
квалификационной
работы
включает
иллюстрации, таблицы, которые объединены в презентацию PowerPoint.
Библиографическая часть выпускной квалификационной работы включает в
себя 15 источников.
4
СОДЕРЖАНИЕ
ВВЕДЕНИЕ
6
1 АНАЛИЗ ЗАДАЧИ РАЗРАБОТКИ ПОДСИСТЕМЫ АНАЛИЗА
ДАННЫХ ПОЛЬЗОВАТЕЛЯ ВЕБ-САЙТА
7
1.1 Психологические типы и их применение в таргетированной рекламе
7
1.2 Анализ и выбор наблюдаемых параметров
12
1.3 Возможные методы анализа полученной информации
17
1.4 Анализ аналогичных решений
21
1.5 Требования к системе
25
2 СПЕЦИФИКАЦИИ ПОДСИСТЕМЫ АНАЛИЗА ДАННЫХ
ПОЛЬЗОВАТЕЛЯ
ВЕБ-САЙТА
30
2.1 Архитектура системы
30
2.2 Функциональная модель подсистемы анализа данных
33
2.3 Информационная модель подсистемы анализа данных
39
2.4 Особенности организации взаимодействия с внешним ПО
48
3 ПРОЕКТИРОВАНИЕ ПОДСИСТЕМЫ АНАЛИЗА ДАННЫХ
ПОЛЬЗОВАТЕЛЯ
ВЕБ-САЙТА
50
3.1 Структура ПО
50
3.1.1 Режим обучения нейронной сети
50
3.1.1.1 Модуль сохранения информации
52
3.1.1.2 Модуль получения поведенческих параметров пользователя
53
3.1.1.3 Модуль анализа данных
58
3.1.1.4 Модуль нейронной сети
59
3.1.1.5 Модуль с конфигурацией проекта
60
3.1.2 Режим определения психотипа пользователя
60
3.1.2.1 Главный модуль
62
3.1.2.2 Модуль подготовки данных и классификации
63
3.2 Основные алгоритмы
65
3.3 Проектирование структур данных
74
5
4 Реализация подсистемы анализа данных пользователя веб-сайта
78
4.1 Режим обучения нейронной сети
78
4.2 Режим определения психотипа пользователя
83
4.3 Статистика функционирования подсистемы анализа данных в режиме
обучения нейронной сети
84
ЗАКЛЮЧЕНИЕ
86
СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ
87
ПРИЛОЖЕНИЕ А - ПРОГРАММНЫЙ КОД
89
УДОСТОВЕРЯЮЩИЙ ЛИСТ НА ДЕМОНСТРАЦИОННЫЙ
МАТЕРИАЛ
110
ИНФОРМАЦИОННО-ПОИСКОВАЯ ХАРАКТЕРИСТИКА
ДОКУМЕНТА НА ЭЛЕКТРОННОМ НОСИТЕЛЕ
111
6
ВВЕДЕНИЕ
С развитием и ростом социальных медиа появилась и набирает силу
таргетированная реклама.
Сам термин «таргетированная реклама» обозначает показ рекламных
объявлений, которые привязываются не к содержанию веб-страницы, а к
определенной
группе
пользователей,
выделенной
на
основании
их
предшествующего поведения или анкетных данных.
Целью данной выпускной квалификационной работы является создание
подсистемы анализа данных пользователя веб-сайта для определения
психотипа пользователя и возврата результата классификации веб-сайту для
подбора типа рекламы.
Основными задачами работы являются:
1) анализ предметной области, выявление требований к создаваемому
программному комплексу;
2) выявление методов анализа полученных данных пользователя;
3) анализ аналогичных решений;
4) определение спецификаций;
5) проектирование подсистемы анализа данных, выявление структуры
ПО, проектирование алгоритмов и структур данных;
6) реализация механизмов подсистемы анализа данных;
7) определение статистики функционирования подсистемы в режиме
обучения нейронной сети.
Работа
выполнена
в
рамках
совместного
И.С.Тургенева и компании «ОрелСайтСтрой».
проекта
ОГУ
им.
7
1 АНАЛИЗ ЗАДАЧИ РАЗРАБОТКИ ПОДСИСТЕМЫ АНАЛИЗА
ДАННЫХ ПОЛЬЗОВАТЕЛЯ ВЕБ-САЙТА
1.1 Психологические типы и их применение в таргетированной
рекламе
Тип личности можно трактовать как совокупность социально значимых
личностных характеристик индивида. В психологии тип личности — это
некая
абстрактная
модель,
включающая
совокупность
характеристик
индивида, которые проявляются с определенным постоянством, являясь
ответной
реакцией
на
воздействие окружающей
социальной
среды.
Классификации по типу личности в психологии весьма разнородны и
многочисленны. Исследования на эту тему ведутся со времен Гиппократа и
не прекращаются по сей день. Наибольших результатов в изучении
особенностей человеческой психики и ее классификации смогли достигнуть
Э. Кречмер, У.Г. Шелдон, З. Фрейд, К. Юнг, К. Леонард и другие.
Исходя из теории Гиппократа, согласно которой психотип человека
зависит от соотношения различных жидкостей в организме: крови, лимфы и
двух
видов
желчи,
выделяются
следующие
типы
человеческого
темперамента:
˗ флегматик – человек, в организме которого преобладает лимфа
(флегма), отчего он становится спокойным и медлительным;
˗ меланхолик – человек, в организме которого преобладает черная
желчь (мелане холе), отчего он боязлив и склонен к печали;
˗ сангвиник – человек, в организме которого много крови (сангвис),
подвижный и веселый;
˗ холерик – горячий и импульсивный, в его организме много желтой
желчи (холе).
В начале ХХ века немецкий психиатр Э. Кречмер выделил различные
типы личности в зависимости от характера. Это была первая классификация
характера. Кречмер связывал психотип человека с конституцией его тела.
8
Три вида телесной конституции:
- Астенический. Худые и высокие люди, у них удлиненные руки и
ноги, слаборазвитая мускулатура.
- Атлетический. Люди крепкие, с хорошо развитой мускулатурой, рост
средний или выше среднего.
- Пикнический. Склонные к полноте люди со слаборазвитыми
мышцами и опорно-двигательным аппаратом, среднего или небольшого
роста.
Так как Э. Кречмер был психиатром, он сопоставил психотипы
личности со склонностью к той или иной психопатологии и сгруппировал их
в два типа личности:
- шизотимики – психически здоровые люди атлетического или
астенического
телосложения,
отдаленно
напоминающие
больных
шизофренией. Им свойственны такие черты характера: артистичность,
чувствительность, отчужденность, эгоистичность, властность;
- циклотимики
телосложения,
–
психические
напоминающие
здоровые
больных
люди
пикнического
маниакально-депрессивным
психозом. Это веселые, оптимистичные, общительные, легкомысленные
люди.
Теория Э. Кречмера была основана лишь на его личных наблюдениях,
но послужила основой для последующих, более сложных типологий
характера. Намного позже ученые пришли к выводу, что форма тела
действительно влияет на характер и индивидуально типологические
особенности личности. [6, c.210]
Общеизвестные психологические типы были выявлены и описаны
австрийским психиатром и психоаналитиком К. Г. Юнгом. Его теория об
«интроверсии – экстраверсии», а также о четырех типах восприятия мира
развивалась и продолжает развиваться.
Психотипы личности, предложенные Юнгом:
9
˗ типы личности в зависимости от вектора ее направленности:
1) экстраверт – человек, психологически ориентированный на
внешний мир; общительный, активный, деятельный;
2) интроверт – человек, ориентированный на внутренний мир;
замкнутый, чувствительный, рассудительный.
˗ психологические типы в зависимости от преимущественного способа
восприятия жизни, иными словами, от основной психической функции:
1) мыслительный
тип
–
человек,
в
принятии
решений
преимущественно опирающийся на логику и мышление. Подавленной
оказывается сфера чувств;
2) чувствующий тип – человек, ориентированный на чувства, судит
категориями «хорошо – плохо», а не логически;
3) ощущающий
тип
–
человек,
воспринимающий
жизнь
непосредственно органами чувств, он смотрит, слушает, трогает и
принимает решение исходя из получаемой информации. Интуиция им
подавляется;
4) интуитивный тип – человек, полагающийся на «шестое» чувство;
такие
люди
принимают
решение,
опираясь
на
интуитивные,
бессознательные знания, а не на непосредственные ощущения.
Основываясь на типологии Юнга, в семидесятых – восьмидесятых
годах
прошлого
столетия
советский
социолог
А.
Аугустинавичюте
разработала одну из самых подробных и достоверных личностных типологий
и стала основательницей научного направления под названием «соционика».
Знания об исследованиях в области установления и описания
психологического типа личности позволяют в большинстве случаев
предугадать модель поведения человека в той или иной ситуации, а
следовательно, возможно и создание мощных механизмов определения
вкусов и пристрастий отдельно взятого индивидуума.
Одним из таких механизмов является реклама, которая продолжает
совершенствовать механизмы влияния на потребности и желания людей и
10
идет в ногу с развитием информационных технологий. В настоящее время
наиболее эффективной является реклама на просторах сети Интернет. Все
виды рекламы в Интернете, а именно: контекстная, баннерная(медийная),
реклама в социальных сетях – в первую очередь ориентированы на то, чтобы
получить максимальную эффективность при минимуме затрат, то есть
направлены на таргетированный, целенаправленный подход к работе с
потребителями. Среди видов таргетинга выделяют следующие:
˗ геотаргетинг позволяет показывать рекламу целевой аудитории того
географического региона, который интересует рекламодателя. Принцип
работы геотаргетинга основывается на данных пользователя о его
местонахождении, которые определяются по IP-адресу;
˗ социально-демографический
таргетинг.
Показ
рекламы
для
определенных категорий пользователей, например, ориентируясь на: возраст,
пол, доход, должность, образование, социальный статус и др.;
˗ поведенческий таргетинг собирает информацию о пользователях и
их поведении с помощью cookie-файлов. Информация аккумулируется в
профилях и содержит статистические данные о действиях пользователей:
какие были введены запросы, просмотрены сайты, какого рода совершены
покупки и т.п.
Однако данные виды таргетированной рекламы больше ориентированы
на действия человека в сети в настоящий момент, не пытаясь определить
причин его выбора. Такие действия пользователя зачастую импульсивны и
выработать алгоритм, который безошибочно определяет предпочтения
индивидуума на основе вышеописанных инструментов не представляется
возможным. Психологический тип личности имеет более перманентное
состояние,
поэтому
ориентируясь
на
эмоционально-психологические
особенности можно добиться более эффективных результатов и увеличить
прибыль от рекламы. Например, рекламная коммуникация для аудитории с
высоким уровнем сознательности и низким уровнем открытости опыту
должна
содержать
посыл
с
выгодой
и
гарантиями
стабильности.
11
Пользователи с противоположными характеристиками, напротив - быстро
увлекаются новыми темами: кампанию эффективнее всего строить вокруг
интересных и необычных свойств продукта.
Зная психотип человека, можно:
˗ лучше понять его ценности и индивидуальные потребности;
˗ структурировать особенности его поведения при взаимодействии с
брендом посредством рекламы;
˗ апеллировать к ценностям каждой группы психотипов через
индивидуальное рекламное предложение.
Разработано множество вариантов тестов и иных видов исследований
для определения психологического типа человека. Среди них выделяется
тест «Сравнение сходных изображений Кагана», который достаточно прост в
проведении и позволяет получить достоверный результат, он используется
для изучения такой стилевой характеристики, как рефлексивность импульсивность.[13, с.79] Испытуемому предъявляются 12 таблиц, на
каждой из которых сверху находится изображение фигуры-эталона, а внизу
располагаются в 2 ряда 8 почти идентичных изображений этой фигуры, из
них только одно полностью соответствует эталону. Испытуемый должен
найти его. Показателем импульсивности рефлексивности служат время
первого ответа и общее число ошибок. Чем короче первое и больше второе,
тем более выражена у испытуемого импульсивность. В таблице 1
представлено сравнение когнитивных стилей.
Таблица 1 – Сравнение когнитивных стилей
Параметр сравнения
Позитивный тип
Негативный тип
1
2
3
Скорость
быстро легко, без труда
медленно с трудом,
прочно, устойчиво во
напряженно поверхностно,
времени
мимолетно
12
Продолжение таблицы 1
1
2
Тщательность
добросовестно
3
халатно небрежно,
аккуратно основательно неряшливо поверхностно
Мотивация
охотно добровольно по
неохотно по обязанности
собственному
под давлением пассивно,
убеждению активно,
вяло, безучастно нерадиво,
включение, увлеченно
лениво
старательно, усердно,
изо всех сил
Регуляция действия
самостоятельно
несамостоятельно
автономно, независимо
подражая бесцельно,
планомерно,
бессистемно, без плана
целенаправленно
периодически,
настойчиво, постоянно
неустойчиво
Когнитивная
осознанно, с
механически, не понимая,
организация
пониманием
методом проб и ошибок
направленно, предвидя
случайно,
последствия
непреднамеренно
рационально, экономно
нерационально,
неэффективно
Общая оценка
Хорошо
Плохо
1.2 Анализ и выбор наблюдаемых параметров
В рамках данной работы рассматриваются два когнитивных стиля:
импульсивный и рефлексивный. Для того, чтобы составить список
параметров, наблюдаемых при посещении веб-страницы определенным
человеком нужно понять какими характеристиками, паттернами поведения
обладает тот или иной психологический тип личности в реальной жизни.
13
Если говорить о представителях импульсивного стиля поведения, то по
многочисленным исследованиям и наблюдениям можно отметить следующие
черты поведения этого типа личности:
˗ подвижность;
˗ эмоциональность;
˗ низкий уровень рефлексии;
˗ коммуникабельность;
˗ инициативность;
˗ импульсивность.
Импульсивные личности предпочитают жить в настоящем времени,
склонны к риску, больше полагаются на кратковременную память.
Уверенность в своих действиях иногда может граничить с безрассудством.
Могут принимать молниеносные решения, недостаточно проанализировав
ситуацию. Люди, относящиеся к импульсивному типу, смотрят на реальные
вещи, планируют реальную деятельность, их взор обращен вовне.
Люди рефлексивного типа же представляют собой противоположность
вышеупомянутому типу личности и для них характерны следующие
основные характеристики:
˗ сдержанность в эмоциональных проявлениях;
˗ высокий уровень развития рефлексии;
˗ замкнутость;
˗ погруженность в себя;
˗ пристрастие к постоянному самоанализу и самокритике.
Рефлексивные
личности
предпочитают
сосредотачиваться
на
собственных чувствах. Субъективная точка зрения таких людей чаще
оказывается сильнее объективной ситуации. Контроль своих эмоций,
спокойствие в принятии решений – все это является чертами, присущими
личностям, успешно выполняющим задачи аналитического типа.
Принимая во внимание различия в чертах характера и шаблонах
поведения импульсивных и рефлексивных людей, а также учитывая
14
ограниченность вариантов выполнения задачи классификации личности на
основе ее поведения на веб-странице, можно сделать вывод о том, что
наиболее удачным набором отслеживаемых параметров, отражающих
специфику поведения конкретного человека, может стать совокупность
интенсивности и характера использования доступных манипуляторов для
ввода информации.
Перечень параметров, используемых в обучении модели нейронной
сети, был составлен экспертным путем посредством участия психологов,
компании «ОрелСайтСтрой» и команды разработчиков «ОГУ им. И.С.
Тургенева». Итоговый список представлен вниманию ниже:
1)
пол (Мужской/Женский (указывается пользователем в начале
Опроса);
2)
возраст (на выбор один из вариантов): младше 18, 18-24, 25-34, 35-
44, 45 и старше (указывается пользователем в начале Опроса);
3)
тип устройства (мобильное устройство, персональный компьютер,
ноутбук без мыши) (указывается пользователем в начале Опроса);
4)
ширина экрана устройства (пикселей);
5)
высота экрана устройства (пикселей);
6)
операционная система (семейство);
7)
время прохождения всех Заданий (фиксируется время начала и
время окончания, после чего вычисляется время прохождения);
8)
длина
имени
пользователя
в
адресе
электронной
почты
(указывается пользователем в начале Опроса);
9)
скорость курсора мыши средняя на 15-секундном интервале.
Определяется как отношение суммы длин всех отрезков в у.е. к общему
времени движения;
10) скорость курсора мыши минимальная на текущем 15-секундном
интервале;
11) скорость курсора мыши максимальная на текущем 15-секундном
интервале;
15
12) расстояние минимальное на текущем 15-секундном интервале,
«пройденное» курсором от старта до остановки, отнесенное к диагонали
экрана (L = S/D);
13) расстояние
среднее
на
текущем
15-секундном
интервале,
«пройденное» курсором от старта до остановки, отнесенное к диагонали
экрана (L = S/D);
14) расстояние максимальное на текущем 15-секундном интервале,
«пройденное» курсором от старта до остановки, отнесенное к диагонали
экрана (L = S/D);
15) количество остановок курсора мыши на текущем 15-секундном
интервале;
16) максимальное положительное ускорение курсора мыши на
текущем 15-секундном интервале;
17) минимальное отрицательное ускорение курсора мыши на текущем
15-секундном интервале;
18) среднее положительное ускорение курсора мыши на текущем 15секундном интервале;
19) среднее отрицательное ускорение курсора мыши на текущем 15секундном интервале;
20) преимущественное положение курсора (слева или справа) в
течение 15-секундного интервала;
21) минимальная скорость скролла мыши в течение 15-секундного
интервала;
22) средняя скорость скролла мыши в течение 15-секундного
интервала;
23) максимальная скорость скролла мыши в течение 15-секундного
интервала;
24) количество скроллов мыши (на текущем 15-секундном интервале);
16
25) скорость набора на клавиатуре средняя за 15-секундный интервал
(символов/сек),
определяемая
как
отношение
количества
набранных
символов к длительности интервалов набора с учетом п. 2.6;
26) факт выделения текста на 15-секундном интервале (Да/Нет);
27) количество раз выделений текста к объему текста на странице (в
рамках 15 секундного интервала);
28) количество выделенных символов к объему всего текста на
странице (в рамках 15-секундного интервала);
29) количество кликов мыши (в рамках 15-секундного интервала);
30) максимальное время между кликами мыши, миллисекунд (в
рамках 15-секундного интервала);
31) длина ответа на вопрос в однострочном поле для ввода текста
(задание с таким полем определяется Заказчиком заранее);
32) длина ответа на вопрос в многострочном поле для ввода текста
(задание с таким полем определяется Заказчиком заранее);
33) количество нажатий клавиши Backspace в процессе ввода текста в
полях, определенных в пунктах 34-35;
34) итоговый показатель классификации пользователя.
Как видно из вышеприведенного списка, помимо большинства
параметров выбранного типа присутствуют также общие параметры, такие
как пол, возраст, характеристики устройства и операционной системы.
Данный подтип признаков был добавлен для большей корреляции со
спецификой среды, находясь в которой пользователь манипулирует
устройствами ввода для достижения собственной конкретной цели.
Получившийся список параметров очевидно избыточный, однако,
сокращать число наблюдаемых значений необязательно, так как полученные
данные могут быть использованы для последующих исследований с целью
определения степени влияния тех или иных параметров на конечный
результат.
17
1.3 Возможные методы анализа полученной информации
Для того чтобы провести анализ методов информации, полученной по
результатам
отслеживания
поведения
пользователя
на
веб-странице,
необходимо классифицировать задачу.
Отнесение
конкретной
задачи
к
определенному
типу
требует
понимания того, какой тип методов анализа данных будет использоваться. В
рамках данной работы выбору предоставляются различные алгоритмы
машинного обучения.
Машинное
интеллекта,
обучение
изучающий
–
обширный
методы
подраздел
построения
искусственного
алгоритмов,
способных
обучаться как на прецедентах, так на постепенном поиске различных
взаимосвязей и закономерностей между объектами.
Если конкретизировать виды машинного обучения, то можно выделить
два основных класса:
1) Контролируемое обучение. Контролируемые алгоритмы обучения
выполняют прогнозирование на основе набора примеров. Каждый пример,
используемый для обучения, помечается собственное идентифицирующей
меткой или определенным числовым значением. Алгоритм данного типа
машинного обучения ищет закономерности зависимостей ряда параметров
примера от идентифицирующей метки. Результатом работы является
наилучший
шаблон
(модель),
позволяющая
с
высокой
точностью
предсказывать значения неразмеченных данных, отданных модели.
Среди классов задач, относящихся к данному типу машинного
обучения, большое распространение получили:
а) Задача регрессии – прогноз на основе выборки объектов с
различными признаками. На выходе должно получиться вещественное число.
б) Задача
классификации. Если
данные
используются
для
прогнозирования категории, контролируемое обучение также называется
классификацией. При наличии только двух вариантов ответов классификация
18
называется двухклассной или биномиальной. Если же вариантов множество,
то классификация называется многоклассовой.
в) Задача прогнозирования отличается тем, что объектами являются
отрезки временных рядов, обрывающиеся в тот момент, когда требуется
сделать прогноз на будущее. Для решения задач прогнозирования часто
удаётся приспособить методы регрессии или классификации, причём во
втором случае речь идёт скорее о задачах принятия решений.
2) Неконтролируемое обучение. При неконтролируемом обучении
точкам данных не присваиваются метки. Вместо этого цель алгоритма
неконтролируемого обучения – определенное упорядочивание данных или
описание их структуры.
В рамках данного типа машинного обучения особое место занимает
задача кластеризации.
Данная задача сходна с задачей классификации, является ее логическим
продолжением, но ее отличие в том, что классы изучаемого набора данных
заранее не предопределены. Кластеризация предназначена для разбиения
совокупности объектов на однородные группы (кластеры или классы). Если
данные выборки представить как точки в признаковом пространстве, то
задача кластеризации сводится к определению «сгущений точек».
Цель кластеризации – поиск существующих структур.
Кластеризация является описательной процедурой, она не делает
никаких
статистических
выводов,
но
дает
возможность
провести
разведочный анализ и изучить «структуру данных».
Само
понятие
исследовании
свои
«кластер»
«кластеры».
определено
неоднозначно:
Переводится
понятие
в
каждом
кластер
как
«скопление».
Кластер можно охарактеризовать как группу объектов, имеющих
общие свойства.
Рассмотрев различные виды и типы задач машинного обучения, а
также приняв во внимание то, что в рамках данного проекта устанавливаются
19
зависимости между двумя типами личности и их характерами поведения на
веб-страницах, можем сделать вывод о том, что типом задачи данной работы
является бинарная классификация.
После определения типа задачи немаловажным пунктом является
выбор алгоритма реализации. Рассмотрим возможные варианты:
˗ Метод ближайших соседей. Метод решения задачи классификации,
относящий объекты к классу, которому принадлежит большинство из k его
ближайших соседей в многомерном пространстве признаков. Это один из
простейших алгоритмов обучения классификационных моделей. Число k –
это количество соседних объектов в пространстве признаков, которое
сравнивается с классифицируемым объектом. Иными словами, если
значением k является 10, то каждый объект сравнивается с 10-ю соседями.
Метод широко применяется в технологиях Data Mining для решения задач
классификации.
В процессе обучения алгоритм просто запоминает все векторы
признаков и соответствующие им метки классов. При работе с реальными
данными, т.е. наблюдениями, метки класса которых неизвестны, вычисляется
расстояние между вектором нового наблюдения и ранее запомненными.
Затем выбирается k ближайших к нему векторов, и новый объект относится к
классу, которому принадлежит большинство из них.
Выбор параметра k противоречив. С одной стороны, увеличение его
значения повышает достоверность классификации, но при этом границы
между классами становятся менее четкими. На практике хорошие результаты
дают эвристические методы выбора параметра k, например, перекрестная
проверка.
Несмотря на свою относительную алгоритмическую простоту метод
показывает хорошие результаты. Главным его недостатком является высокая
вычислительная трудоемкость, которая увеличивается квадратично с ростом
числа записей в наборе данных.
20
˗ Случайный лес. Основная идея данного алгоритма заключается в
построении как можно менее зависимых друг от друга деревьев решений, с
последующим принятием решения путем усреднения в случае регрессии и
голосованием в случае классификации. Зависимость между деревьями
снижается за счет использования случайной выборки с возвращением из
исходных прецедентов и случайного подмножества признаков.
Все деревья строятся по одной схеме:
1) выбирается подвыборка обучающей выборки случайного размера
– по ней строится дерево;
2) для построения каждого разветвления в дереве просматриваются
определенное количество случайных признаков.
3) выбирается наилучшие признак и разветвление по нему. Дерево
строится, как правило, до исчерпания выборки, но в современных
реализациях есть параметры, которые ограничивают высоту дерева,
число объектов в листьях и число объектов в подвыборке, при котором
проводится разветвление.
˗ Машина опорных векторов (SVM). SVM относится к числу первых
алгоритмов машинного обучения, а готовые модели используются во многих
приложениях: от поиска информации до классификации текстов и
изображений. Данный алгоритм может использоваться как для задач
классификации, так и для регрессии.
Модель SVM требует наличия в данных меток классов. В процессе
обучения алгоритм анализирует входные данные и распознает шаблоны в
многомерном пространстве объектов, называемом гиперплоскостью. Все
входные примеры представлены в виде точек в этом пространстве и
отображаются на выходные категории таким образом, что категории
разделяются в общем случае гиперплоскостью.
˗ Нейронная
сеть.
Нейронная
сеть
представляет
собой
набор
взаимосвязанных слоев. Входы являются первым уровнем и вместе с
21
выходным уровнем представляют собой ациклический граф, состоящий из
взвешенных ребер и узлов.
Между входным и выходным уровнем может быть построено
несколько скрытых слоев. Большинство прогностических задач можно легко
выполнить только с одним или несколькими скрытыми слоями. Однако
глубокие нейронные сети (DNN) со множеством скрытых слоев могут быть
очень эффективными в сложных задачах, таких как распознавание
изображений или речи.
Связь между входами и выходами образуются при обучении модели
нейронной посредством подачи на внешний слой данных для процесса
обучения. Граф ориентирован от входного уровня через скрытые слои к
выходному уровню. Все узлы в слое связаны взвешенными ребрами с узлами
в следующем слое.
Получение
результата
работы
сети
для
конкретного
входа
производится посредством вычисления значение для каждого узла в скрытых
слоях и на выходном уровне. Значение устанавливается путем вычисления
взвешенной суммы значений узлов из предыдущего слоя. Затем к этой
взвешенной сумме применяется функция активации.
Для реализации подсистемы анализа данных системы определения
психотипа пользователя требуется использовать возможности нейронной
сети. Во-первых, это является основным требованием заказчика, во-вторых,
инструменты по созданию нейронной сети позволяют создать достаточно
гибкую архитектуру, которую можно легко преобразовывать с целью
исследования возможностей полученной модели.
1.4 Анализ аналогичных решений
Определение психотипа человека с целью отображения направленной
рекламы одной из первых применила компания Mail.Ru Group. Для
формирования обучающей выборки департамент Big Data Mail.Ru Group и
22
проект Research.Mail.Ru на основании опросника Хромова протестировали
несколько сотен тысяч пользователей социальных сетей. [14, с.1]
В качестве основной методологии психотипирования была выбрана
BIG 5 / OCEAN, которая берет за основу присутствие в человеке пяти общих
и относительно независимых черт:
˗
открытости опыту;
˗
сознательности;
˗
экстраверсии;
˗
доброжелательности
(дружелюбия,
способности
прийти
к
согласию);
˗
нейротизма
(противоположный
полюс
—
эмоциональная
стабильность).
В качестве определяющей цели были представлены пользователи с
наиболее ярко- и слабовыраженными значениями по каждой шкале. В
таблице 2 представлены выявленные таргетинги.
Таблица 2 – Классификация признаков по шкалам методологии BIG5
Шкалы BIG5
Высокий уровень
Низкий уровень
1
2
3
Открытость опыту
Сознательность
новаторы, стремящиеся
прагматики,
к обучению и
ориентируются на данные
инновациям, с
при принятии решений,
положительным
консерваторы по
отношением к риску
отношению к инновациям
выполняют
увлекающиеся личности,
обязательства,
принимают решения
предпочитают
спонтанно
планирование
23
Продолжение таблицы 2
1
Экстраверсия
2
3
получают энергию из
получают энергию из
внешнего мира,
своего внутреннего мира,
открыты к контакту и
менее расположены к
общению:
разговорам и контакту:
˗
душа компании;
˗
немногословны;
˗
часто в центре
˗
думают много, прежде
внимания;
˗
чувствуют себя
чем говорить или
действовать;
комфортно среди
˗
людей;
внимание к себе;
˗
охотно начинают и
˗
не любят привлекать
молчат среди
поддерживают
незнакомцев;
разговоры;
˗
˗
легко находят общий
предпочитают узкие
компании.
язык с незнакомыми
людьми
Доброжелательность дружелюбны,
абстрагированы, могут
командны,
быть подозрительны по
сострадательны
отношению к другим,
восприниматься как
сложные
Нейротизм
эмоциональная
эмоциональная
нестабильность,
стабильность,
24
Продолжение таблицы 2
Нейротизм
преобладают
преобладают позитивные
негативные эмоции
эмоции, (сдержанность)
(эмоциональность)
Низкий уровень открытости опыту и низкий уровень нейротизма
Прагматичный и традиционный. Экономный. Хочет, чтобы все как у людей
или не хуже, чем у людей. Сверхценность - деньги. Хозяйственный и
конкретный. Упор на существительные, конкретный, краткий посыл с явной
ценностью для потребителя. Высокий уровень открытости опыту в сочетании
с высоким уровнем экстраверсии. Быстро думают, генерируют новые идеи,
убеждают окружающих и быстро увлекаются новыми темами. Свобода для
них - самая главная ценность. Один из жизненных принципов: «Сдаваться
раньше времени не спортивно!» Можно поймать на «слабо», «на интерес», на
возможность сэкономить время любым способом или даже продать продукт
необычного состава.
Методами
машинного
обучения
были
построены
модели
для
определения психотипов пользователей на основании корреляции их
интересов и поведения в интернете с данными пользователей из обучающей
выборки.
Еще одна работа, которая была представлена на конференции «2nd
Russian-Pacific Conference on Computer Technology and Applications»,
предполагает
разработку
и
реализацию
методов
и
алгоритмов
автоматического определения психотипа человека на основе анализа
видеозаписи психологического тестирования испытуемого. Производится
стандартный тест во время отбора кандидатур на вакантное место,
претенденту задаются вопросы, идёт видеозапись, на ней можно увидеть
жесты и мимику человека на собеседовании. Эта запись отправляется на вход
искусственной нейронной сети, которая знает, какие заданы вопросы и
25
какова реакция на них, и затем может выдать результат: склонен ли,
кандидат, например, к обману, дисциплинирован ли. На данный момент
система обучена распознавать два психологических типа. В дальнейшем
планируется увеличить практическую пользу системы путем добавления
возможности распознавания и других типов.
Среди методов определения психологического типа выделяется
биометрия на основе данных мыши и клавиатуры, которая рассматривается в
научном сообществе с 2007 года. Хотя пользователю кажется, что курсор
мыши
перемещается
плавно,
для
компьютера
движение
мыши
представляется последовательным набором дискретных данных. Одна
единица таких данных содержит положение курсора, состояние кнопок
мыши и текущее время события. Под событием мыши понимается как
нажатие кнопки, так и движение самой мыши. Разные авторы используют
разные наборы ключевых характеристик, однако общая методология сбора и
анализа схожа. Программное обеспечение, которое разработал профессор
Джеффри Дженкинс из университета Бригама Янга, позволит определять
эмоциональное состояние человека по движению курсора мыши.
В ходе испытаний Дженкинс выявил, что раздражение или злость
заставляют человека двигать мышку быстрее и более резко, а разочарование
или грусть вызывают обратный эффект – курсор перемещается медленней и
неточно. Во время исследования ученый целенаправленно злил участников:
тесты загружались медленно, а за неправильные ответы следовало наказание.
Дженкинс уверен в том, что его разработка будет полезной в сфере интернетмаркетинга и конструировании сайтов. Программа поможет выявить
реакцию пользователей того или иного ресурса, их разочарование или же
благосклонность.
1.5 Требования к системе
Требования по реализации подсистемы анализа данных пользователя и
подсистемы хранения данных:
26
1)
Наблюдение осуществляется только в ходе выполнения заданий.
2)
Параметры 10-36 сохраняются в виде единого JSON-массива и раз
в 15 секунд передаются на сервер (в базу данных). Определяется
оптимальная структура JSON-массива.
3)
Хранятся все 15-секундные сессии с привязкой к уникальному
идентификатору пользователя (параметр 9). Это необходимо для возможного
вычисления минимальных/средних/максимальных значений не только в
рамках 15-секундного интервала, но и в рамках всей сессии пользователя и
исследования взаимосвязи этих параметров.
4)
В случае если параметр не определен (например, действие не
проводилось), в массив записывается пустое значение NULL.
5)
Наблюдение осуществляется только в случае активности окна
браузера. Если пользователь переключился на другую вкладку, сбор данных
должен быть приостановлен, и текущий 15-секундный интервал должен быть
поставлен «на паузу».
6)
Для
предотвращения
сбоя
работы
наблюдателя
в
случае
одновременного открытия более одной вкладки в браузере необходимо
предусмотреть механизм присвоения уникального идентификатора каждой
вкладке, и разделение потоков данных от разных вкладок при отправке на
сервер.
7)
Все параметры, характерные для опроса в целом (не относящиеся
к 15-секундным интервалам) фиксируются скриптами опроса и заданий в
виде JSON-массива в локальное хранилище браузера, откуда их может
считать разрабатываемая подсистема сбора данных.
8)
данных
Подсистема сбора данных должна полностью сохранять в базу
траекторию
движения
мыши,
отслеживаемую
по
событию
«MouseMove», а также клики мышью и нажатия клавиш на клавиатуре,
привязанные
к
временным
отметкам.
Для
реализации
допустимо
использовать любые готовые алгоритмы «record mouse movement javascript».
27
9)
После отправки вычисленных параметров на сервер и получения
подтверждения получения, все данные 15-секундного интервала стираются
из локальной памяти. В случае, если по каким-то причинам сервер не принял
данные и не вернул подтверждение успешного получения, данные должны
быть отправлены повторно вместе со следующей 15-секундной сессией.
10) Для
мобильных
устройств
осуществляется
сбор
всех
перечисленных выше параметров кроме 21-26 с учетом следующих
особенностей:
˗ событию «движения курсора мыши» эквивалентно событие
«свайп» (перемещение курсора по сенсорному экрану),
˗ событию «клик» эквивалентно событие «тап» (нажатие пальцем
на сенсорный экран)
Требования к обучению и функционированию подсистемы нейронной
сети:
1) Три
четверти
полученных
результатов
(1000
респондентов,
исключая отбракованных по шкале «ложь») используется для обучения
нейросети. Четверть полученных результатов должна быть направлена на
проверку результативности работы обученной модели.
2) Обученная нейросеть должна иметь веб-интерфейс, который по
результатам обучения может определять и возвращать тип темперамента на
основе поведенческих реакций, переданных ему в виде JSON-запроса.
3) Нейросеть
должна
иметь
возможность
определять
тип
поведенческой реакции независимо от количества снятых характеристик
(могут отсутствовать, например, такие параметры как скорость набора на
клавиатуре
и
т.п.).
В
минимальном
случае
пользователь
может
характеризоваться 10-12 параметрами.
4) Максимальное время работы алгоритма нейросети по определению
психотипа на основе переданных поведенческих характеристик (время
ответа) в условиях прохождения сигнала в локальной сети 100 гб/с в
условиях работы на оборудовании не хуже Intel 2xXeon 2,13 Ггц (2x4 ядра),
28
32 Gb DDR3, 2 x 120Gb SSD, 1 x 1Tb SATA не должно превышать 5 секунд
при количестве одновременных подключений не более 100.
Прочие
технические
требования
к
реализации
программного
обеспечения
5)
Предпочтительная операционная система – CentOS 7.
6)
Предпочтительный язык реализации серверной части – PHP 7.
7)
База данных – MySQL.
8)
Язык
реализации
нейросети
не
определен,
ограничивается
операционной системой.
9)
Помимо
реализации
нейросети,
проанализировать
работу
классических алгоритмов машинного обучения.
10) Реализация функций модуля наблюдения на клиенте – на языке
javascript с использованием предоставляемых Заказчиком интерфейсов
(примеров), позволяющих бесконфликтно подключать любые js-скрипты и
библиотеки
к
любому
сайту
и
придерживаться
единого
стиля
программирования.
11) Возможности интерфейса:
˗ подключение javascript-файлов непосредственно в страницу
(единая точка входа JS) одним из вариантов:
а) внедрение javascript при загрузке страницы;
б) вызов через jquery внутри методов;
˗ разделение по логическим классам (без использования отдельных
компонентов в одном файле, подключение их «в точке входа»);
˗ наличие
своего
jQuery,
возможно
использование
других
библиотек;
˗ использование
едином
пространстве
имён
для
всех
объектов/методов;
˗ возможность безопасного запуска методов (отсутствие метода не
вызовет ошибки JS).
29
В конечном итоге система должна представлять обученный по
результатам прохождения опроса и заданий алгоритм нейросети, который
получает на вход данные о поведении посетителя сайта в виде JSON-массива
посредством HTTP-запроса и возвращает в ответе результат – психотип
(рефлексивный или импульсивный), к которому вероятнее всего относится
данный посетитель.
30
2 СПЕЦИФИКАЦИИ ПОДСИСТЕМЫ АНАЛИЗА ДАННЫХ
ПОЛЬЗОВАТЕЛЯ ВЕБ-САЙТА
2.1 Архитектура системы
Архитектура системы определения психотипа пользователя веб-сайта
представляет
собой
частный
случай
клиент-серверной
архитектуры.
Основными компонентами являются:
˗ сервер, управляющий хранением данных, доступом и защитой,
выполняющий запросы клиента;
˗ клиент, предоставляющий интерфейс пользователя, выполняющий
логику приложения, посылающий запросы к серверу и получающий ответы
от него;
˗ сеть
и
коммуникационное
программное
обеспечение,
осуществляющее взаимодействие между клиентом и сервером посредством
сетевых протоколов.
Для реализации системы определения психотипа пользователя вебсайта
такая
архитектура
предпочтительна,
так
как
она
полностью
удовлетворяет требованиям заказчика, а именно: способствует снижению
сетевого трафика при выполнении запросов, приспосабливается к росту
количества пользователей и увеличению объема базы данных без замены
программного обеспечения, обеспечивает защищенность пользовательских
данных, доступ к которым имеет лишь тот, кто обладает соответствующими
правами доступа, что немаловажно при соблюдении коммерческой тайны
участниками проекта.
Требуется пояснить некоторые особенности, которые встречаются в
архитектуре проектируемой системы определения психотипа пользователя.
Для системы необходимо спроектировать два режима: режим обучения и
режим определения психотипа.
31
Режим обучения представляет из себя обучение нейронной сети на
основе выборки данных, полученных от пользователей, проходивших
тестирование.
Архитектура режима обучения состоит из следующих компонентов:
Подсистема сбора данных пользователя:
1) модуль
наблюдения
–
программный
комплекс,
который
отслеживает поведенческие реакции пользователей в процессе прохождения
заданий теста и фиксирует их в базе данных;
2) сервер
хранения
данных
–
обслуживающее
устройство,
обеспечивающее взаимосвязь между базой данных, модулем наблюдения и
модулем получения;
3) база данных сессий пользователя – организованная структура,
предназначенная для хранения, изменения и обработки информации о
сессиях пользователей.
Подсистема анализа данных пользователя:
1) модуль получения - программный комплекс, который осуществляет
получение информации из базы данных сессий пользователя;
2) модуль
обработчик
–
программный
комплекс,
который
осуществляет вычисление необходимых для обучения нейронной сети
параметров;
3) модуль анализа – программный комплекс, который осуществляет
анализ параметров сессий и приводит их к виду, пригодному для обучения
нейронной сети;
4) модуль построения модели нейронной сети - программный
комплекс,
который
реализует
построение
модели
спроектированной
нейронной сети и обучает ее;
5) модель нейронной сети – файл, хранящий модель нейронной сети,
на основании которой происходит классификация по входным параметрам.
Архитектура режима обучения системы определения психотипа
представлена на рисунке 1.
32
Рисунок 1 – Архитектура системы в режиме обучения
Что касается режима определения психотипа системы, то происходит
упразднение компонентов, связанных с обучением модели нейронной сети,
так как на этом этапе уже имеется готовый программный комплекс,
осуществляющий
классификацию
полученных
данных.
Так
же
из
компонентов системы было убрано хранилище данных, потому что для
работы системы в реальном времени не требуется долгосрочно хранить
информацию, вместо этого был добавлен другой механизм передачи сессий
пользователя.
Среди компонентов архитектуры режима определения психотипа были
выявлены:
Подсистема сбора данных пользователя:
1) модуль наблюдения;
2) принимающий
сервер
–
обслуживающее
устройство,
обеспечивающее постановку в очередь полученных сессий;
3) очередь сессий – организованная структура, предназначенная для
хранения информации о сессиях пользователей.
33
Подсистема анализа данных пользователя:
1) классифицирующий
сервер
–
обслуживающее
устройство,
обеспечивающее возврат результата классификации;
2) модуль классификации;
3) модель нейронной сети.
Сервер стороннего ресурса – стороннее обслуживающее устройство,
принимающее результат классификации пользователя для дальнейшей
работы с ним.
Архитектура режима определения психотипа изображена на рисунке 2.
Рисунок 2 – Архитектура системы в режиме определения психотипа
2.2 Функциональная модель подсистемы анализа данных
Функционирование подсистемы анализа данных предполагает работу в
двух режимах:
˗ режим обучения нейронной сети;
˗ режим определения психотипа пользователя.
Для демонстрации функционала подсистемы анализа данных в режиме
обучения
нейронной
сети
была
построена
диаграмма
вариантов
34
использования, представленная на рисунке 3. На USECASE-диаграмме
выделен один актер – подсистема сбора данных.
Подсистема сбора данных – программная система, обеспечивающая
отслеживание действий пользователя на веб-странице, сбор и хранение
необходимых данных, а также функционал для выдачи информации по
запросу.
Как видно из рисунка подсистема сбора параметров может выполнять
следующие действия:
˗ выдача
общей
информации
о
пользователях
и
результатах
тестирования;
˗ выдача наборов сессий пользователей.
После получения подсистемой анализа данных общей информации о
пользователях
и
результатах
тестирования
происходит
сохранение
накопленных данных в локальное хранилище. Успешность этого шага
определяет возможность получения подсистемой анализа данных наборов
сессий тех пользователей, общая информация о которых корректна.
Наборы сессий пользователей также сохраняются в локальное
хранилище во избежание повторных дорогостоящих запросов к подсистеме
сбора данных.
Следующим прецедентом в режиме обучения нейронной сети является
получение поведенческих параметров пользователя следующих типов:
1) Поведенческие
параметры
пользователей,
связанные
использованием мыши. Данный класс параметров включает:
˗ вычисление максимальной скорости скролла курсора мыши;
˗ вычисление минимальной скорости скролла курсора мыши;
˗ вычисление средней скорости движения курсора мыши;
˗ вычисление максимальной скорости движения курсора мыши;
˗ вычисление минимальной скорости движения курсора мыши;
˗ вычисление количества остановок курсора;
с
35
˗ вычисление максимального расстояния между остановками
курсора;
˗ вычисление
минимального
расстояния
между
остановками
курсора;
˗ вычисление среднего расстояния между остановками курсора;
˗ вычисление минимального положительного ускорения курсора
мыши;
˗ вычисление максимального положительного ускорения курсора
мыши;
˗ вычисление среднего положительного ускорения курсора мыши;
˗ установление факта наличия выделенного текста;
˗ вычисление средней скорости скролла курсора мыши;
˗ вычисление среднего негативного ускорения курсора мыши;
˗ вычисление максимального времени между кликами курсора
мыши;
˗ вычисление количества кликов курсора мыши;
˗ вычисление преобладающей позиции курсора мыши;
˗ вычисление количества скорллов курсора мыши.
2) Поведенческие
параметры
пользователей,
связанные
с
использованием клавиатуры. Данный класс параметров включает:
˗ вычисление количества выделенных символов отнесенного к
общей длине текста;
˗ вычисление количества выделений текста отнесенного к общей
длине текста;
˗ вычисление средней скорости нажатия клавиш;
˗ количество нажатия клавиши Backspace;
˗ вычисление длины ответа на вопрос в многострочном поле для
ввода текста;
˗ вычисление длины ответа на вопрос в однострочном поле для
ввода текста.
36
3) Получение прочих параметров пользователей. Данный класс
параметров включает:
˗ получение пола пользователя;
˗ получение возраста пользователя;
˗ получение типа устройства пользователя;
˗ получение ширины экрана устройства пользователя;
˗ получение высоты экрана устройства пользователя;
˗ получение типа операционной системы устройства пользователя;
˗ вычисление общего времени прохождения теста пользователем;
˗ получение длины имени пользователя;
˗ получение метки класса пользователя.
Набор всех вышеперечисленных параметров также перемещается в
локальное хранилище для предотвращения возможности потери данных.
Для демонстрации функционала подсистемы анализа данных в режиме
определения психотипа пользователя была построена диаграмма вариантов
использования, представленная на рисунке 4. В подсистеме выделено 2
актера:
˗ подсистема сбора данных – программная система, обеспечивающая
отслеживание поведения пользователя на веб-странице, построение на
основе полученных данных сессии пользователя и немедленная передача
информации подсистеме анализа данных;
˗ внешний ресурс – веб-ресурс, находящийся вне системы, задачей
которого является прием результата классификации сессии пользователя.
Подсистема
пользователя
от
анализа
данных
подсистемы
всегда
сбора
готова
параметров.
к
приему
Текущую
сессии
сессию
пользователя подсистема анализа данных использует для получения
поведенческих параметров пользователя всех типов, описанных в разделе
режима обучения нейронной сети.
37
Рисунок 3 – Режим обучения нейронной сети
После успешного вычисления набора поведенческих параметров
пользователя подсистема анализа данных подготавливает информацию к
классификации моделью нейронной сети. На данном этапе подготовленный
набор параметров может быть классифицирован. Обязательным фактором,
определяющим наличие функционала для классификации в целом является
успешность загрузки модели нейронной сети.
38
В случае успешной классификации результат пересылается внешнему
ресурсу для дальнейшего использования.
Если сравнивать между собой режимы функционирования подсистемы
анализа данных, то можно заметить, что режим обучения нейронной сети
направлен на сбор, сохранение, подготовку большого объема информации,
предназначенной исключительно для обучения и тестирования модели
нейронной сети. Работа подсистемы анализа данных в режиме определения
психотипа пользователя ориентирована на условия реальной эксплуатации, в
которых важно быстро получить конкретный результат.
Рисунок 4 – Режим определения психотипа пользователя
39
2.3 Информационная модель подсистемы анализа данных
Говоря об абстрактном представлении информации в каждом режиме
функционирования подсистемы анализа данных можно выделить следующие
типы данных:
˗ входные данные;
˗ промежуточные данные;
˗ выходные данные.
Рассматривая режим обучения нейронной сети, можно выделить
следующие сложные типы входных данных:
˗ общая информация о пользователе и результатах прохождения теста;
˗ набор объектов, содержащих сессии пользователя.
Первый тип входных данных представлен на рисунке 5.
Данный тип информации можно структурировать следующим образом:
˗ Id – идентификатор, однозначно определяющий пользователя;
˗ Gender – пол пользователя;
˗ Age – возраст пользователя;
˗ Email – адрес электронной почты пользователя;
˗ AMeta – составной элемент, содержащий следующие поля:
1) ATimer – составной элемент, содержащий следующие поля:
1.1) SStart – время начала тестирования;
1.2) SEnd – время окончания тестирования;
2) AResult - составной элемент, содержащий следующие поля:
1.1) IMistakes – количество ошибок;
1.2) AAnswers
–
составной
элемент,
содержащий
следующие поля:
а)
IQuestionId – идентификатор вопроса:
б)
SAnswerType – тип ответа;
в)
IQuestionType – тип вопроса;
г)
SAnswerDateEnd – время окончания ответа;
д)
SAnswerDateStart – время начала ответа;
40
˗ Device_os – операционная система устройства;
˗ Device_type – тип устройства.
Рисунок 5 – Общая информация о пользователе
и результатах прохождения теста
Общая схема второго типа входных данных представлена на рисунке 6.
В сессии пользователя можно выделить следующие необходимые
элементы:
41
˗ Participant_id
–
идентификатор,
однозначно
определяющий
пользователя;
˗ Width – ширина экрана устройства пользователя в пикселях;
˗ Height – высота экрана устройства пользователя в пикселях;
˗ Z – показатель классификации;
˗ Mouse_move – составной элемент, содержащий следующие поля:
1) X – координата курсора по оси Ox;
2) Y – координата курсора по оси Oy;
3) Time – временная отметка в миллисекундах.
˗ Mouse_selection – составной элемент, содержащий следующие поля:
1) Text – выделенный курсором текст;
2) Time – временная отметка в миллисекундах;
3) AllTextLength – общий объем текста на странице.
˗ Mouse_click – составной элемент, содержащий следующие поля:
1) X – координата курсора по оси Ox;
2) Y – координата курсора по оси Oy;
3) Time – временная отметка в миллисекундах;
˗ Mouse_scroll – составной элемент, содержащий следующие поля:
1) Time – временная отметка в миллисекундах;
2) ScrollY – величина скролла по оси Oy в пикселях;
˗ Key_press – составной элемент, содержащий следующие поля:
1) Code – код клавиши;
2) Time – временная отметка в миллисекундах;
3)
FocusOn – наличие фокуса на поле ввода во время ввода
символа;
4) ElemName – имя поля ввода;
5) ElemType – тип поля ввода.
42
Рисунок 6 – Сессия пользователя
43
Среди промежуточных типов данных режима обучения нейронной сети
можно выделить следующие:
˗ набор поведенческих параметров пользователя;
˗ многочисленных вспомогательные структуры данных, создающиеся
и применяющиеся в процессе вычисления поведенческих параметров
пользователя.
Общая схема первого промежуточного типа данных режима обучения
нейронной сети подсистемы анализа данных представлена на рисунке 7.
Рисунок 7 – Набор поведенческих параметров пользователя
44
Представленный
класс
информации
является
типом
данных,
предназначенном непосредственно для обучения нейронной сети в составе
большой выборки. Как видно из схемы, некоторые поля, предоставляющие
общую информацию о пользователе идентичны полям первого и второго
типа входных данных режима обучения нейронной сети. Также в
единственном промежуточном типе данных первого типа функционирования
подсистемы анализа данных появляются следующие поля:
˗ Test_time – общее время прохождения теста пользователем;
˗ Name_length – длина имени пользователя;
˗ Stop_count – общее количество остановок курсора;
˗ Min_start_stop_distance
–
минимальное
расстояние
от
старта
движения курсора до его остановки;
˗ Max_start_stop_distance – максимальное расстояние от старта
движения курсора до его остановки;
˗ Avg_start_stop_distance – среднее расстояние от старта движения
курсора до его остановки;
˗ Min_cursor_speed – минимальная скорость движения курсора;
˗ Max_cursor_speed – максимальная скорость движения курсора;
˗ Avg_cursor_speed – средняя скорость движения курсора;
˗ Max_positive_acceleration – максимальное положительное ускорение
курсора;
˗ Min_positive_acceleration – минимальное положительное ускорение
курсора;
˗ Avg_positive_acceleration
–
среднее
положительное
ускорение
–
среднее
отрицательное
ускорение
курсора;
˗ Avg_negative_acceleration
курсора;
˗ Max_scroll_speed – максимальная скорость скролла;
˗ Min_scroll_speed – минимальная скорость скролла;
˗ Avg_scroll_speed – средняя скорость скролла;
45
˗ Scroll_count – количество скроллов;
˗ Avg_key_press_speed – средняя скорость набора текста;
˗ Mouse_click_count – общее количество кликов мыши;
˗ Max_mouse_click_time – максимальный временной промежуток
между кликами мыши;
˗ Fact_of_selection – факт выделения текста;
˗ Backspace_press_count – общее количество нажатий клавиши
«Backspace»;
˗ Selection_count – общее количество выделений текста;
˗ Selected_symbols_count – общее количество выделенных символов,
отнесенное к общему количеству символов на странице;
˗ Textarea_answer_length – длина ответа в многострочном поле ввода;
˗ Singleline_answer_length – длина ответа в однострочном поле ввода;
Общая схема второго типа промежуточных данных режима обучения
нейронной
сети
в
лице
ломаной
движения
курсора
манипулятора
представлена на рисунке 8.
Ломаная курсора манипулятора состоит из набора элементов каждый
из которых имеет следующие поля:
˗ sol – старт отрезка ломаной. Данное поле является составным и
включает следующие элементы:
1) time – временная отметка в миллисекундах;
2) x – координата по оси Ox;
3) y – координата по оси O.
˗ eol – окончание отрезка ломаной. Данное поле является составным и
содержит идентичные элементам старта отрезка ломаной поля;
˗ line – общая информация об отрезке ломаной. Данное поле является
составным и включает следующие элементы:
1) length – длина отрезка ломаной;
2) time
–
время
миллисекундах.
прохождения
отрезка
ломаной
в
46
Рисунок 8 – Ломаная движения курсора манипулятора
В качестве выходных данных режима обучения нейронной сети
подсистемы анализа данных можно выделить файл модели нейронной сети,
загрузка
содержимого
которого
в
сторонний
программный
модуль
47
предоставляет
функционал
по
классификации
объектов
информации
подходящего типа.
Для режима работы подсистемы анализа данных в режиме определения
психотипа пользователя в качестве входных данных также служат сессии
пользователей. Отличие от первого режима функционирования подсистемы
состоит в том, что входная информация представляет собой не набор
элементов одинакового типа, а одиночный объект.
Промежуточный
пользователя
также
тип
данных
представлен
режима
набором
определения
психотипа
поведенческих
параметров
пользователя. Однако в данном режиме функционирования подсистемы
требуется всего один объект данных для классификации.
Общая схема выходных данных режима определения психотипа
пользователя подсистемы анализа данных представлена на рисунке 9.
Данный тип информации характеризуется следующими полями:
˗ Participant_id
-
идентификатор,
однозначно
определяющий
пользователя;
˗ Result_class – результат классификации сессии пользователя.
Рисунок 9 – Выходные данные режима определения психотипа пользователя
48
2.4 Особенности организации взаимодействия с внешним ПО
Само по себе существование подсистемы сбора данных пользователя
веб-сайта обусловлено необходимостью анализа полученных параметров для
выявления психотипа человека. Как уже было описано ранее, подсистемы
являются внешними по отношению друг к другу, где подсистема сбора
данных является источником, а подсистема анализа данных, соответственно,
приемником
информации,
поэтому
необходимо
организовать
их
взаимодействие для беспрерывной работы системы определения психотипа.
Среди
способов
интеграции
различных
приложений
выделяют
следующие:
˗
Передача
файла.
Взаимодействие
между
приложениями
осуществляется с помощью файлов, в которые помещаются общие данные.
˗
Общая
база
данных.
Взаимодействие
между
приложениями
осуществляется с помощью базы данных, в которой сохраняется общая
информация.
˗
Удаленный вызов процедуры. Взаимодействие между приложениями
осуществляется с помощью удаленного вызова процедур, использующихся
для выполнения действий или обмена данными.
˗
Обмен
сообщениями.
Взаимодействие
между
приложениями
осуществляется с помощью системы обмена сообщениями, которые
используются для обмена данными и выполнения действий.
В
режиме
обучения
две
подсистемы
реализуют
механизм
взаимодействия посредством использования общей базы данных. Подсистема
сбора данных осуществляет передачу полученных параметров пользователя
на сервер хранения данных. Далее серверная часть реализует сохранение
переданной информации в базе данных сессий пользователя. Подсистема
анализа данных посредством запросов к серверу хранения данных получает
хранимые в базе данных параметры сессий пользователя и использует их для
дальнейшей обработки.
49
Что касается самих данных, которые участвуют в процессе сохранения
и передачи через сервер используются общая информация о пользователе и
результатах прохождения теста, сессионная информация пользователя.
Ситуация
несколько
меняется,
если
говорить
о
механизме
взаимодействия подсистем в режиме определения психотипа. Как таковой
базы данных данный режим не предусматривает. Переданные сессионные
данные пользователя сохраняются в очередь, откуда далее их получает
классифицирующий сервер. То есть модуль наблюдения все так же
осуществляет передачу данных серверу, который добавляет в очередь новые
объекты. Классифицирующий сервер постоянно инициирует проверку
состояния очереди на наличие новых данных, чтобы получить их и
приступить к дальнейшей обработке в подсистеме анализа данных.
Различия в организации взаимодействия двух режимов работы системы
можно объяснить тем, что использование базы данных в режиме обучения
необходимо
для
сбора
статистической
информации, которая
может
потребоваться для дальнейших исследований и увеличения точности
классификации модели нейронной сети. В режиме определения психотипа,
когда уже имеется готовый классификатор, не имеет смысла хранить
избыточную
информацию,
основная
задача
–
оперативно
передать
сессионные данные нейронной сети, получить результат и отправить его на
сервер стороннего ресурса.
50
3 ПРОЕКТИРОВАНИЕ ПОДСИСТЕМЫ АНАЛИЗА ДАННЫХ
ПОЛЬЗОВАТЕЛЯ ВЕБ-САЙТА
3.1 Структура ПО
Для облегчения эксплуатации, обеспечения инкапсуляции, удобства
отладки, а также возможной модификации для построения подсистемы
анализа данных была выбрана модульная архитектура.
3.1.1 Режим обучения нейронной сети
В подсистеме анализа данных в режиме обучения нейронной сети
выделены следующие модули:
˗ Downloader – модуль сохранения информации;
˗ Handler
–
модуль
получения
поведенческих
параметров
пользователя;
˗ Data_analyze – модуль анализа данных;
˗ Model – модуль нейронной сети;
˗ Config – модуль с конфигурацией проекта.
Модули подсистемы взаимодействуют посредством включения одного
в другой. Большинство модулей представлено сложными пользовательскими
типами данных, содержащими методы, предназначенные для внешнего
использования, что обеспечивает сокрытие реализации методов для
пользователя.
Диаграмма классов данного режима функционирования подсистемы
анализа данных представлена на рисунке 10.
51
Рисунок 10 – Диаграмма классов режима обучения нейронной сети
52
3.1.1.1 Модуль сохранения информации
Данный модуль выполняет запрос информации у подсистемы сбора
данных, сохранения полученной информации, взаимодействие с модулем
получения поведенческих параметров пользователя, а также сохранения
полученных параметров.
Основой данного модуля является пользовательский тип данных
Downloader, среди полей которого были выделены:
˗ json_data
–
файл
для
сохранения
общего
списка
сессий
пользователей;
˗ all_sessions – общий список сессий пользователей;
˗ headers – информация необходимая для осуществления запросов к
подсистемы сбора данных.
Среди методов данного класса были выделены:
˗ init – метод инициализации экземпляра класса. Работа данного
метода заключается в осуществлении подготовительных операций, а
первоначальной инициализации полей класса.
˗ delete – метод удаления экземпляра класса. Данный метод необходим
для получения уведомления о завершении работы объекта.
˗ get_participant_with_sessions – метод получения общей информации
данных. Параметром данного метода является идентификатор пользователя
Работа метода заключается в проведении серии запросов к подсистеме сбора
данных на получение следующих типов информации:
1) общей информации о пользователях и результатах тестирования;
2) сессий пользователей.
Полученные данные проходят валидацию и объединяются для удобства
дальнейшего использования.
˗ handle_participant – метод вычисления поведенческих параметров
пользователя.
пользователя.
Параметром
Вычисление
данного
метода
параметров
является
происходит
набор
сессий
посредством
использования модуля Handler на основе полученной сессии пользователя.
53
В данном модуле также выделен основной метод, задающий общую
последовательность действий и сохранение информации.
3.1.1.2 Модуль получения поведенческих параметров
пользователя
Работа данного модуля заключается в вычислении поведенческих
параметров пользователя на основе полученной сессии. Модуль представлен
классом Handler, среди полей которого были выделены:
˗ gender_index – пол пользователя;
˗ age – возраст пользователя;
˗ device_type – тип устройства пользователя;
˗ device_os – операционная система устройства пользователя;
˗ name_length – длина имени пользователя;
˗ test_time – общее время прохождения теста пользователем;
˗ participant_id – идентификатор пользователя;
˗ path_list – трек движения курсора;
˗ scroll_list – трек скролла;
˗ key_press_list – трек нажатия клавиш на клавиатуре;
˗ mouse_click_list – трек кликов мыши;
˗ mouse_selection_list – трек выделения текста курсором;
˗ width – ширина экрана устройства пользователя;
˗ height – высота экрана устройства пользователя;
˗ screen_diagonal – диагональ экрана устройства пользователя;
˗ cursor_path – ломаная движения курсора;
˗ start_stop – схема стартов и остановок курсора;
˗ acceleration_list – схема ускорений курсора на отдельных участках
траектории движения курсора;
˗ width_middle – величина центра экрана пользователя;
˗ bias_list – схема смещений веб-страницы по оси Оу при скролле в
отслеживаемые моменты времени;
54
˗ time_difference_list – схема временных разностей отслеживаемых
моментов начала скролла;
˗ scroll_speed
–
схема
скорости
скролла
в
разные
моменты
отслеживаемого времени;
˗ start_stop_distance – схема расстояний между стартами и остановками
курсора;
˗ key_press_stop_list – схема остановок пользователя при печати;
˗ z – показатель класса пользователя.
Среди методов данного класса были выделены:
˗ init – метод инициализации объекта класса. Параметром данного
метода является сессия пользователя. Данный метод необходим для
первичной инициализации полей класса и построения схем;
˗ get_parameters – метод получения параметров. Главный метод,
собирающий вычисленные поведенческие параметры пользователя в единый
объект;
˗ get_width_middle – метод получения величины центра экрана
устройства пользователя. Параметром данного метода является ширина
экрана устройства пользователя;
˗ get_screen_diagonal – метод получения величины диагонали экрана
устройства пользователя. Параметрами данного метода являются ширина и
высота экрана;
˗ get_distance
–
метод
получения
расстояния
между
двумя
положениями курсора на экране. Параметрами данного метода являются
координаты положений курсора;
˗ get_acceleration – метод получения ускорения курсора в пределах
двух отрезков ломаной движения курсора. Параметрами являются начальная
и конечная скорости курсора в пределах двух отрезков ломаной а также
время прохождения второго отрезка;
˗ get_acceleration_list – метод получения схемы ускорений курсора.
Параметром данного метода является схема стартов и остановок курсора;
55
˗ get_int_param_difference_list – метод получения списка разностей
временных отметок соседних элементов трека скролла. Параметрами данного
метода являются трек скролла, а также название поля числового параметра;
˗ get_scroll_speed_list – метод получения схемы скорости скролла в
разные моменты отслеживаемого времени. Параметрами данного метода
являются схема смещений веб-страницы по оси Оу при скролле в
отслеживаемые моменты времени и список разностей временных отметок
соседних элементов трека скролла;
˗ get_key_press_stop – метод получения схемы остановок пользователя
при печати. Параметром данного метода является трек нажатия клавиш на
клавиатуре;
˗ get_cursor_path – метод получения ломаной движения курсора.
Параметрами данного метода являются трек движения курсора и величина
диагонали экрана устройства;
˗ get_start_stop – метод получения схемы стартов и остановок курсора.
Параметром данного метода является ломаная движения курсора;
˗ get_stop_count – метод получения количества остановок курсора.
Параметром данного метода является схема стартов и остановок курсора;
˗ get_start_stop_distance – метод получения схемы расстояний между
стартами и остановками курсора. Параметром данного метода является схема
стартов и остановок курсора;
˗ get_min_start_stop_distance
–
метод
получения
минимального
расстояния между стартом и остановкой курсора. Параметрами данного
метода являются схема расстояний между стартами и остановками курсора, а
также диагональ экрана устройства пользователя;
˗ get_max_start_stop_distance
–
метод
получения
максимального
расстояния между стартом и остановкой курсора. Параметрами данного
метода являются схема расстояний между стартами и остановками курсора, а
также диагональ экрана устройства пользователя;
56
˗ get_avg_start_stop_distance – метод получения среднего расстояния
между стартом и остановкой курсора. Параметрами данного метода являются
схема расстояний между стартами и остановками курсора, а также диагональ
экрана устройства пользователя;
˗ get_min_cursor_speed – метод получения минимальной скорости
курсора. Параметрами данного метода являются схема расстояний между
стартами и остановками курсора, а также диагональ экрана устройства
пользователя;
˗ get_max_cursor_speed – метод получения максимальной скорости
курсора. Параметрами данного метода являются схема расстояний между
стартами и остановками курсора, а также диагональ экрана устройства
пользователя;
˗ get_avg_cursor_speed – метод получения средней скорости курсора.
Параметрами данного метода являются схема расстояний между стартами и
остановками курсора, а также диагональ экрана устройства пользователя;
˗ get_max_positive_acceleration – метод получения максимального
положительного ускорения курсора. Параметром данного метода является
схема ускорений курсора;
˗ get_min_positive_acceleration – метод получения минимального
положительного ускорения курсора. Параметром данного метода является
схема ускорений курсора;
˗ get_avg_positive_acceleration
–
метод
получения
среднего
положительного ускорения курсора. Параметром данного метода является
схема ускорений курсора;
˗ get_avg_negative_acceleration
–
метод
получения
среднего
отрицательного ускорения курсора. Параметром данного метода является
схема ускорений курсора;
˗ get_max_scroll_speed – метод получения максимальной скорости
скролла. Параметром данного метода является схема скорости скролла в
разные моменты отслеживаемого времени;
57
˗ get_max_scroll_speed – метод получения максимальной скорости
скролла. Параметром данного метода является схема скорости скролла в
разные моменты отслеживаемого времени;
˗ get_min_scroll_speed – метод получения минимальной скорости
скролла. Параметром данного метода является схема скорости скролла в
разные моменты отслеживаемого времени;
˗ get_avg_scroll_speed – метод получения средней скорости скролла.
Параметром данного метода является схема скорости скролла в разные
моменты отслеживаемого времени;
˗ get_scroll_count
–
метод
получения
количества
скроллов.
Параметром данного метода является трек скролла;
˗ get_preferred_cursor_position – метод получения преимущественного
положения курсора. Параметрами данного метода являются трек движения
курсора и величина центра экрана устройства пользователя;
˗ get_avg_key_press_speed – метод получения средней скорости
печати. Параметром данного метода является схема остановок пользователя
при печати;
˗ get_mouse_click_count
–
метод
получения
количества
кликов
манипулятора. Параметром данного метода является трек кликов мыши;
˗ get_max_time_mouse_click
–
метод
получения
максимального
времени между кликами манипулятора. Параметром данного метода является
трек кликов мыши;
˗ get_fact_of_selection – метод получения факта выделения текста.
Параметром данного метода является трек выделения текста курсором;
˗ get_count_backspace_press – метод получения количества нажатий на
клавишу «Backspace». Параметром данного метода является трек нажатия
клавиш на клавиатуре;
˗ get_count_selection – метод получения отношения количества
выделений текста к общему объему текста на странице. Параметром данного
метода является трек нажатия клавиш на клавиатуре;
58
˗ get_count_selection_symbols
–
метод
получения
отношения
количества выделенных символов к общему объему текста на странице.
Параметром данного метода является трек нажатия клавиш на клавиатуре;
˗ get_length_answer_in_textarea – метод получения длины ввода в
многострочном поле ввода. Параметром данного метода является трек
нажатия клавиш на клавиатуре;
˗ get_length_answer_in_singleline – метод получения длины ввода в
однострочном поле ввода. Параметром данного метода является трек
нажатия клавиш на клавиатуре;
˗ get_user_class – метод получения метки класса пользователя.
Параметром данного метода является показатель класса пользователя;
˗ get_gender – метод получения метки пола пользователя. Параметром
данного метода является пол пользователя;
˗ get_device – метод получения метки типа устройства пользователя.
Параметром данного метода является тип устройства.
3.1.1.3 Модуль анализа данных
Данный модуль необходим для анализа и подготовки к обучению
нейронной сети выборки поведенческих параметров пользователя.
В качестве основных логических частей были выделены:
˗ чтение
параметров
данных
выборки
пользователей
из
находится
файла.
в
Выборка
файле,
поведенческих
созданном
модулем
Downloader;
˗ выделение категориальных и количественных признаков в выборке
поведенческих параметров пользователей;
˗ заполнение пропущенных значений количественных параметров
выборки. Так как сессии пользователя, а соответственно и набор параметров
могут быть неполными, пропуски должны быть заполнены;
˗ заполнение пропущенных значений категориальных параметров
выборки;
59
˗ векторизация бинарных категориальных признаков. Преобразование
бинарных категориальных признаков к количественным;
˗ векторизация небинарных категориальных признаков;
˗ нормализация
количественных
признаков.
Производится
масштабирование данных для корректной работы модели нейронной сети;
˗ соединение обработанных данных в одну таблицу;
˗ сохранение полученной выборки в файл;
˗ сохранения файла с основными данными, полученными в ходе
анализа выборки и необходимыми для заполнения пропусков в наборе
параметров режима определения психотипа пользователя.
3.1.1.4 Модуль нейронной сети
Работа данного модуля заключается в построении и сохранении модели
нейронной сети.
Среди основных логических частей были выделены:
˗ чтение
подготовленной
выборки
поведенческих
параметров
пользователей из файла, созданного модулем Data_analyze;
˗ подготовка к обучению тренировочной и тестовой выборок;
˗ построение модели нейронной сети;
˗ обучение нейронной сети. На данном этапе построенная модель
нейронной сети работает с обучающей выборкой;
˗ тестирование нейронной сети. Обученная модель нейронной сети
используется для классификации наблюдений из тестовой выборки;
˗ сохранение модели нейронной сети в файл. Для использования
функционала классификации вне модуля нейронной сети модель необходимо
сохранить в файл.
60
3.1.1.5 Модуль с конфигурацией проекта
Данный модуль не представлен сложными пользовательскими типами
данных и методами обработки информации. Config содержит различные
поля, такие как:
˗ пути к файлам;
˗ сетевые адреса;
˗ различные целочисленные параметры.
Модуль с конфигурацией проекта включается в другие части
подсистемы анализа данных, которым информация из модуля Config
необходима.
Вынесение полей в модуль с конфигурацией проекта дает возможность
пользователю
изменять
эти
поля,
не внося
изменений
в
модули,
использующие данную информацию.
3.1.2 Режим определения психотипа пользователя
В подсистеме анализа дынных в режиме определения психотипа
пользователя выделены следующие модули:
˗ Server_classificator – главный модуль;
˗ Classification_utils – модуль подготовки данных и классификации;
˗ Handler
–
модуль
получения
поведенческих
параметров
пользователя;
˗ Config – модуль с конфигурацией проекта.
Диаграмма классов данного режима представлена на рисунке 11.
61
Рисунок 11 – Диаграмма классов режима определения психотипа
пользователя
62
3.1.2.1 Главный модуль
Задачами данного модуля являются:
˗ опрос очереди на предмет наличия сессий пользователей и
извлечение данных из очереди;
˗ использование
функционала
модуля
Classification_utils
для
подготовки и классификации сессии;
˗ отправка результата классификации стороннему ресурсу.
Основой данного модуля является класс ServerClassificator, среди полей
которого были выделены:
˗ conn – подключение к серверу очереди сессий пользователей;
˗ classification_utils – объект класса ClassificationUtils.
В данном классе выделены следующие методы:
˗ init – инициализация экземпляра класса. Работа данного метода
необходима для инициализации полей класса, необходимых для дальнейшей
работы;
˗ delete – удаление экземпляра класса. Метод необходим для
уведомления о завершении работы экземпляра класса и проведения
завершающих операций;
˗ redis_connect_tcp – подключение к серверу очереди. Необходима
связь с сервером, предоставляющим функционал для получения данных;
˗ fetch – выполнение запроса. Параметрами данного метода являются
интерфейс для совершения запроса к стороннему ресурсу, адрес стороннего
ресурса, результат классификации. Данный метод выполняет запрос на
отправку результата классификации стороннему серверу;
˗ handle – обработка сессии. Параметром данного метода является
сессия пользователя. Используя функционал модуля Classification_utils,
данный
метод
получает
поведенческие
параметры
пользователя,
подготавливает набор параметров к классификации, получает результат
классификации и выполняет запрос на отправку результата стороннему
ресурсу;
63
˗ listen_to_redis
–
просмотр
очереди.
Работа
данного
метода
заключается в постоянной проверке состояния очереди на наличие сессий.
Главный
метод
ServerClassificator,
данного
задает
модуля,
основную
используя
объект
последовательность
класса
действий
и
координирует работу методов класса.
3.1.2.2 Модуль подготовки данных и классификации
Работа данного модуля заключается в вычислении поведенческих
параметров пользователя на основе полученной сессии, подготовка сессии к
классификации и классификация набора параметров.
Модуль представлен классом ClassificationUtils, среди полей которого
были выделены:
˗ participant_id – идентификатор пользователя;
˗ model – модель нейронной сети;
˗ help_json – файл с основными данными, полученными в ходе анализа
выборки и необходимыми для заполнения пропусков в наборе параметров
режима определения психотипа пользователя;
˗ numeric_columns
–
список
количественных
поведенческих
признаков;
˗ binary_columns – список бинарных категориальных поведенческих
признаков;
˗ dummy_encoding_cols – список dummy-закодированных небинарных
поведенческих признаков.
Данный класс содержит следующие методы:
˗ init – инициализация экземпляра класса. Работа данного метода
необходима для инициализации полей, необходимых для дальнейшей
работы. Можно отметить, что частью работы данного метода является
загрузка информации из файла, созданного модулем анализа данных и
64
содержащего основные данные, полученные в ходе подготовки выборки к
обучению нейронной сети;
˗ delete – удаление экземпляра класса. Метод необходим для
уведомления о завершении работы экземпляра класса и проведения
завершающих операций;
˗ normalize – нормализация количественного признака. Параметрами
данного метода являются значение параметра, имя параметра. Данный метод
необходим для масштабирования параметра в соответствии с алгоритмом,
примененным
в
процессе
подготовки
выборки
к
обучению.
Масштабирование производится на основе данных из help_json;
˗ prepare_num_cols – подготовка количественных признаков. Параметр
– список поведенческих признаков. Происходит заполнение пропусков на
основе информации из help_json, а также нормализация всех количественных
параметров;
˗ prepare_binary_cols
–
подготовка
бинарных
категориальных
признаков. Параметр – список поведенческих признаков. Работа данного
метода заключается в заполнении пропусков и векторизации параметров на
основе информации из help_json;
˗ prepare_nonbinary_cols – подготовка небинарных категориальных
признаков. Параметр – список поведенческих признаков. Производится
dummy-кодирование признаков на основе информации из help_json;
˗ add_to_params – пополнение конечного списка поведенческих
параметров. Параметрами данного метода являются конечный список
поведенческих параметров, список параметров для заполнения и список
подготовленных поведенческих признаков
˗ get_parameters – получение параметров. Параметр метода – сессия
пользователя. Метод, используя функционал модуля Handler, вычисляет
поведенческие параметры пользователя;
˗ prepare_parameters – подготовка параметров. Параметр метода –
список поведенческих признаков. Данный метод необходим для подготовки
65
всех поведенческих параметров пользователя. Используется функционал
всех методов подготовки количественных и категориальных признаков;
˗ classificate – классификация. Параметр метода - конечный список
поведенческих признаков. Используя модель нейронной сети, загруженной
из файла, метод классифицирует подготовленный набор параметров.
3.2 Основные алгоритмы
Если говорить о функционировании подсистемы анализа данных в
режиме обучения нейронной сети, то можно выделить следующие основные
алгоритмы, требующие детального описания:
˗ запрос у подсистемы сбора данных и сохранение общей информации
пользователей,
результатов
тестирования,
а
также
наборов
сессий
пользователей модулем Downloader;
˗ получение и
сохранение выборки поведенческих параметров
пользователей модулем Downloader;
˗ построение ломаной движения курсора модулем Handler;
˗ построение схемы стартов и остановок курсора модулем Handler.
Блок-схема первого алгоритма изображена на рисунке 12. Запросы на
получение информации от подсистемы сбора данных продолжаются пока не
пройден конец списка идентификаторов пользователей. В случае достижения
конца списка идентификаторов общий список сессий сохраняется в файл и
алгоритм завершает работу. При получении очередного идентификатора
пользователя формируется URL-адрес для запроса общей информации
пользователя и результатов тестирования. Ответ, полученный от подсистемы
сбора данных, форматируется и проверяется на наличие пустых полей.
В случае отсутствия пустых полей в ответе формируется URL-адрес
для запроса набора сессий пользователя. Полученный ответ подсистемы
сбора данных также форматируется. Следующим этапом является проход по
списку полученных сессий. На каждой итерации данного цикла проверяется
наличие метки класса пользователя у сессии. В случае присутствия метки
66
сессия пользователя объединяется с общей информацией пользователя и
результатами тестирования. Также происходит пополнение общего списка
сессий. В противном случае происходит переход на новую итерацию цикла
набора сессий. В результате достижения конца набора сессий пользователя
происходит повторная итерация всего алгоритма.
Рисунок 12 – Запрос информации у подсистемы сбора данных
Блок-схема алгоритма получения и сохранения выборки поведенческих
параметров пользователей представлена на рисунке 13. Работа алгоритма
67
продолжается пока не будет достигнут конец общего списка сессий. В случае
достижения конца общего списка сессий происходит сохранение общей
выборки поведенческих параметров в файл и алгоритм завершает работу.
При получении очередной сессии инициализируется объект класса
Handler. Происходит вычисление поведенческих параметров пользователя с
помощью методов данного класса. Следующим этапом работы алгоритма
является удаление объекта класса Handler и пополнение общей выборки
поведенческих параметров пользователей.
Рисунок 13 – Получение и сохранение выборки поведенческих параметров
пользователей
68
Блок-схема
алгоритма
построения
ломаной
движения
курсора
представлена на рисунке 14. Основной цикл алгоритма начинается в том
случае, если трек движения курсора не пуст. В противном случае происходит
возврат пустой ломаной движения курсора и завершение работы алгоритма.
Цикл алгоритма подразумевает увеличение индекса от единицы до
величины длины трека движения курсора. На очередной итерации цикла
происходит сохранение предыдущего и текущего элемента трека движения
курсора.
Далее происходит вычисление длины сегмента ломаной движения
курсора и времени прохождения этого сегмента. Следующим шагом
алгоритма является проверка вычисленного значения времени на равенство
нулю. В случае равенства происходит переход к новой итерации цикла. В
противном случае формируется звено сегмента ломаной движения курсора,
состоящее из следующих полей:
˗ длины сегмента ломаной движения курсора;
˗ времени прохождения сегмента ломаной движения курсора.
После происходит формирование сегмента ломаной, состоящей из:
˗ старта сегмента, являющегося элементом трека движения курсора;
˗ конца сегмента, также являющегося элементом трека движения
курсора;
˗ вышеописанного звена сегмента ломаной движения курсора.
В случае успешного формирования сегмента ломаной движения
курсора, полученный сегмент добавляется к ломаной движения курсора и
происходит переход на новую итерацию цикла. В случае превышения
значением индекса длины трека движения курсора происходит возврат
построенной ломаной движения курсора и алгоритм завершает работу.
69
Рисунок 14 – Построение ломаной движения курсора
70
Блок-схема алгоритма построения схемы стартов и остановок курсора
представлена на рисунке 15. Данный алгоритм начинает свою работу с
проверки на пустоту ломаной движения курсора. В случае пустоты ломаной
происходит возврат пустой схемы стартов и остановок курсора и алгоритм
завершает работу. В противном случае текущим отрезком устанавливается
нулевой элемент ломаной.
Следующим шагом алгоритма последняя позиция курсора помечается
как остановка, а первая позиция курсора как старт. Далее начинается
внешний цикл алгоритма, продолжающий свою работу до момента
достижения конца ломаной движения курсора. В случае завершения работы
цикла происходит возврат схемы стартов и остановок курсора и алгоритм
завершает работу. На очередной итерации внешнего цикла обнуляется
таймер движения и расстояние, пройденное от начала движения.
Далее запускается внутренний цикл алгоритма, который продолжает
свою работу в случае, если величина таймера движения не превосходит 500
мс. На очередной итерации внутреннего цикла производится увеличение
значения таймера на величину времени прохождения текущего отрезка
ломаной, увеличение значения пройденного расстояния на величину длины
текущего отрезка ломаной. Также текущим отрезком устанавливается
следующий элемент ломаной движения курсора и происходит переход на
новую итерацию внутреннего цикла. В случае завершения работы
внутреннего
цикла
алгоритма
производится
сравнение
расстояния,
пройденного от начала движения и величины 5 пикселей. В случае если
расстояние не превосходит данную величину осуществляется пометка первой
вершины текущего отрезка как старта, второй вершины предыдущего отрезка
ломаной как остановки, а также переход на новую итерацию внешнего цикла.
В противном случае также происходит переход на следующую итерацию
внешнего цикла. По завершению работы внешнего цикла происходит возврат
схемы стартов и остановок курсора и алгоритм завершает работу.
71
Рисунок 15 – Построение схемы стартов и остановок курсора
72
Если говорить о функционировании подсистемы анализа данных в
режиме
определения
психотипа
пользователя,
то
можно
выделить
следующие основные алгоритмы:
˗ проверка очереди сессий на обновления;
˗ классификация сессии.
Блок-схема алгоритма проверки очереди на обновления представлена
на рисунке 16.
Рисунок 16 – Проверка очереди на обновления
73
Алгоритм в процессе своей работы запускает бесконечный цикл.
Каждая итерация этого цикла включает попытку запроса последней сессии из
очереди. В случае положительного ответа полученная сессия форматируется,
а
также
происходит
планирование
события
классификации
сессии.
Завершение работы алгоритма происходит только в случае вмешательства
пользователя.
Блок-схема алгоритма классификации сессии приведена на рисунке 17.
Рисунок 17 – Классификация сессии
74
В первую очередь полученная сессия используется для вычисления
набора поведенческих параметров пользователя. В случае пустого набора
поведенческих параметров планируется событие отправки сообщения об
ошибке стороннему ресурсу и алгоритм завершает работу. В противном
случае
происходит
подготовка
набора
поведенческих
параметров
к
классификации и получение результатов классификации. Если результат
классификации не получен, планируется событие отправки сообщения об
ошибке стороннему ресурсу и алгоритм завершает работу. В случае
получения результата классификации планируется событие отправки
стороннему ресурсу данных, содержащих следующие поля:
˗ идентификатор пользователя;
˗ метка класса пользователя.
3.3 Проектирование структур данных
В подсистеме анализа данных можно выделить основные структуры
данных:
˗ сессия пользователя;
˗ общая информация о пользователе и результатах тестирования;
˗ результаты классификации.
Все вышеописанные структуры данных подвергаются постоянной
передаче между модулями и подсистемами. Учитывая это, для представления
физической структуры основных типов данных был выбран форма JSON.
Данный формат легок для понимания, и существует огромное множество
инструментов для работы с этим форматом представления данных.
Для агрегации больших скоплений основных структур данных
применялись массивы формата JSON.
Ниже приведены примеры физического представления основных
структур данных:
˗ сессия пользователя:
{
75
"z": 1.9,
"id": 45752,
"width": 1301,
"height": 618,
"participant_id": 1000,
"mouse_move": [{"x": 524, "y": 390,"time": 59}, {...}],
"mouse_click": [{"x": 634, "y": 345, "time": 6589}, {...}],
"mouse_selection": [{"text": "закрытый", "time": 11561, "allTextLength": 32208}, {...}],
"mouse_scroll": [{"time": 572, "scrollY": -53}, {...}],
"key_press": [{"code": null, "time": 13121, "focus":
"on","elemName":
"client-post[data][answer]", "elemType": "TEXTAREA"},{...}]
}
˗ общая информация о пользователе и результатах тестирования:
{
"id": 1000,
"z": 0,
"gender": 2,
"age": 3,
"email": "[email protected]",
"meta": {
"aTimer": {
"aTask": {
"sEnd": "2018-01-21 23:03:24",
"sStart": "2018-01-21 22:45:59"
},
"aTest": {
"sEnd": "2018-01-21 22:45:59",
"sStart": "2018-01-21 22:40:25"
}
76
},
"aResult": {},
"deleted_at": null,
"created_at": "2018-01-21 22:40:27",
"updated_at": "2018-01-21 23:03:24",
"device_os": "Linux",
"device_type": "2"
}
˗ результаты классификации:
{
participant_id: 996,
class: +
}
Если говорить о многочисленных структурах данных, таких как
ломаная движения курсора или схема стартов и остановок курсора,
строящихся и использующихся в процессе вычисления поведенческих
параметров пользователей, то спроецировав данные модели на структуры
языка программирования Python, можно сделать вывод о том, что такие
модели данных удобно представлять и обрабатывать в качестве списка
словарей.
Ниже приведены примеры физического представления ломаной
движения курсора и схемы стартов и остановок курсора:
˗ ломаная движения курсора:
cursor_path = [
{
'sol': {'time': 200, 'x': 1195, 'y': 564},
'eol': {'time': 202, 'x': 1195, 'y': 565},
'line':{'length': 1, ‘time’: 2}
},
77
{
'sol': {'time': 204, 'x': 1197, 'y': 534},
'eol': {'time': 206, 'x': 1201, 'y': 578},
'line':{'length': 1, ‘time’: 2}
},
]
˗ схема стартов и остановок курсора:
cursor_path = [
{
'sol': {'time': 200, 'x': 1195, 'y': 564, 'is_start': True},
'eol': {'time': 202, 'x': 1195, 'y': 565, 'is_stop': False},
'line':{'length': 1, ‘time’: 2}
},
{
'sol': {'time': 204, 'x': 1197, 'y': 534, 'is_start': False},
'eol': {'time': 206, 'x': 1201, 'y': 578, 'is_stop': True},
'line':{'length': 1, ‘time’: 2}
},
]
78
4 РЕАЛИЗАЦИЯ ПОДСИСТЕМЫ АНАЛИЗА ДАННЫХ
ПОЛЬЗОВАТЕЛЯ ВЕБ-САЙТА
Для реализации подсистемы анализа данных был выбран язык
программирования Python версии 3. Выбор обусловлен:
˗ простотой использования языка;
˗ возможностью писать короткие скрипты под отдельные задачи;
˗ наличием богатого инструментария, связанного с работой в сети, с
базами данных, с обработкой файлов различных типов, с анализом больших
данных, с проектированием нейронных сетей и других алгоритмов
машинного обучения.
4.1 Режим обучения нейронной сети
Диаграмма компонентов подсистемы, функционирующей в данном
режиме, представлена на рисунке 18.
Рисунок 18 – Диаграмма компонентов режима обучения нейронной сети
79
Если говорить о режиме обучения нейронной сети, то стоит
проанализировать реализацию следующих механизмов:
˗ механизм запроса информации у подсистемы сбора данных,
получения выборки поведенческих параметров пользователей, сохранения
информации (модуль Downloader.py);
˗ механизм анализа и подготовки выборки поведенческих параметров
пользователей (модуль Data_analyze.py);
˗ механизм построения модели нейронной сети (модуль Model.py).
Запрос информации у подсистемы сбора данных и получение выборки
поведенческих параметров пользователей производятся многопоточно. С
помощью библиотеки Multiprocessing создается набор рабочих потоков в
каждом из которых выполняется 2 HTTP-запроса:
˗ на получение общей информации пользователя и результатов
тестирования;
˗ на получение набора сессий пользователя.
Полученные данные объединяются в словарь и добавляются в
результирующий
список
participants_sessions.
А
также
в
процессе
выполнения запросов каждая сессия добавляется в список all_sessions для
последующего сохранения списка в файл формата JSON.
Далее набор рабочих потоков, обрабатывая список participants_sessions,
собирает список наборов поведенческих параметров пользователей, который
сохраняется в файле Parameters.csv. Программный код вышеописанного
механизма представлен ниже:
try:
participants_ids = get_participants_ids()
pool = ThreadPool(config.RQ_THREADS)
downloader = Downloader()
participants_sessions = pool.map(downloader.get_participant_with_sessions,
participants_ids[0:10])
json.dump(downloader.all_sessions, downloader.json_data)
80
downloader.json_data.close()
participants_parameters = pool.map(downloader.handle_participant,
participants_sessions)
res = list(chain.from_iterable(participants_parameters))
pool.close()
pool.join()
with open(config.RESULT_PARAMETERS_CSV, "w", newline="") as file:
columns = [key for key in res[0].keys()]
writer = csv.DictWriter(file, fieldnames=columns)
writer.writeheader()
writer.writerows(res)
except Exception as ex:
log.error('Error in __main__: %s' % str(ex))
Анализ
и
подготовка
выборки
поведенческих
параметров
пользователей проводилась с использованием такого инструмента, как
IPython notebook, представляющего из себя графическую веб-оболочку для
исполнения команд «на лету» и мгновенным отображением результата
работы ячейки кода. Пример работы с данным инструментом приведен на
рисунке 19.
Для непосредственного анализа и подготовки выборки поведенческих
параметров пользователей использовалась библиотека Pandas, которая
позволяет преобразовать выборку в тип DataFrame. В данном представлении
информацию легко анализировать и корректировать. Ниже приведен пример
кода, реализующего выделение категориальных, количественных, а также
бинарных и небинарных категориальных признаков:
categorical_columns = [c for c in data.columns if data[c].dtype.name == 'object'
and c != '34']
numerical_columns = [c for c in data.columns if data[c].dtype.name != 'object'
and c != '34']
81
data_describe = data.describe(include=[object])
binary_columns = [c for c in categorical_columns if data_describe[c]['unique']
== 2]
nonbinary_columns = [c for c in categorical_columns if data_describe[c]['unique']
> 2]
Рисунок 19 – Пример работы в IPython notebook
Ниже приведен пример векторизации бинарных категориальных
признаков:
for c in binary_columns:
top = data_describe[c]['top']
top_items = data[c] == top
data.loc[top_items, c] = 0
data.loc[np.logical_not(top_items), c] = 1
82
Показанный пример кода выполняет следующие действия:
˗ итерирование по бинарным категориальным колонкам таблицы;
˗ нахождение преобладающего значения колонки;
˗ получение индексов по строкам преобладающих элементов столбца;
˗ замещение преобладающих элементов столбца значением 0;
˗ замещение элементов, отличных от преобладающих значением 1.
Модель нейронной сети построена с помощью библиотеки Keras,
которая является отличным инструментом в сборке и тонкой настройке
различных моделей сетей. Реализация архитектуры нейронной сети
приведена ниже:
HIDDEN_LAYER_SIZE = 200
CLASS_COUNT = 2
model = Sequential()
model.add(Dense(HIDDEN_LAYER_SIZE, input_shape=(X_train.shape[1],)))
model.add(Dropout(0.2))
model.add(Dense(HIDDEN_LAYER_SIZE, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(HIDDEN_LAYER_SIZE, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(CLASS_COUNT, activation='softmax'))
Архитектура сети представляет собой многослойный перцептрон с
двумя полносвязными скрытыми слоями размерностью 200. Между слоями
сети применена настройка Dropout, позволяющая за каждую итерацию
обучения исключать нейроны из слоя на время этой итерации с определенной
вероятностью.
83
4.2 Режим определения психотипа пользователя
Диаграмма компонентов подсистемы, функционирующей в данном
режиме, представлена на рисунке 20.
Рисунок 20 – Диаграмма компонентов режима определения психотипа
пользователя
Ниже приведена реализация механизма опроса очереди сессий на
наличие обновлений:
async def listen_redis(self):
try:
while True:
session = await self.conn.execute('brpop',
config.REDIS_SESSIONS_FOLDER, 0)
if session != None and len(session) == 2:
session_to_classificate = json.loads(session[1])
asyncio.ensure_future(self.handle(session_to_classificate))
else:
break
84
except Exception as ex:
log.error('Error in listen_redis: %s' % str(ex))
Данный механизм реализован с использованием библиотеки Asyncio,
которая предоставляет инфраструктуру для написания однопоточного
конкурентного кода при помощи сопрограмм. Сопрограмма - специальная
функция, которая возвращает управление объекту, вызвавшему ее, сохраняя
при этом свое состояние. Функционал Asyncio основан на понятии цикл
событий. Главная функция цикла событий - ожидание какого-либо события и
определенная реакция на него.
Цикл опроса очереди сессий представлен в качестве сопрограммы,
которая сразу выполняется в цикле событий. При попытке асинхронно
получить сессию из очереди, сопрограмма возвращает выполнение в
основной цикл событий, при этом сохраняя свое состояние. При получении
сессии выполнение продолжается с места возврата. Пройдя валидацию,
сессия передается обработчику, однако обработка выполняется не сразу. При
каждом получении сессии из очереди ее обработка преобразуется во Futureобъект, который планируется в расписании заданий. Данным расписанием
управляет основной цикл событий.
4.3 Статистика функционирования подсистемы анализа данных в
режиме обучения нейронной сети
В ходе оценки успешности работы алгоритма классификации было
проведено сравнение нескольких алгоритмов машинного обучения:
˗ метод ближайших соседей;
˗ случайный лес;
˗ метод опорных векторов;
˗ нейронная сеть.
Для сравнения данные были разделены следующим образом:
˗ 80% выборки – обучение модели;
˗ 20% выборки – тестирование обученной модели.
85
Результаты сравнения алгоритмов представлены в таблице 3:
Таблица 3 – Результаты сравнения работы алгоритмов машинного обучения
Метод
Величина ошибки на тестовой
выборке, %
Метод ближайших соседей
15,0
Случайный лес
1,1
Метод опорных векторов
13,4
Нейронная сеть
1,4
Как видно из таблицы алгоритм случайного леса показал лучший
результат, опередив даже нейронную сеть. Однако это можно отнести как к
недостаточной сложности или определенным свойствам архитектуры
нейронной сети, так и к особенностям конкретной выборки данных.
Применение нейронной сети имеет больший приоритет в плане
дальнейшего исследования архитектуры модели. В будущем возможно также
соединение нескольких алгоритмов машинного обучения для достижения
большей точности.
86
ЗАКЛЮЧЕНИЕ
В ходе выполнения работы были решены все поставленные задачи:
1) Выполнен анализ предметной области и выявлены основные
требования к системе, проанализированы наблюдаемые параметры;
2) Проведен обзор основных методов анализа полученных данных;
3) Проанализированы основные преимущества и недостатки системаналогов относительно разрабатываемой системы;
4) На
основании
выявленных
требований
были
описаны
спецификации, определена архитектура подсистемы;
5) Показана структура ПО, разобраны основные алгоритмы, показана
структура основных структур данных;
6) Реализованы все механизмы подсистемы анализа данных;
7) Приведена статистика успешности работы подсистемы в режиме
обучения нейронной сети и сравнение результатов работы других алгоритмов
классификации;
Таким образом, можно сделать вывод о том, что поставленная цель
была достигнута
87
СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ
1. Кречмер, Э. Строение тела и характер [Текст] : [пер. с нем.
Тартаковский Г. Я] / Э. Кречмер. – М.: Академический Проект, 2015 (ориг.
1921). – 328 с.
Леоненков, А.В. Самоучитель UML 2 [Текст] / А.В. Леоненков. – СПб.:
БХВ-Петербург, 2007. – 576 с.
2. Холодная, М.А. Когнитивные стили. О природе индивидуального
ума [Текст] / М.А. Холодная. – 2-е изд. – СПб.: Питер, 2004 – 384 с.
3. Хромов, А.Б. Пятифакторный опросник личности: Учебнометодическое пособие [Текст] / А.Б. Хромов. – Курган: Изд-во Курганского
гос. университета, 2000. – 23 с.
4. Доусон, М. Программируем на Python [Текст] / М. Доусон– СПб.:
Питер, 2014. – 416 с.
5. Лутц, М. Изучаем Python, 4-е издание [Текст] : [пер. с англ.] / М.
Лутц – СПб.: Символ-Плюс, 2011. – 1280 с.
6. Лутц, М. Программирование на Python, том I, 4-е издание [Текст] :
[пер. с англ.] / М. Лутц – СПб.: Символ-Плюс, 2011. – 992 с.
7. Лутц, М. Программирование на Python, том II, 4-е издание [Текст]
: [пер. с англ.] / М. Лутц – СПб.: Символ-Плюс, 2011. – 992 с.
8. Прохоренок, Н.А. Python 3 и PyQt. Разработка приложений [Текст]
/ Н.А Прохоренок – СПб.: БХВ-Петербург, 2012. – 704 с.
10. Прохоренок, Н.А. Самое необходимое [Текст] / Н.А. Прохоренок
— СПб.: БХВ-Петербург, 2011. — 416 с.
11.
Хахаев,
И.А.
Практикум
по
алгоритмизации
и
программированию на Python [Текст] / Хахаев И.А. – М.: Альт Линукс,
2010. — 126 с. (Библиотека ALT Linux).
12. Бунаков, В. Е. Нейронная физика. Учебное пособие: моногр [Текст]
/ В.Е. Бунаков, Л.В. Краснов. – М.: Издательство Санкт-Петербургского
университета, 2015. – 200 c
88
13. Нейронные сети. Statistica Neural Networks. Методология и
технологии современного анализа данных [Текст] – М.: Горячая линия –
Телеком, 2008. – 392 c.
14. Галушкин, А.И. Нейронные сети: основы теории [Текст] / А.И.
Галушкин. – М.: ГЛТ, 2012. – 496 c.
15. Барский, А.Б. Логические нейронные сети: Учебное пособие [Текст]
/ А.Б. Барский. – М.: Бином, 2013. – 352 c.
89
ПРИЛОЖЕНИЕ А
(обязательное)
ПРОГРАММНЫЙ КОД
Модуль Downloader.py
from Handler import Handler
import config
import requests as rq
import json
import csv
import openpyxl
import logging
import os.path
from itertools import chain
from multiprocessing.dummy import Pool as ThreadPool
log = logging.getLogger("Downloader")
log.setLevel(logging.INFO)
fh = logging.FileHandler(config.LOG_FILE_NAME)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
fh.setFormatter(formatter)
log.addHandler(fh)
class Downloader:
def __init__(self):
try:
log.info('Downloader started!')
self.json_data = open(config.RAW_DATA_CSV, "w")
self.all_sessions = []
self.headers = \
{
"Accept": "application/json",
"Authorization": "Bearer
eUxQ47veZYNr3EXj5DAjBqtJVPkFonrCoY87T2Z42SQEMfZu2oNhEUgACPgC",
"Content-Type": "application/json",
"Origin": "http://test.psytarget.com"
}
except Exception as ex:
log.error('Exeption in __init__: %s' % str(ex))
def __delete__(self, instance):
log.info('Downloader stopped!')
90
def get_participant_with_sessions(self, id):
try:
participant_url = config.PARTICIPANTS_API_URL % (str(id))
text = rq.get(participant_url, headers=self.headers).text
participant = json.loads(text)
print('###======= PARTICIPANT %s =======###' % (str(participant["id"])))
if 'meta' in participant and participant['meta'] is not None:
participant_sessions_url = config.SESSIONS_API_URL % (str(id))
response_text = rq.get(participant_sessions_url, headers=self.headers).text
participant_sessions = json.loads(response_text)
for session in participant_sessions:
if session['z'] != None:
session['gender'] = participant['gender']
session['age'] = participant['age']
session['device_type'] = participant['device_type']
session['device_os'] = participant['device_os']
session['email'] = participant['email']
session['sStart'] = participant["meta"]["aTimer"]["aTest"]["sStart"]
session['sEnd'] = participant["meta"]["aTimer"]["aTest"]["sEnd"]
self.all_sessions.append(session)
return \
{
'sessions': participant_sessions
}
except Exception as ex:
log.error('Exception in get_participant_with_sessions: %s\nID: %s' % (str(ex), str(id)))
def handle_participant(self, participant_data):
try:
res = []
for session in participant_data['sessions']:
session_handler = Handler(session)
parameters = session_handler.get_parameters()
del session_handler
res.append(parameters)
return res
except Exception as ex:
log.error('Error in handle_participant: %s' % str(ex))
def get_participants_ids():
try:
res = openpyxl.load_workbook('res.xlsx')
91
res_sheet = res.active
participants_ids = []
for i in range(2, res_sheet.max_row + 1):
participants_ids.append(res_sheet.cell(row=i, column=1).value)
return participants_ids
except Exception as ex:
log.error('Error in get_participants_ids: %s' % str(ex))
if __name__ == "__main__":
try:
participants_ids = get_participants_ids()
pool = ThreadPool(config.RQ_THREADS)
downloader = Downloader()
participants_sessions = pool.map(downloader.get_participant_with_sessions,
participants_ids[0:10])
json.dump(downloader.all_sessions, downloader.json_data)
downloader.json_data.close()
participants_parameters = pool.map(downloader.handle_participant, participants_sessions)
res = list(chain.from_iterable(participants_parameters))
pool.close()
pool.join()
with open(config.RESULT_PARAMETERS_CSV, "w", newline="") as file:
columns = [key for key in res[0].keys()]
writer = csv.DictWriter(file, fieldnames=columns)
writer.writeheader()
writer.writerows(res)
except Exception as ex:
log.error('Error in __main__: %s' % str(ex))
Модуль Handler.py
from math import sqrt, ceil, fabs
from copy import copy
from operator import itemgetter
import json
import logging
from datetime import datetime, date, time
import time
92
import random
from setuptools.command.test import test
from pprint import pprint
logging.basicConfig(filename="HandlerLog.log", level=logging.INFO, filemode="w")
log = logging.getLogger("log")
class Handler:
def __init__(self, participant_session):
self.gender_index = participant_session["gender"]
self.age = participant_session["age"]
self.device_type = participant_session["device_type"]
self.device_os = participant_session["device_os"]
self.name_length = len(participant_session["email"].split('@')[0])
start_time_test = datetime.strptime(participant_session["sStart"], "%Y-%m-%d
%H:%M:%S")
end_time_test = datetime.strptime(participant_session["sEnd"], "%Y-%m-%d
%H:%M:%S")
self.test_time = time.mktime(end_time_test.timetuple()) time.mktime(start_time_test.timetuple())
self.__participant_id = str(participant_session['participant_id'])
self.__path_list = participant_session["mouse_move"]
self.__scroll_list = participant_session["mouse_scroll"]
self.__key_press_list = participant_session["key_press"]
self.__mouse_click_list = participant_session["mouse_click"]
self.__mouse_selection_list = participant_session["mouse_selection"]
self.__width = participant_session["width"]
self.__height = participant_session["height"]
self.__screen_diagonal = self.__get_screen_diagonal(self.__width, self.__height)
cursor_path = self.__get_cursor_path(self.__path_list, 0)
self.__start_stop = self.__get_start_stop(cursor_path)
self.__acceleration_list = self.__get_acceleration_list(self.__start_stop)
self.__width_middle = self.__get_width_middle(self.__width)
bias_list = [e["scrollY"] for e in self.__scroll_list][1:]
time_difference_list = self.__get_int_param_difference_list(self.__scroll_list, 'time')
self.__scroll_speed = self.__get_scroll_speed_list(bias_list, time_difference_list,
self.__screen_diagonal)
self.__start_stop_distance = self.__get_start_stop_distance(self.__start_stop)
self.__key_press_stop_list = self.__get_key_press_stop(self.__key_press_list)
self.__z = participant_session["z"]
if self.__z == None:
print('z:', self.__z, self.__participant_id)
def get_parameters(self):
try:
stop_count = self.__get_stop_count(self.__start_stop)
avg_key_press_speed = self.__get_avg_key_press_speed(self.__key_press_stop_list)
93
min_start_stop_distance = self.__get_min_start_stop_distance(self.__start_stop_distance,
self.__screen_diagonal)
max_start_stop_distance =
self.__get_max_start_stop_distance(self.__start_stop_distance, self.__screen_diagonal)
avg_start_stop_distance = self.__get_avg_start_stop_distance(self.__start_stop_distance,
self.__screen_diagonal)
min_cursor_speed = self.__get_min_cursor_speed(self.__start_stop_distance,
self.__screen_diagonal)
max_cursor_speed = self.__get_max_cursor_speed(self.__start_stop_distance,
self.__screen_diagonal)
avg_cursor_speed = self.__get_avg_cursor_speed(self.__start_stop_distance,
self.__screen_diagonal)
max_positive_acceleration =
self.__get_max_positive_acceleration(self.__acceleration_list)
min_positive_acceleration =
self.__get_min_positive_acceleration(self.__acceleration_list)
avg_positive_acceleration =
self.__get_avg_positive_acceleration(self.__acceleration_list)
avg_negative_acceleration =
self.__get_avg_negative_acceleration(self.__acceleration_list)
max_scroll_speed = self.__get_max_scroll_speed(self.__scroll_speed)
min_scroll_speed = self.__get_min_scroll_speed(self.__scroll_speed)
avg_scroll_speed = self.__get_avg_scroll_speed(self.__scroll_speed)
scroll_count = self.__get_scroll_count(self.__scroll_list)
preffered_cursor_position = self.__get_preffered_cursor_position(self.__path_list,
self.__width_middle)
mouse_click_count = self.__get_mouse_click_count(self.__mouse_click_list)
max_time_mouse_click = self.__get_max_time_mouse_click(self.__mouse_click_list)
fact_of_selection = self.__get_fact_of_selection(self.__mouse_selection_list)
count_backspace_press = self.__get_count_backspace_press(self.__key_press_list)
count_selection = self.__get_count_selection(self.__mouse_selection_list)
count_selection_symbols =
self.__get_count_selection_symbols(self.__mouse_selection_list)
length_answer_in_textarea =
self.__get_length_answer_in_textarea(self.__key_press_list)
length_answer_in_singleline =
self.__get_length_answer_in_singleline(self.__key_press_list)
return \
{
"1": self.__get_gender(self.gender_index),
"2": self.age,
"3": self.__get_device(int(self.device_type)),
"4": self.__width,
"5": self.__height,
"6": self.device_os,
"7": self.test_time,
"8": self.name_length,
"9": stop_count,
"10": min_start_stop_distance,
"11": max_start_stop_distance,
"12": avg_start_stop_distance,
94
"13": min_cursor_speed,
"14": max_cursor_speed,
"15": avg_cursor_speed,
"16": max_positive_acceleration,
"17": min_positive_acceleration,
"18": avg_positive_acceleration,
"19": avg_negative_acceleration,
"20": max_scroll_speed,
"21": min_scroll_speed,
"22": avg_scroll_speed,
"23": scroll_count,
"24": preffered_cursor_position,
"25": avg_key_press_speed,
"26": mouse_click_count,
"27": max_time_mouse_click,
"28": fact_of_selection,
"29": count_backspace_press,
"30": count_selection,
"31": count_selection_symbols,
"32": length_answer_in_textarea,
"33": length_answer_in_singleline,
"34": self.__get_user_class(self.__z)
}
except Exception as ex:
log.exception(str(datetime.now()) + " Error in get_parameters: " + str(ex))
# helping functions
def __get_width_middle(self, width):
try:
return ceil(width / 2)
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_width_middle: " + str(ex) + "\n\n")
def __get_screen_diagonal(self, width, height):
try:
return ceil(sqrt(width**2 + height**2))
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_screen_diagonal: " + str(ex) + "\n\n")
def __get_distance(self, x1, y1, x2, y2):
try:
return ceil(sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2))
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_distance: " + str(ex) + "\n\n")
def __get_acceleration(self, speed0, speed1, time1):
try:
return round((speed1 - speed0) / time1, 3)
95
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_acceleration: " + str(ex) + "\n\n")
def __get_acceleration_list(self, start_stop):
try:
if len(start_stop) != 0:
acceleration_list = []
for pos in range(1, len(start_stop)):
prev_segm = start_stop[pos - 1]
cur_segm = start_stop[pos]
if prev_segm['line']['time'] != 0 and cur_segm['line']['time'] != 0:
prev_speed = prev_segm['line']['length'] / prev_segm['line']['time']
cur_speed = cur_segm['line']['length'] / cur_segm['line']['time']
cur_time = cur_segm['line']['time']
acceleration_list.append(self.__get_acceleration(prev_speed, cur_speed,
cur_time))
return acceleration_list
else:
return []
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_acceleration_list: " + str(ex) + "\n\n")
def __get_int_param_difference_list(self, scroll_list, key):
try:
if len(scroll_list) != 0:
difference_list = []
for pos in range(1, len(scroll_list)):
prev_segm = scroll_list[pos - 1]
cur_segm = scroll_list[pos]
difference = ceil(abs(prev_segm[key] - cur_segm[key]))
difference_list.append(difference)
return difference_list
else:
return []
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_int_param_difference_list: " + str(ex) + "\n\n")
def __get_scroll_speed_list(self, bias_list, time_difference, screen_diag):
try:
if len(bias_list) != 0 and len(time_difference) != 0:
scroll_speed_list = []
for pos in range(0, len(bias_list)):
if time_difference[pos] != 0:
speed = bias_list[pos] / screen_diag / time_difference[pos]
scroll_speed_list.append(round(speed, 7))
return scroll_speed_list
else:
return []
96
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_scroll_speed_list: " + str(ex) + "\n\n")
def __get_key_press_stop(self, key_press_list):
try:
if len(key_press_list) != 0:
stop_key = 'is_stop'
key_press_list[0][stop_key] = False
key_press_list[-1][stop_key] = True
for pos in range(0, len(key_press_list) - 2):
next_segm = key_press_list[pos + 1]
cur_segm = key_press_list[pos]
if next_segm['time'] - cur_segm['time'] >= 3000:
key_press_list[pos + 1][stop_key] = True
else:
key_press_list[pos + 1][stop_key] = False
return key_press_list
else:
return []
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_key_press_stop: " + str(ex) + "\n\n")
def __get_cursor_path(self, path_list, scr_diag):
try:
if len(path_list) != 0:
cursor_path = []
for pos in range(1, len(path_list)):
prev_vert = path_list[pos - 1]
cur_vert = path_list[pos]
path_segm_len = self.__get_distance(prev_vert['x'], prev_vert['y'], cur_vert['x'],
cur_vert['y'])
path_segm_time = cur_vert['time'] - prev_vert['time']
if path_segm_time != 0:
path_unit = {'length': path_segm_len, 'time': path_segm_time}
path_segm = {'sol': copy(prev_vert), 'eol': copy(cur_vert), 'line': path_unit}
cursor_path.append(path_segm)
return cursor_path
else:
return []
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_cursor_path: " + str(ex) + "\n\n")
def __get_start_stop(self, cursor_path):
try:
if len(cursor_path) != 0:
start_key = 'is_start'
stop_key = 'is_stop'
cur_pos = 0
cursor_path[0]['sol'][start_key] = True
97
cursor_path[0]['eol'][stop_key] = False
cursor_path[-1]['eol'][stop_key] = True
cursor_path[-1]['sol'][start_key] = False
for segm in cursor_path[1:-1]:
segm['sol'][start_key] = False
segm['eol'][stop_key] = False
while cur_pos < len(cursor_path):
timer = 0
distance = 0
while timer <= 500:
timer += cursor_path[cur_pos]['line']['time']
distance += cursor_path[cur_pos]['line']['length']
cur_pos += 1
if cur_pos > len(cursor_path) - 1:
return cursor_path
if distance > 5:
break
if distance <= 5:
cursor_path[cur_pos]['sol'][start_key] = True
cursor_path[cur_pos - 1]['eol'][stop_key] = True
return cursor_path
else:
return []
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_start_stop: " + str(ex) + "\n\n")
def __get_stop_count(self, start_stop):
try:
if len(start_stop) != 0:
stop_count = 0
for segm in start_stop:
if segm['eol']['is_stop']:
stop_count += 1
return stop_count
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_stop_count: " + str(ex) + "\n\n")
def __get_start_stop_distance(self, start_stop):
try:
if len(start_stop) != 0:
start_stop_distance = []
cur_pos = 0
while cur_pos < len(start_stop):
timer = 0
distance = 0
while not start_stop[cur_pos]['eol']['is_stop']:
timer += start_stop[cur_pos]['line']['time']
distance += start_stop[cur_pos]['line']['length']
98
cur_pos += 1
timer += start_stop[cur_pos]['line']['time']
distance += start_stop[cur_pos]['line']['length']
cur_pos += 1
start_stop_distance.append({'ddist': distance, 'dtime': timer})
return start_stop_distance
else:
return []
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_start_stop_distance: " + str(ex) + "\n\n")
def __get_min_start_stop_distance(self, start_stop_distance, screen_diag):
try:
if len(start_stop_distance) != 0:
start_stop_dist = sorted(start_stop_distance, key=itemgetter('ddist'))
return round(start_stop_dist[0]['ddist'] / screen_diag, 3)
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_min_start_stop_distance: " + str(ex) + "\n\n")
def __get_max_start_stop_distance(self, start_stop_distance, screen_diag):
try:
if len(start_stop_distance) != 0:
start_stop_dist = sorted(start_stop_distance, key=itemgetter('ddist'))[::-1]
return round(start_stop_dist[0]['ddist'] / screen_diag, 3)
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_max_start_stop_distance: " + str(ex) + "\n\n")
def __get_avg_start_stop_distance(self, start_stop_distance, screen_diag):
try:
if len(start_stop_distance) != 0:
dist_sum = 0
for dist in start_stop_distance:
dist_sum += dist['ddist']
return round(dist_sum / len(start_stop_distance) / screen_diag, 3)
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_avg_start_stop_distance: " + str(ex) + "\n\n")
def __get_min_cursor_speed(self, start_stop_distance, screen_diag):
try:
if len(start_stop_distance) != 0:
speed_list = []
for dist in start_stop_distance:
99
speed = dist['ddist'] / screen_diag / dist['dtime']
speed_list.append(speed)
return round(min(speed_list), 7)
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_min_cursor_speed: " + str(ex) + "\n\n")
def __get_max_cursor_speed(self, start_stop_distance, screen_diag):
try:
if len(start_stop_distance) != 0:
speed_list = []
for dist in start_stop_distance:
speed = dist['ddist'] / screen_diag /dist['dtime']
speed_list.append(speed)
return round(max(speed_list), 7)
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_max_cursor_speed: " + str(ex) + "\n\n")
def __get_avg_cursor_speed(self, start_stop_distance, screen_diag):
try:
if len(start_stop_distance) != 0:
speed_list = []
for dist in start_stop_distance:
speed = dist['ddist'] / screen_diag / dist['dtime']
speed_list.append(speed)
return round(sum(speed_list) / len(speed_list), 7)
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_avg_cursor_speed: " + str(ex) + "\n\n")
def __get_max_positive_acceleration(self, acceleration_list):
try:
if len(acceleration_list) != 0:
return max(acceleration_list)
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_max_positive_acceleration: " + str(ex) + "\n\n")
def __get_min_positive_acceleration(self, acceleration_list):
try:
positive_acc = [acc for acc in acceleration_list if acc > 0]
if len(positive_acc) != 0:
return min(positive_acc)
100
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_min_positive_acceleration: " + str(ex) + "\n\n")
def __get_avg_positive_acceleration(self, acceleration_list):
try:
if len(acceleration_list) != 0:
positive_acc_list = []
for acc in acceleration_list:
if acc > 0:
positive_acc_list.append(acc)
if len(positive_acc_list) != 0:
return round(sum(positive_acc_list) / len(positive_acc_list), 3)
else:
return None
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_avg_positive_acceleration: " + str(ex) + "\n\n")
def __get_avg_negative_acceleration(self, acceleration_list):
try:
if len(acceleration_list) != 0:
negative_acc_list = []
for acc in acceleration_list:
if acc < 0:
negative_acc_list.append(acc)
if len(negative_acc_list) != 0:
return round(sum(negative_acc_list) / len(negative_acc_list), 3)
else:
return None
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_avg_negative_acceleration: " + str(ex) + "\n\n")
def __get_max_scroll_speed(self, scroll_speed):
try:
if len(scroll_speed) != 0:
for i in range(0, len(scroll_speed)):
scroll_speed[i] = fabs(scroll_speed[i])
return fabs(max(scroll_speed))
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_max_scroll_speed: " + str(ex) + "\n\n")
101
def __get_min_scroll_speed(self, scroll_speed):
try:
if len(scroll_speed) != 0:
for i in range(0, len(scroll_speed)):
scroll_speed[i] = fabs(scroll_speed[i])
return fabs(min(scroll_speed))
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_min_scroll_speed: " + str(ex) + "\n\n")
def __get_avg_scroll_speed(self, scroll_speed):
try:
if len(scroll_speed) != 0:
return round(sum(scroll_speed) / len(scroll_speed), 3)
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_avg_scroll_speed: " + str(ex) + "\n\n")
def __get_scroll_count(self, scroll_list):
try:
return len(scroll_list)
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_scroll_count: " + str(ex) + "\n\n")
def __get_preffered_cursor_position(self, path_list, width_middle):
try:
if len(path_list) != 0:
left_position = 0
right_position = 0
for cursor in path_list:
if cursor['x'] > width_middle:
right_position += 1
else:
left_position += 1
if left_position == right_position:
left_position += 1
if left_position > right_position:
return "l"
else:
return "r"
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_preffered_cursor_position: " + str(ex) + "\n\n")
def __get_avg_key_press_speed(self, key_press_stop_list):
102
try:
if len(key_press_stop_list) > 1:
time_press_count = key_press_stop_list[0]['time']
key_press_count = len(key_press_stop_list)
speed_key_press_list = []
for key in key_press_stop_list:
if key['is_stop'] == True:
time_press_count = key['time'] - time_press_count
if time_press_count != 0:
speed_list_elem = key_press_count / (time_press_count / 1000)
speed_key_press_list.append(round(speed_list_elem, 2))
time_press_count = key['time']
key_press_count = 0
return round(sum(speed_key_press_list) / len(speed_key_press_list), 3)
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_avg_key_press_speed: " + str(ex) + "\n\n")
def __get_mouse_click_count(self, mouse_click_list):
try:
return len(mouse_click_list)
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_mouse_click_count: " + str(ex) + "\n\n")
def __get_max_time_mouse_click(self, mouse_click_list):
try:
if len(mouse_click_list) > 1:
time_mouse_click_list = []
for pos in range(0, len(mouse_click_list) - 1):
cur_click = mouse_click_list[pos]
next_click = mouse_click_list[pos + 1]
time_difference = next_click['time'] - cur_click['time']
time_mouse_click_list.append(time_difference)
return max(time_mouse_click_list)
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nError in
__get_max_time_mouse_click: " + str(ex) + "\n\n")
def __get_fact_of_selection(self, mouse_selection_list):
try:
if len(mouse_selection_list) > 0:
return 'y'
else:
return 'n'
103
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nException in
__get_fact_of_selection: " + str(ex) + "\n\n")
def __get_count_backspace_press(self, key_press_list):
try:
if len(key_press_list) != 0:
count = 0
for key in key_press_list:
if key["code"] == 8:
count += 1
return count
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nException in
__get_count_backspace_press: " + str(ex) + "\n\n")
def __get_count_selection(self, mouse_selection_list):
try:
if len(mouse_selection_list) != 0:
return len(mouse_selection_list) / mouse_selection_list[0]['allTextLength']
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nException in
__get_count_selection: " + str(ex) + "\n\n")
def __get_count_selection_symbols(self, mouse_selection_list):
try:
if len(mouse_selection_list) != 0:
result_user_select_str = ""
for symbols in mouse_selection_list:
if symbols['text'] != None:
result_user_select_str += symbols['text']
return len(result_user_select_str) / mouse_selection_list[0]['allTextLength']
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nException in
__get_count_selection_symbols: " + str(ex) + "\n\n")
def __get_length_answer_in_textarea(self, key_press_list):
try:
if len(key_press_list) != 0:
length = 0
for key in key_press_list:
if key['elemType'] == 'TEXTAREA':
length += 1
return length
else:
return None
104
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nException in
__get_length_answer_in_textarea: " + str(ex) + "\n\n")
def __get_length_answer_in_singleline(self, key_press_list):
try:
if len(key_press_list) != 0:
length = 0
for key in key_press_list:
if key['elemType'] != 'TEXTAREA':
length += 1
return length
else:
return None
except Exception as ex:
log.exception(str(datetime.now()) + "\nID: " + self.__participant_id + "\nException in
__get_length_answer_in_singleline: " + str(ex) + "\n\n")
def __get_user_class(self, coeff):
if coeff != None:
if coeff >= 0:
return '+'
else:
return '-'
else:
return random.choice(['+', '-'])
def __get_gender(self, gender_index):
if gender_index == 1:
return 'm'
else: return 'w'
def __get_device(self, device_index):
if device_index == 1:
return 'm'
else: return 't'
Модуль Data_analyze.py
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pprint import pprint
plt.style.use('ggplot')
105
data = pd.read_csv('kagan_user_downloaded_data2.csv', na_values='?')
data.shape
categorical_columns = [c for c in data.columns if data[c].dtype.name == 'object' and c != '34']
numerical_columns = [c for c in data.columns if data[c].dtype.name != 'object' and c != '34']
json_data = {}
json_data['numerical_columns'] = numerical_columns
descr = data.describe()
for col in numerical_columns:
json_data[col] = {
'mean': descr[col]['mean'],
'std': descr[col]['std'],
'50%': descr[col]['50%']
}
data = data.fillna(data.median(axis=0), axis=0)
data['24'] = data['24'].fillna('r')
data_describe = data.describe(include=[object])
binary_columns = [c for c in categorical_columns if data_describe[c]['unique'] == 2]
nonbinary_columns = [c for c in categorical_columns if data_describe[c]['unique'] > 2]
json_data['binary_columns'] = binary_columns
for c in binary_columns:
top = data_describe[c]['top']
print(top)
top_items = data[c] == top
data.loc[top_items, c] = 0
data.loc[np.logical_not(top_items), c] = 1
json_data[c] = {
'top_value': top,
'top_replacement': 0,
'nontop_replacement': 1
}
data_nonbinary = pd.get_dummies(data[nonbinary_columns])
json_data['dummy_encoding'] = data_nonbinary.columns.tolist()
data_numerical = data[numerical_columns]
data_numerical = (data_numerical - data_numerical.mean()) / data_numerical.std()
import json
json_data['nonbinary_values'] = sorted(data['6'].unique().tolist())
with open('Help.json', 'w') as f:
json.dump(json_data, f)
top = data_describe['34']['top']
top_items = data['34'] == top
data.loc[top_items, '34'] = 0
data.loc[np.logical_not(top_items), '34'] = 1
data = pd.concat((data_numerical, data[binary_columns], data_nonbinary, data['34']), axis=1)
data = pd.DataFrame(data, dtype=float)
data.to_csv('kagan_prepeared_data2.csv', index = False)
106
Модуль Model.py
from keras.models import Model, Sequential
from keras.layers import Dense, Activation, Input, Dropout, Conv1D, Embedding, Flatten
from keras.utils import np_utils
from sklearn.cross_validation import train_test_split
import pandas as pd
import numpy as np
from sklearn.metrics import classification_report
from sklearn.utils import shuffle
from keras import optimizers
from keras.datasets import mnist
BATCH_SIZE = 8
NUM_EPOCHS = 50
HIDDEN_LAYER_SIZE = 200
CLASS_COUNT = 2
data = pd.read_csv('kagan_prepeared_data2.csv', skiprows=[0], header=None)
X = data.drop((37), axis=1)
y = data.iloc[:, -1:]
y = np.array(y)
y = y.reshape((y.shape[0],)).astype('uint8')
y = np_utils.to_categorical(y, CLASS_COUNT)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 11)
X_train, y_train = shuffle(X_train, y_train, random_state=12)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 100
X_test /= 100
print('test_string:', np.array(X_test)[0,])
print('X_test', X_test)
Y_train = y_train
Y_test = y_test
model = Sequential()
model.add(Dense(HIDDEN_LAYER_SIZE, input_shape=(X_train.shape[1],)))
model.add(Dropout(0.2))
model.add(Dense(HIDDEN_LAYER_SIZE, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(HIDDEN_LAYER_SIZE, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(CLASS_COUNT, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
107
model.fit(X_train, Y_train,
batch_size=BATCH_SIZE, epochs=NUM_EPOCHS,
verbose=1, validation_split=0.1)
print(model.evaluate(X_test, Y_test, verbose=1))
print(classification_report(Y_train, model.predict_classes(X_train, batch_size=batch_size,
verbose=1)))
model.save('model')
Модуль Config.py
SERVER_HOST = 'localhost'
SERVER_PORT = 443
REDIS_HOST = '192.168.99.100'
REDIS_PORT = 32768
REDIS_SESSIONS_FOLDER = 'sessions'
LOG_FILE_NAME = 'Log.txt'
HELP_FILE_NAME = 'Help.json'
MODEL_FILE_NAME = 'model'
EXTERNAL_SERVICE_URL = 'http://localhost:443/res'
# Downloader settings
RQ_THREADS = 13
RAW_DATA_CSV = 'Raw_data.json'
RESULT_PARAMETERS_CSV = 'Result_parameters.csv'
PARTICIPANTS_API_URL = "http://62.76.36.235/api/v1/participants/%s"
SESSIONS_API_URL = "http://62.76.36.235/api/v1/participants/%s/tracks"
Модуль Server_classificator.py
import asyncio
import aiohttp
import aioredis
import config
import time
import json
import logging
from classification_utils import ClassificationUtils
log = logging.getLogger("Server_classificator")
log.setLevel(logging.INFO)
108
fh = logging.FileHandler(config.LOG_FILE_NAME)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
fh.setFormatter(formatter)
log.addHandler(fh)
class ServerClassificator:
def __init__(self):
try:
self.conn = None
self.classification_utils = ClassificationUtils()
except Exception as ex:
log.error('Error in __init__: %s' % str(ex))
def __delete__(self):
try:
log.info('Connection closed')
self.conn.close()
except Exception as ex:
log.error('Error in __delete__: %s' % str(ex))
async def redis_connect_tcp(self):
try:
self.conn = await aioredis.create_connection((config.REDIS_HOST,
config.REDIS_PORT), db=10, encoding='utf-8')
log.info('Connected successfully')
except Exception as ex:
log.error('Error in redis_connect_tcp: %s' % str(ex))
async def fetch(self, session, url, data):
try:
async with session.post(url, json=data) as response:
return await response.text()
except Exception as ex:
log.error('Error in fetch: %s' % str(ex))
async def handle(self, session):
try:
parameters = self.classification_utils.get_parameters(session)
prepeared = self.classification_utils.prepare_parameters(parameters)
predicted_class = self.classification_utils.classificate(prepeared)
109
async with aiohttp.ClientSession() as session:
asyncio.ensure_future(self.fetch(session, config.EXTERNAL_SERVICE_URL,
predicted_class))
except Exception as ex:
log.error('Error in handle: %s' % str(ex))
async def listen_redis(self):
try:
while True:
session = await self.conn.execute('brpop', config.REDIS_SESSIONS_FOLDER, 0)
if session != None and len(session) == 2:
session_to_classificate = json.loads(session[1])
asyncio.ensure_future(self.handle(session_to_classificate))
else:
break
except Exception as ex:
log.error('Error in listen_redis: %s' % str(ex))
if __name__ == '__main__':
try:
client_classificator = ServerClassificator()
asyncio.get_event_loop().run_until_complete(client_classificator.redis_connect_tcp())
asyncio.get_event_loop().run_until_complete(client_classificator.listen_redis())
except Exception as ex:
log.error('Error in __main__: %s' % str(ex))
Модуль Classification_utils
import pandas
import json
import logging
import numpy as np
from pprint import pprint
from keras.models import load_model
from Handler import Handler
import config
log = logging.getLogger("Classification_utils")
log.setLevel(logging.INFO)
fh = logging.FileHandler(config.LOG_FILE_NAME)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
fh.setFormatter(formatter)
log.addHandler(fh)
110
class ClassificationUtils:
def __init__(self):
try:
self.participant_id = None
self.model = load_model(config.MODEL_FILE_NAME)
self.help_json = open(config.HELP_FILE_NAME, "r")
self.help = json.load(self.help_json)
self.numeric_columns = self.help['numerical_columns']
self.binary_columns = self.help['binary_columns']
self.dummy_encoding_cols = self.help['dummy_encoding']
except Exception as ex:
log.error('Exeption in __init__: %s' % str(ex))
def __delete__(self, instance):
try:
self.help_json.close()
except Exception as ex:
log.error('Exeption in __delete__: %s' % str(ex))
def __normalize(self, param, num_col):
try:
return (param - self.help[num_col]['mean']) / self.help[num_col]['std']
except Exception as ex:
log.error('Exeption in __normalize: %s' % str(ex))
def __prepare_num_cols(self, parameters):
try:
for num_col in self.numeric_columns:
if parameters[num_col] == None:
parameters[num_col] = self.__normalize(self.help[num_col]['50%'], num_col)
else:
parameters[num_col] = self.__normalize(parameters[num_col], num_col)
except Exception as ex:
log.error('Exeption in __prepare_num_cols: %s' % str(ex))
def __prepare_binary_cols(self, parameters):
try:
for cat_col in self.binary_columns:
if parameters[cat_col] == None:
parameters[cat_col] = self.help[cat_col]['top_replacement']
else:
111
if parameters[cat_col] == self.help[cat_col]['top_value']:
parameters[cat_col] = self.help[cat_col]['top_replacement']
else:
parameters[cat_col] = self.help[cat_col]['nontop_replacement']
except Exception as ex:
log.error('Exeption in __prepare_binary_cols: %s' % str(ex))
def __prepare_nonbinary_col(self, parameters):
try:
nonbinary_param_index = self.help['nonbinary_values'].index(parameters['6'])
for ecol in self.dummy_encoding_cols:
ecol_index = self.dummy_encoding_cols.index(ecol)
if nonbinary_param_index == ecol_index:
parameters[ecol] = 1
else:
parameters[ecol] = 0
except Exception as ex:
log.error('Exeption in __prepare_nonbinary_col: %s' % str(ex))
def __add_to_params(self, params_list, cols, parameters):
try:
for col in cols:
params_list.append(parameters[col])
except Exception as ex:
log.error('Exeption in __add_to_params: %s' % str(ex))
def get_parameters(self, session):
try:
self.participant_id = session['participant_id']
session_handler = Handler(session)
parameters = session_handler.get_parameters()
del session_handler
return parameters
except Exception as ex:
log.error('Exeption in get_parameters: %s' % str(ex))
def prepare_parameters(self, parameters):
try:
self.__prepare_num_cols(parameters)
self.__prepare_binary_cols(parameters)
self.__prepare_nonbinary_col(parameters)
parameters.pop('6', None)
112
parameters.pop('34', None)
for key, value in parameters.items():
parameters[key] = value / 100
params_list = []
self.__add_to_params(params_list, self.numeric_columns, parameters)
self.__add_to_params(params_list, self.binary_columns, parameters)
self.__add_to_params(params_list, self.dummy_encoding_cols, parameters)
return params_list
except Exception as ex:
log.error('Exeption in prepare_parameters: %s' % str(ex))
def classificate(self, prepeared_params):
try:
final_params = np.array(prepeared_params)
final_params = final_params.reshape((1, final_params.shape[0]))
predicted = self.model.predict(final_params)
predicted_class = None
if predicted[0][0] > predicted[0][1]:
predicted_class = '-'
elif predicted[0][0] < predicted[0][1]:
predicted_class = '+'
else:
predicted_class = 'high_degree_of_uncertainty'
return \
{
'participant_id': self.participant_id,
'class': predicted_class
}
except Exception as ex:
log.error('Exeption in classificate: %s' % str(ex))
Powered by TCPDF (www.tcpdf.org)
1/--страниц
Пожаловаться на содержимое документа