МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ федеральное государственное бюджетное образовательное учреждение высшего образования «УЛЬЯНОВСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ» Факультет__ФИСТ_____________ Кафедра __Информационные системы__ УТВЕРЖДАЮ Руководитель предприятия К ЗАЩИТЕ ДОПУСТИТЬ Зав. кафедрой _______________/ _______________ / ____________ /_Н. Г. Ярушкина__/ подпись инициалы, фамилия подпись «___»__________________ 20__ г. инициалы, фамилия «___»_________________ 20__ г. БАКАЛАВРСКАЯ РАБОТА Тема__Разработка автоматизированной системы выявления аномалий SQL-запросов PostgreSQL _________________________________________ Студент ________________________ /_Д. А. Фасхутдинова________/ подпись инициалы, фамилия Обозначение ВКР _ БР – УлГТУ – 09.03.04 – 14/456 – 2018 Группа _ПИбд-41 для технических направлений подготовки (специальностей) Направление подготовки (специальность) ___09.03.04________________ код, наименование _____________Программная инженерия_____________________________ Руководитель ВКР ______________________ /_Н.В. Корунова_______/ подпись, дата Ульяновск 2018 г. инициалы, фамилия МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ федеральное государственное бюджетное образовательное учреждение высшего образования «УЛЬЯНОВСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ» Факультет__ФИСТ_____________ Кафедра __Информационные системы__ Направление подготовки (специальность) 09.03.04_Программная инженерия УТВЕРЖДАЮ Зав. кафедрой ____________ /_Н. Г. Ярушкина__/ подпись инициалы, фамилия «___»_________________ 20__ г. ЗАДАНИЕ на бакалаврскую работу студент Фасхутдинова Диляра Альбертовна курса __4_ группы _ПИбд-41____ фамилия, имя, отчество Тема ВКР _Разработка автоматизированной системы выявления аномалий SQLзапросов PostgreSQL________________________________________________ утверждена приказом по УлГТУ от «12» декабря 2017 г. №_2422_ Срок сдачи обучающимся законченной ВКР______________________________ Исходные данные к ВКР__ При огромных объемах хранимой информации в базах данных, возникают ошибки, ведущие к задержкам доступа к данным, либо их потерей, которые необходимо выявить и устранить. Необходимо разработать автоматизированную систему для выявления ошибочных данных (аномалий) в базе данных, что позволит быстро выявить узкие места в работе системы.__________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ Содержание расчетно-пояснительной записки (перечень подлежащих разработке вопросов)_____________________________________________________________ _1. Анализ предметной области и формирование требований к разработке____ _2. Проект разработки системы_______________________________________ _3. Оценка эффективности проекта_____________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ Перечень графического материала (с точным указанием обязательных диаграмм проектного решения)___________________________________________________ _модели «Как есть» и «Как должно быть», диаграмма потоков данных, диаграмма вариантов использования, диаграмма классов, диаграмма последовательности, диаграмма компонентов__________________________________________ _____________________________________________________________________ _____________________________________________________________________ __________________________________________________________________ Календарный график работы над ВКР на весь период (с указанием сроков выполнения и содержания отдельных этапов) № Содержание этапа Срок этапа выполнения 1 Анализ предметной области 05.02 – 14.02 2 Формирование требований 15.02 – 06.03 3 Обзор методов решения задачи 07.03 – 05.04 4 Разработка проекта 06.04 – 13.05 5 Тестирование 14.05 – 20.05 6 Составление документации 20.05 – 03.06 Дата выдачи задания «12» декабря 2017 г. Руководитель__ст. преподаватель___ ___________ / _Н. В. Корунова___/ должность, учёная степень, ученое звание подпись инициалы, фамилия Задание принял к исполнению ______________ /_Д. А. Фасхутдинова___ подпись студента инициалы, фамилия / АННОТАЦИЯ В данной бакалаврской работе приведено описание разработки системы, предназначенной для автоматизации выявления аномалий данных, которые хранятся в системе управления базами данных PostgreSQL. В первой главе приведены анализ предметной области, описание задач системы, постановка задания на разработку проекта, а так же календарно-ресурсное планирование. Во второй главе приводятся результаты проектирования программы: описана функциональная структура проекта, её обеспечение и обоснование выбранных технологий, а так же демонстрируется работа программы. Третья глава содержит расчеты затрат на реализацию проекта, а так же результаты тестирования готового программного продукта. СОДЕРЖАНИЕ ВВЕДЕНИЕ ..................................................................................................................... 7 1. ОБЗОР ПРЕДМЕТНОЙ ОБЛАСТИ ................................................................. 9 1.1. Описание задачи выявления аномалий в данных ........................................ 9 1.1.1. Описание предметной области ......................................................... 9 1.1.2. Описание проблемы ручного выявления аномалий ........................ 15 1.1.3. Состояние и стратегия развития схожих решений. ................... 15 1.2. Постановка задачи ........................................................................................ 15 1.2.1. Цели и задачи проекта ..................................................................... 15 1.2.2. Построение и обоснование модели автоматизированной системы выявления аномалий ......................................................................... 18 1.2.3. Спецификация и обоснование нефункциональных требований ... 19 1.3. Календарно-ресурсное планирование проекта, анализ бюджетных ограничений и рисков ........................................................................................... 21 1.3.1. Модель жизненного цикла разработки информационной системы 21 1.3.2. Анализ ограничений и рисков ........................................................... 21 1.3.3. Календарно-ресурсное планирование проекта, анализ бюджетных ограничений и рисков ................................................................. 22 2. ПРОЕКТ РАЗРАБОТКИ АВТОМАТИЗИРОВАННОЙ СИСТЕМЫ ВЫЯВЛЕНИЯ АНОМАЛИЙ .................................................................................... 25 2.1. Функциональная структура.......................................................................... 25 2.2. Информационное обеспечение .................................................................... 29 2.3. Математическое обоснование...................................................................... 32 2.4. Программное обеспечение ........................................................................... 38 2.5. Техническое обеспечение ............................................................................ 38 2.6. Обеспечение информационной безопасности ........................................... 39 БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Разраб. Фасхутдинова Д.А. Руковод. Корунова Н. В. Эгов Е. Н. Н. контр. Реценз. Утвержд. Ярушкина Н.Г. Подпись Дата Разработка автоматизированной системы выявления аномалий SQL-запросов PostgreSQL Лит Лист Листов Б 5 77 Кафедра ИС гр. ПИбд-41 2.7. Технологическое обеспечение ..................................................................... 39 2.8. Контрольный пример .................................................................................... 40 3. ОЦЕНКА ЭФФЕКТИВНОСТИ ПРОЕКТА .................................................. 46 3.1. Анализ затрат на ресурсное обеспечение (оценка совокупной стоимости владения) ................................................................................................................ 46 3.2. Тестирование ПО .......................................................................................... 49 3.2.1. Установочное тестирование .......................................................... 49 3.2.2. Бета-тестирование.......................................................................... 49 3.2.3. Интеграционное тестирование ...................................................... 51 3.2.4. Тестирование Usability ..................................................................... 51 3.2.5. Эксперименты с системой .............................................................. 51 ЗАКЛЮЧЕНИЕ ........................................................................................................... 55 СПИСОК ЛИТЕРАТУРЫ ......................................................................................... 56 ПРИЛОЖЕНИЕ А. ЛИСТИНГ ПРОГРАММЫ ................................................... 59 БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Разраб. Фасхутдинова Д.А. Руковод. Корунова Н. В. Эгов Е. Н. Н. контр. Реценз. Утвержд. Ярушкина Н.Г. Подпись Дата Разработка автоматизированной системы выявления аномалий SQL-запросов PostgreSQL Лит Лист Листов Б 6 77 Кафедра ИС гр. ПИбд-41 ВВЕДЕНИЕ Базы данных – необходимая составляющая для большинства информационных систем, окружающих нас. В них хранятся порой огромные объемы информации. И там могут появляться данные, отличающиеся от общего шаблона, которые в данной работе будут называться дефекты или аномалии. Современные системы управления базами данных имеют огромные встроенные возможности валидации данных. Однако, не смотря на развитие технологий, не все компании готовы переходить на новые программы. Таким образом, использование устаревших систем управления базами данных (СУБД), не имеющих встроенные функции проверки корректности полей, или их некорректная настройка, могут приводить к появлению аномалий. Так же дефекты могут появиться вследствие человеческого фактора. Долговременное использование имеющихся хранилищ данных могут приводить к ситуациям, когда со временем первоначальный формат записи в них информации искажается, потому что теряется общая информация о правилах заполнения и структуре таблиц. Тогда, на плечи администратора ложиться сложная задача – выявить подобные дефекты – аномалии. При больших объемах данных поиск занимает огромное количество времени, при этом существует большая вероятность пропустить аномалию, и тогда поиск придется повторять снова. Не смотря на актуальность вопроса на данный момент нет широко распространённых программных продуктов, способных выявлять аномалий в данных. Для решения данной задачи необходимо разработать автоматизированную систему выявления аномалий данных. Выявление дефектных данных должно быть реализовано с применением различных методов для каждого типа данных. Пользователь должен иметь возможность самостоятельно настраивать методы поиска или же использовать данные, представленные программой по умолчанию. На выходе пользователь должен получить отчет о выявленных аномалиях. Целью проекта является сокращение времени на процесс выявления точечных аномалий в данных. Задачи, необходимые для реализации: a) произвести анализ предметной области выявления аномалий; Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 7 b) спроектировать приложение для автоматизированного системы выяв- ления аномалий; c) разработать автоматизированную систему выявления аномалий. Решение реализовано в виде десктоп-приложения, ориентированного на работу с операционной системой Microsort, в котором будет реализовано взаимодействие с системой управления базами данных PostgreSQL. В качестве IDE будет использована Visual Studio, а для управления версиями использоваться GIT. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 8 1. ОБЗОР ПРЕДМЕТНОЙ ОБЛАСТИ 1.1. Описание задачи выявления аномалий в данных 1.1.1. Описание предметной области Выявление аномалий - одна из интереснейших областей исследования, имеющая необычайную популярность в наши дни. В сети можно найти достаточное количество статей и исследовательских работ, посвященных данной теме. В процессе изучения материалов, относящихся к выявлению аномалий, было выявлено три основных направления исследований. a) Аномалии поведения. Данное направление исследований ориентировано, в первую очередь, на выявление закономерностей в имеющихся данных и выявление аномалий в тех, что поступают в систему после. Чаще всего, решения в данной области используются для обеспечения информационной безопасности, в частности, для выявления угроз несанкционированного доступа к данным. В таких случаях, анализу подвергаются потоки данных или же информация о действиях пользователя в системе. Например, банке хранятся данные о действиях пользователя относительно его счета. На основе данной информации, строится профиль его поведения, и все дальнейшие операции будут сравниваться с ним. Если действие будет отличаться от стандартного, то система получит сообщение об аномалии и может среагировать на потенциально нежелательную ситуацию. Например, заблокирует данную транзакцию.[24] b) Аномалии проектирования. Исследования в этой области направлены на выявления дефектов при проектировании в структуре баз данных и ошибках при настройке валидации полей. Чаще всего, задача формулируется как определение нормальной формы, в которой находится база, а в качестве решения могут быть использованы рекомендации к исправлению аномалий и методы нормализации БД. В рамках данной группы аномалий выделяются следующие виды: 1. Аномалии вставки. Данные виды дефектов проявляются при вводе новых данных. Чаще всего, данный тип аномалии связан с валидацией Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 9 полей. В качестве примера для данной и последующих аномалий данной группы, будем рассматривать базу данных, хранящую информацию о деятельности студенческих объединений. В ней, предположительно, есть таблицы с информацией об активистах, и, допустим, о мероприятиях данных объединений. Допустим, что таблица с информацией о студентах, имеет следующие поля: фамилия, имя, группа, объединение. Тогда, добавляя новую запись, мы должны заполнить все поля. Однако если ввести данные, не соответствующие имеющимся в таблице (например, вместо названия объединения – «танцевальный ансамбль «РИО»» ввести его номер - «15»), то тогда мы не сможем с уверенностью сказать, какая из записей корректна. 2. Аномалии обновления. Они возникают при изменении данных дефектной схемы. Чаще всего связаны с ошибками проектирования отношений. Исходя из примера, описанного выше, рассмотрим записи того же танцевального ансамбля. Допустим, что его решили переименовать в творческий коллектив «Реверанс». Необходимо изменить все записи, касающиеся этого объединения, то есть переименовать его названия в записях об активистах и о мероприятиях. Если пропустить хотя бы одну из строк, то в базе возникнет аномалия обновления и будет храниться информация о несуществующем объединении, что может серьезно повлиять на выборку и анализ данных. 3. Аномалии удаления возникают при удалении данных из дефектной схемы. Так же связаны с нарушениями при проектировании, в том числе с ошибками при создании схемы данных. Предположим, что в описанной выше базе данных, нет отдельной таблицы, хранящей данные об объединениях, и их список получают выборкой из таблицы с активистами. Допустим, что все члены объединения «Реверанс» ушили из него. Тогда в базе, после удаления записей об ушедших студентах, не будет ни одной записи об этом объединении.[20] c) Аномалии данных. Исследования данного типа дефектов относится к непосредственному анализу уже имеющихся данных. В данном случае аномалия Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 10 представляются в виде исследования выборки данных на предмет значений, отличающихся ото всех представленных. В данной группе так же выделяются три вида аномалий. 1. Точечные аномалии возникают в ситуации, когда отдельный экземпляр данных может рассматриваться как аномальный по отношению к остальным данным. В данном случае, аномалия представляется в качестве выброса на фоне общей выборки данных. Например, в таблице об активистах в поле ФИО студента, появление числовых значений можно считать аномалией. На рисунке 1 представлено графическое отображение точечной аномалии. Две большие группы данных представляют собой нормальные значения, тогда как точка А является выбросом из общей выборки, или точечной аномалией. Рисунок 1 - Пример точечной аномалии 2. Контекстуальные аномалии наблюдаются, если экземпляр данных является аномальным лишь в определенном контексте, (данный вид аномалий также называется условным). Допустим, что имеется таблица с информацией о среднемесячной температуре. Нулевое значение входит в диапазон допустимых значений данного поля. При этом данная среднемесячная температура в августе является аномалией. Графическое изображение условной аномалии для описанного выше примера представлено на рисунке 2. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 11 Рисунок 2 - Пример контекстной (условной) аномалии 3. Коллективные аномалии возникают, когда последовательность связанных экземпляров данных является аномальной по отношению к целому набору данных. Чаще всего, данные аномалии встречаются в исследованиях временных рядов. Отдельный экземпляр данных в такой последовательности может быть нормальным, однако совместное появление таких экземпляров приводит к коллективной аномалии. Например, на электрокардиограмме человека наблюдается аномальный участок. Само по себе значение не является аномальным, однако длительное его повторение сигнализирует о наличии коллективной аномалии (рисунок 3). Рисунок 3 - Пример коллективной аномалии Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 12 В рамках данной работы главным объектов исследования являются точечные аномалии данных. Для выявления точечных аномалий применяются следующие методы: a) Классификация. Реализация данного метода основана на предположении о том, что данные могут определяться одним или несколькими классами. Тогда, элемент, не принадлежащий ни к одному из классов, является отклонением. Поиск аномалий проходит в два этапа: обучение и распознавание. Классификатор обучается на массиве маркированных данных, далее определяется принадлежность к одному из известных классов. В противном случае экземпляр помечается, как аномалия. Наиболее широко применяемыми механизмами реализации являются: нейронные сети, Байесовы сети, метод опорных векторов и метод на основе правил. b) Кластеризация. Данный метод предполагает группировку похожих экземпляров в кластеры и не требует знаний о свойствах возможных отклонений. Выявление аномалий строится на предположении, что данные, ни относящиеся ни к одному из кластеров, являются аномалиями. Так же имеет место предположение, что аномальные данные находятся дальше всего от центра кластера. В случае, когда аномальные данные не являются единичными, они также могут образовывать кластеры. Тогда, их выявление строится на предположении, что кластеры с аномальными данными малочисленные и разреженные, в отличие от кластеров с нормальными данными. Одной из простейших реализаций подхода на основе кластеризации является алгоритм k-means. c) Статистический анализ. Метод чаще всего применяется при выявлении аномальных данных среди поступающих, на основе уже имеющихся. Для этого строится профиль данных и создается функция аномальности. Если значение функции выше указанного порога, данные считаются аномальными. Применяется предположение том, что нормальное поведение системы будет находиться в зоне высокой вероятности, в то время как выбросы – в зоне низкой. Данный класс методов удобен тем, Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 13 что не требует заранее определенных знаний о виде аномалии. Однако сложности могут возникать в определении точного статистического распределения и порога. d) Алгоритм ближайшего соседа. Для использования данной методики необходимо определить понятие расстояния (меры похожести) между объектами. Примером может быть Евклидово расстояние. Два основных подхода основываются на следующих предположениях: расстояние до k-го ближайшего соседа. Для реализации этого подхода расстояние до ближайшего объекта определяется для каждого тестируемого экземпляра класса. Экземпляр, являющийся выбросом, наиболее отдален от ближайшего соседа. Использование относительной плотности основано на оценке плотности окрестности каждого экземпляра данных. Экземпляр, который находится в окрестности с низкой плотностью, оценивается как аномальный, в то время как экземпляр в окрестности с высокой плотностью оценивается как нормальный. Для данного экземпляра данных расстояние до его k-го ближайшего соседа эквивалентно радиусу гиперсферы с центром в данном экземпляре и содержащей k остальных экземпляров. e) Спектральные методы. Спектральные методы находят аппроксимацию данных, используя комбинацию атрибутов, которые передают большую часть вариативности в данных. Эта методика основана на следующем предположении: данные могут быть вложены в подпространство меньшей размерности, в котором нормальное состояние и аномалии проявляются иначе. Спектральные методы часто применяются совместно с другими алгоритмами для предобработки данных. f) Гибридные методы. Гибридные методики распознавания аномалий, позволяют сочетать преимущества различных подходов. При этом различные техники могут применяться как последовательно, так и параллельно для достижения усредненных результатов.[22] Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 14 1.1.2. Описание проблемы ручного выявления аномалий Поиск дефектных данных в данный момент трудоемкое, монотонное и долгое занятие. Для поиска аномалий в ручном режиме необходимо открывать каждую таблицу и просматривать построчно, попутно сравнивая каждую запись со спецификацией и/или уже просмотренными данными. Время, затрачиваемое на поиск прямо пропорционально количеству таблиц и записей, хранящихся в базе данных. Если в среднем на просмотр одной строки затрачивать 1 секунды, то на исследование базы, суммарно содержащей 10 000 строк, необходимо потратить 10 000 сек или, приблизительно, 2,7 часа. Так же высока вероятность пропустить какое-либо аномальное значение. А это значит, что процесс выявления аномалий придется повторять. Поиск аномалий не требует специфических действий со стороны пользователя. Он четко регламентирован, а, значит, его можно автоматизировать. Благодаря хорошо развитым технологиям можно не только ускорить процесс, но и минимизировать вероятность пропуска аномалии за счет использования различных методик их выявления. 1.1.3. Состояние и стратегия развития схожих решений. В сети можно найти достаточное количество исследований в данной области, однако на данный момент не существует каких-либо распространяемых продуктов, направленных на автоматизацию выявления точечных аномалий данных. 1.2. Постановка задачи 1.2.1. Цели и задачи проекта Целью проекта является сокращение времени на процесс выявления точечных аномалий в данных. Для её достижения было разработано десктопприложение. Описание реализуемых процессов. Базами данных пользуется огромное количество людей, однако чаще всего они взаимодействуют с ними не напрямую, а через прикладные программы или администраторов. Так что в первую очередь проект будет интерес разработчикам подобных прикладных программ и администраторам баз данных, а так же людям, Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 15 в чьи обязанности входят администрирование, сопровождение и поддержка баз данных. В рамках работы над проектом рассматривается СУБД PostgreSQL, так как она изначально была заявлена в условиях поставленной задачи. PostgreSQL — это объектно-реляционная система управления базами данных (ОРСУБД, ORDBMS), основанная на POSTGRES, Version 4.2 — программе, разработанной на факультете компьютерных наук Калифорнийского университета в Беркли. В POSTGRES появилось множество новшеств, которые были реализованы в некоторых коммерческих СУБД гораздо позднее. Она поддерживает большую часть стандарта SQL и предлагает множество современных функций: a) сложные запросы; b) внешние ключи; c) триггеры; d) изменяемые представления; e) транзакционная целостность; f) многоверсионность.[28] Кроме того, пользователи могут всячески расширять возможности PostgreSQL, например, создавая свои: a) типы данных; b) функции; c) операторы; d) агрегатные функции; e) методы индексирования; f) процедурные языки. А благодаря свободной лицензии, PostgreSQL разрешается бесплатно использовать, изменять и распространять всем и для любых целей — личных, коммерческих или учебных[2]. Общее описание процесса выявления аномалий на данный момент представлено моделью «КАК-ЕСТЬ» в нотации IDEF0 [27] и отображен на рисунках 4, 5. Во время поиска аномалий оператор опирается на спецификацию, в которой описан формат записи данных и на сами данные в таблице. Он построчно проЛист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 16 сматривает информацию, сверяясь с документами и уже просмотренными записями, и составляют список, в котором отображены выявленные некорректные записи. На выходе у администратора имеется отчет о выявленных аномалиях. Однако, стоит учесть, что модель не отображает временные затраты на данный процесс, длительность которого прямо пропорциональна количеству информации в исследуемой базе. Рисунок 4 - Модель "КАК-ЕСТЬ" Рисунок 5 - Модель "КАК-ЕСТЬ". Декомпозиция Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 17 1.2.2. Построение и обоснование модели автоматизированной системы выявления аномалий Модель «КАК-ДОЛЖНО-БЫТЬ» (рисунок 6, рисунок 7) так же представлена в нотации IDEF0 и описывает изменения системы. К входным данным добавлены параметры алгоритмов поиска. Сам процесс так же претерпел серьезные изменения. Администратор загружает базу данных в программу. Следующим шагом происходит настройка параметров поиска. Затем, пользователю необходимо лишь нажать на кнопку. Программа применяет различные методы классификации, кластеризации для определённых типов данных. На выходе пользователь получает подробный отчет о найденных дефектах в данных с указанием таблицы и строки с найденной аномалией. В отличие от модели «КАК-ЕСТЬ», пользователь почти не принимает участия в выявлении аномалии. Все действия выполняет программа. Данных подход экономит время администратора базы данных. Рисунок 6 - Модель "КАК-ДОЛЖНО-БЫТЬ" Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 18 Рисунок 7 - Модель "КАК-ДОЛЖНО-БЫТЬ". Декомпозиция Разработанная система должна выполнять следующие функции: a) загрузка БД b) выбор алгоритмов выявления аномалии; c) настройка параметров выявления аномалий; d) анализ БД; e) вывод отчета о результатах анализа; f) сохранение отчета в формате .pdf. 1.2.3. Спецификация и обоснование нефункциональных требований Квалификационные требования персонала С системой может работать только обученный пользователь. Требования к эргономике и технической эстетике Программа должна иметь понятный и удобный для пользователя интерфейс, разработанный в соответствии со стандартами. Понятность интерфейса: интерфейс системы должен быть спроектирован так, чтобы пользователь мог понимать назначение каждого элемента управления. Охват всех функций интерфейсом: интерфейс системы должен обеспечивать доступ ко всем функциям системы. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 19 Простота интерфейса: интерфейс системы должен исключать излишние действия пользователя при работе с системой. Требования к надежности Доступность Приложение и данные должны быть доступны в круглосуточном режиме. Время, затрачиваемое на обслуживание системы не должно превышать 3% от общего времени работы. Наработка на отказ Система не должна нагружать ПК пользователя без необходимости. Норма дефектов В работе системы не должны появляться критические ошибки, приводящие к остановке работы системы. Допускается отсутствие обработки таких ситуаций как: a) сбой операционной системы; b) внезапные сбои аппаратного обеспечения (например, потеря электропитания или механическое повреждение аппаратуры); c) отсутствие ресурсов для продолжения работы (например, переполненность жёсткого диска). Требования к лингвистическому обеспечению Язык программирования – C#. Язык взаимодействия с пользователем – русский. Требования к программному обеспечению На компьютере должен быть установлена СУБД PostgreSQL или же он должен иметь корректное подключение к ней. Требования к техническому обеспечению Для функционирования системы необходимо следующее техническое обеспечение со следующими минимальными характеристиками: a) не менее 512 Mb оперативной памяти; b) не менее 2048 Mb свободного дискового пространства; c) процессор с тактовой частотой не менее 1000 MHz; d) операционная система Windows 7 и выше. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 20 1.3. Календарно-ресурсное планирование проекта, анализ бюджет- ных ограничений и рисков 1.3.1. Модель жизненного цикла разработки информационной системы Исходя из состава команды, всего 1 разработчика, была выбрана методология SCRUM. SCRUM — методология, предназначенная для небольших команд (до 10 человек). Весь проект делится на итерации (спринты) продолжительностью 30 дней каждый. Выбирается список функций системы, которые планируется реализовать в течение следующего спринта. Самые важные условия — неизменность выбранных функций во время выполнения одной итерации и строгое соблюдение сроков выпуска очередного релиза, даже если к его выпуску не удастся реализовать весь запланированный функционал. Scrum не требует внедрения каких-либо дорогостоящих инструментов. Приступая к работе, нужно создать максимально полный список всех требований, предъявляемых к продукту или цели. Пункты этого списка должны быть расставлены по приоритету. Вся работа разбивается на спринты – отрезки времени, за которые выполняется часть пунктов. Основная цель - в каждом следующем спринте должно быть выполнено больше задач, чем в предыдущем. После каждого спринта проводится обсуждение с оценкой проделанной работы. По окончанию разработки проекта выполняется ретроспективный анализ.[10] 1.3.2. Анализ ограничений и рисков Риск – это возможное изменение показателей в худшую или лучшую сторону от запланированных в процессе реализации проекта по причинам, не зависящим от команды разработки. Риски сопровождают любой проект, и предусмотреть их все фактически невозможно. Однако это и не требуется. Анализ рисков при планировании проекта заключается в поиске наиболее «узких» мест в плане и корректировке плана с целью минимизации их количества. [21] Риски проекта a) Отсутствие необходимого количества специалистов для выполнения проекта. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 21 b) Не запланированное выбывание сотрудника из состава команда разработки на некоторое количество дней. c) Невозможность получения лицензии на программное обеспечение, используемое для разработки, запуска и тестирования разрабатываемого сервиса. d) Изменение целей, задач и подхода к реализации проекта на поздних стадиях проекта Границы проекта a) Программа должна устанавливаться на компьютер с ОС Windows не ниже 7. b) Система, через которую осуществляется работа с базами данных – PostgreSQL. Ограничения проекта a) Средством разработки ПО является Visual Studio. b) ПО разрабатывается в виде десктоп-приложения для ОС Windows. Допущения проекта a) Все изменения содержания будут своевременно выноситься на рассмотрение управляющего комитета. b) Сроки выполнения проекта могут быть пересмотрены в ходе реализации проекта в зависимости от вносимых изменений. 1.3.3. Календарно-ресурсное планирование проекта, анализ бюджетных ограничений и рисков Планирование проекта один из главнейших элементов процесса управления проектом. Основным результатом процесса планирования является принятый план проекта. Говоря о нем, обычно подразумевают календарный план проекта – это его главный элемент [6]. В плане, представленном в таблице 1, содержатся наименования работ, даты начала и завершения работ по каждой задачи, так же исполнитель. Таблица 1 - Календарный план проекта Название ID КС1 Начало проекта Дата начала Дата окончания 05.02.18 10.06.18 Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 22 1 Разработка плана проекта 05.02.18 06.03.18 1.1 Анализ предметной области 05.02.18 14.02.18 15.02.18 21.02.18 1.2.1 вспомогательных данных приложе- 15.02.18 16.02.18 Определение функциональных ре- 1.2 шений Определение состава и содержания ния 1.2.2 Определение технологии работы с базой данных Формирование требований. ТЗ 1.3 КС2 Утверждение ТЗ 18.02.18 21.02.18 22.02.18 27.02.18 27.02.18 27.02.18 1.4 Содержание проекта, ИСР 28.02.18 02.03.18 1.5 План проекта 03.03.18 06.03.18 06.03.16 06.03.16 КС3 Завершение разработки плана проекта 2 Проектирование приложения 07.03.18 05.04.18 2.1 Проектирование архитектуры ПО 07.03.18 13.03.18 14.03.18 22.03.18 23.03.18 29.03.18 30.03.18 03.04.18 Проектирование интерфейсов экра- 2.2 нов Прототипирование 2.3 интерфейсов экранов Проектирование алгоритмов анализа 2.4 Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 23 Продолжение таблицы 1 Проектирование алгоритма форми- 2.5 рования отчета КС4 Завершение проектирования 30.03.18 05.04.18 05.04.18 05.04.18 3 Разработка ПО 06.04.18 13.05.18 3.1 Интерфейсы ПО 06.04.18 10.04.18 3.2 Алгоритмы анализа 10.04.18 27.04.18 3.3 Формирование отчета 01.05.18 03.05.18 3.4 Модуль загрузки базы данных 03.05.18 13.05.18 4 Тестирование 14.05.18 20.05.18 4.1 Тестирование полученного ПО 14.05.18 20.05.18 4 Разработка документации 20.05.18 03.06.18 5 Завершение работ по проекту 04.06.18 10.06.18 5.1 Анализ исполнения проекта 04.06.18 10.06.18 Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 24 2. ПРОЕКТ РАЗРАБОТКИ АВТОМАТИЗИРОВАННОЙ СИСТЕМЫ ВЫЯВЛЕНИЯ АНОМАЛИЙ 2.1. Функциональная структура Функциональная структура проекта представлена в виде USE-case диаграммы.[4] Прецедент — возможность моделируемой системы (часть её функциональности), благодаря которой пользователь может получить конкретный, измеримый и нужный ему результат. Прецедент соответствует отдельному сервису системы, определяет один из вариантов её использования и описывает типичный способ взаимодействия пользователя с системой. Варианты использования обычно применяются для спецификации внешних требований к системе[16]. Рисунок 8 - USE-case диаграмма Ниже, представленные на диаграмме варианты использования конкретизируются. Каждый прецедент имеет собственное кодовое значение, состоящее из литеры «П» и порядкового номера описываемого прецедента. П1. Анализ базы данных Основное действующее лицо: Пользователь. Другие участники прецедента: отсутствуют Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 25 Связи с другими вариантами использования: расширяется прецедентом П2 Настройка методов, имеет включение прецедента П4 Загрузка базы данных и П5 Сохранение результатов анализа Краткое описание. Данный вариант использования позволяет пользователю проанализировать данную базу данных и выявить в ней аномалии. Пользователь загружает базу данных. При желании может использовать параметры, заданные системой, или выбрать методов самостоятельно. Выбор методов осуществляется из предоставленного списка. Так же пользователь имеет возможность настраивать параметры. Данные, используя методы классификации и кластеризации, обрабатывают данные, а затем производится анализ «выбившихся» из общих групп значений. На выходе на экран выводится отчет о результатах анализа, содержащий название таблицы и номер строки, в которой выявлена аномалия. П2. Настройка методов Основное действующее лицо: Пользователь. Другие участники прецедента: Отсутствуют Связи с другими вариантами использования: расширяется прецедентом П3 настройка параметров Краткое описание. Данный вариант использования позволяет выбирать методы для обработки различных типов данных. Пользователь может самостоятельно выбирать методы для каждого типа данных из списка доступных методов, представленного в программе. П3. Настройка параметров Основное действующее лицо: Пользователь. Другие участники прецедента: отсутствуют Связи с другими вариантами использования: является расширением П2 Настройка методов Краткое описание. Данный вариант использования позволяет настроить специфичные параметры методов анализа. Настраиваемые параметры зависят от методов. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 26 П4. Загрузка базы данных Основное действующее лицо: Пользователь. Другие участники прецедента: отсутствуют Связи с другими вариантами использования: Является включением П1 Анализ БД Краткое описание. Данный вариант использования позволяет пользователю загрузить базу данных, которую необходимо проанализировать П5. Сохранение результатов анализа Основное действующее лицо: Пользователь. Другие участники прецедента: отсутствуют Связи с другими вариантами использования: является расширением П1 Анализ БД Краткое описание. Позволяют пользователю сохранить результаты анализа для дальнейшего использования. Для лучшего понимания функциональных зависимостей были разработаны диаграммы последовательности. Диаграмма последовательности (англ. sequence diagram) — диаграмма, на которой для некоторого набора объектов на единой временной оси показан жизненный цикл какого-либо определённого объекта (создание-деятельность- уничтожение некой сущности) и взаимодействие актёров (действующих лиц) ИС в рамках какого-либо определённого прецедента (отправка запросов и получение ответов).[15] На рисунке 9 представлена диаграмма последовательности для анализа базы данных, включая в себя настройки параметров алгоритмов. Пользователь запускает программу, выбирает пункт «Анализ базы данных». Затем осуществляется переход к мастеру анализа. На первом шаге пользователь вводит данные, необходимые для подключения к базе данных. Затем пользователь выбирает методы, которые будут использоваться для тех или иных типов данных, или же оставляет настройки по умолчанию. Так же для одного или нескольких методов пользоваЛист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 27 тель настраивает параметры алгоритма. При нажатии кнопки далее запускается анализ данных. Пользователю демонстрируется экран с отображением логов действия системы с таблицами и прогрессом выполнения анализа. По завершению работы система сигнализирует пользователю и после нажатия на кнопку далее, осуществляется переход к окну с результатами работы программы. Там отображаются номер строки, наименование таблицы и столбца, где обнаружена аномалия, а так же само аномальное значение. Рисунок 9 - Диаграмма последовательности для анализа БД с применением всех расширений На рисунке 10 представлена последовательность действий без дополнительных настроек алгоритма. Она повторяет последовательность, описанную на рисунке 9, за исключением пункта изменения параметров алгоритмов. Рисунок 10 - Диаграмма последоательности для анализа БД без настройки параметров методов Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 28 Так же, помимо анализа, у пользователя есть возможность настраивать параметры не только для конкретного анализа, но и сохранять их для последующих тестирований. Последовательность действий отображена на рисунке 11. Пользователь программы на главном окне выбирает пункт «Настройка». Пользователь переходит к окну сопоставления типов данных и методов. Можно выбрать тип данных, для которого будет применяться метод, а так же при нажатии рядом с названием метода кнопки «Настроить», осуществляется переход к окну настройки параметров. Для завершения работы необходимо нажать кнопку сохранить. Рисунок 11 - Диаграмма последовательности для настройки параметров анализа 2.2. Информационное обеспечение Входными данными для системы являются записи из БД, хранящейся в СУБД PostgreSQL. Инфологическая модель разрабатываемой системы представлена в виде диаграммы классов (рисунок 12). Диаграмма классов (англ. Static Structure diagram) — диаграмма, демонстрирующая классы системы, их атрибуты, методы и взаимосвязи между ними[13]. Архитектура программы построена c использованием паттерна MVVM.[5] Паттерн MVVM (Model-View-ViewModel) позволяет отделить логику приложения от визуальной части (представления). Данный паттерн был представлен Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 29 Джоном Госсманом (John Gossman) в 2005 году как модификация шаблона Presentation Model и был первоначально нацелен на разработку приложений в WPF. MVVM состоит из трех компонентов: модели (Model), модели представления (ViewModel) и представления (View). Модель описывает используемые в приложении данные. В то же время модель не должна содержать никакой логики, связанной с отображением данных и взаимодействием с визуальными элементами управления. View или представление определяет визуальный интерфейс, через который пользователь взаимодействует с приложением. ViewModel или модель представления связывает модель и представление через механизм привязки данных.[23] Рисунок 12 - Диаграмма классов В соответствии с этим, программа разбита на три основных компонента: a) View: a. MainWindow – основное окно программы; b. LoadDBWindow – окно подключения к базе данных; c. SettingsWindow – окно сопоставления типов данных и методов; d. SettingsParametrWindow – окно настоек параметров методов; e. AnalysWIndow – окно анализа, в нем отображается подробный отчет о действиях системы и состояние процесса анализа; f. ResultForm – окно результатов анализа; Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 30 b) ViewModel: a. MainWindowVM – содержит взаимодействие данных и интерфейса главного окна программы; b. LoadDBWindowVM – содержит взаимодействие данных и интерфейса подключения к базе данных; c. SettingsWindowVM – содержит взаимодействие данных и интерфейса сопоставления типов данных и методов; d. SettingsParametrWindowVM – содержит взаимодействие данных и интерфейса настоек параметров методов; e. AnalysWIndowMV– содержит взаимодействие данных и интерфейса окно анализа; f. ResultFormMV – содержит взаимодействие данных и интерфейса результатов анализа; c) Model a. GlobalData – хранит в себе основные данные, необходимые для работы программы; b. Analys – описывает основной алгоритм анализа БД; c. LoadDB – хранит в себе логику работы с исследуемой БД; d. DeffectData – описывает формат хранения дефектных данных; e. DataofTable – описывает формат хранения данных о таблицах; f. AlgoritmSettings – описывает форматы хранения вспомогательных данных; Так же, помимо вышеописанных компонентов, в системе есть два вспомогательных: d) Algoritm – хранит в себе использующиеся в системе алгоритмы; a. FCM – описывает алгоритм нечеткой кластеризации данных; b. K_means++ - описывает алгоритм кластеризации на основе k-средних; c. DBScan – описывает плотностный алгоритм кластеризации; d. CLOPE – описывает алгоритм кластеризации категорийных данных. e) SaveReport – описывает генерацию отчета о выявленных аномалиях. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 31 a. GenerateReport – реализует генерацию и сохранение отчета в формате .pdf Реализация описанных выше классов приведена в приложении А. Выходными данными является отчет о результатах анализа, который можно сохранить в PDF-файл. Для хранения соответствия типов данных и методов их кластеризации и для хранения параметров кластеризации используется XML-файл со следующей структурой: <Список методов> <название метода> <тип сопоставленных данных> <Список параметров> <Название параметра> <Значение> </Список параметров> </Список методов> 2.3. Математическое обоснование Как было описано в анализе предметной области, для выявления точечных аномалий используются различные методы, однако кластеризация наиболее удобна из них в реализации и обработке получаемых результатов. Таким образом, если исходить, что в программе для обнаружения аномалий будут использоваться методы кластеризации, необходимо определиться с моделью определения аномалии относительно заданных методов. Исходя из определения аномалии – данные, отличающиеся от общей выборки. Тогда, приходим к выводу, что в нашем случае, аномалия - это данные, не попавшие ни в один из кластеров. Однако, возможна ситуация, когда аномалии сами определяются в группы. Тогда можно предположить, что кластер, содержащий аномалии малочисленней и разрежен, относительно остальных разбиений. Тогда, в общем случае, алгоритм определения аномалий в общем виде будет выглядеть следующим образом: 1) Разбиение выборки на кластеры. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 32 2) Поиск одиночных значений. 3) Поиск малочисленных кластеров. 4) Передача малочисленных кластеров на повторный анализ. Повторный анализ может быть проведен как с помощью данного метода, так и с применением других. Определимся с используемыми методами. Не все алгоритмы подходят для всех типов данных. Однако универсальным считается алгоритм k-средних. Метод k-средних – это метод кластерного анализа, цель которого является разделение m наблюдений (из пространства Rn) на k кластеров, при этом каждое наблюдение относится к тому кластеру, к центру (центроиду) которого оно ближе всего. В качестве меры близости используется Евклидово расстояние. (1) Метод k-средних разделяет m наблюдений на k групп (или кластеров) (k ≤ , чтобы минимизировать суммарное квадратичное отклонение m) точек кластеров от центроидов этих кластеров: (2) , где - центроид для кластера . Итак, если мера близости до центроида определена, то разбиение объектов на кластеры сводится к определению центроидов этих кластеров. Число кластеров k задается исследователем заранее. Рассмотрим первоначальный набор k средних (центроидов) рах в класте- . На первом этапе центроиды кластеров выбираются случайно или по определенному правилу (например, выбрать центроиды, максимизирующие начальные расстояния между кластерами). Относим наблюдения к тем кластерам, чье среднее (центроид) к ним ближе всего. Каждое наблюдение принадлежит только к одному кластеру, даже если его можно отнести к двум и более кластерам. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 33 Затем центроид каждого i-го кластера перевычисляется по следующему правилу: (3) Таким образом, алгоритм k-средних заключается в перевычислении на каждом шаге центроида для каждого кластера, полученного на предыдущем шаге. Алгоритм останавливается, когда значения не меняются: . [17] Алгоритм нечеткой кластеризации называют FCM-алгоритмом. Целью FCMалгоритма кластеризации является автоматическая классификация множества объектов, которые задаются векторами признаков в пространстве признаков. Другими словами, такой алгоритм определяет кластеры и соответственно классифицирует объекты. Кластеры представляются нечеткими множествами, и, кроме того, границы между кластерами также являются нечеткими. [9] FCM-алгоритм кластеризации предполагает, что объекты принадлежат всем кластерам с определенной функцией принадлежности. Степень принадлежности определяется расстоянием от объекта до соответствующих кластерных центров. Данный алгоритм итерационно вычисляет центры кластеров и новые степени принадлежности объектов. Для заданного множества К входных векторов хk и N выделяемых кластеров сj предполагается, что любой хк принадлежит любому сj с принадлежностью µjk интервалу [0,1], где j – номер кластера, а k – номер входного вектора. Принимаются во внимание следующие условия нормирования для µjk: (4) Цель алгоритма – минимизация суммы всех взвешенных расстояний , : (5) где q – фиксированный параметр, задаваемый перед итерациями. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 34 Для достижения вышеуказанной цели необходимо решить следующую систему уравнений: (6) Совместно с условиями нормирования µjk данная система дифференциальных уравнений имеет следующее решение: (7) (взвешенный центр гравитации) и (8) Алгоритм нечеткой кластеризации выполняется по шагам. Шаг 1. Инициализация. Выбираются следующие параметры: необходимое количество кластеров N, 2 < N < К, мера расстояний, как Евклидово расстояние, фиксированный параметр q (обычно 1,5), начальная (на нулевой итерации) матрица принадлежности объектов хk с учетом заданных начальных центров кластеров сj. Шаг 2. Регулирование позиций cj(t) центров кластеров. На t-м итерационном шаге при известной матрице µjk(t) вычисляется cj(t) в соответствии с вышеприведенным решением системы дифференциальных уравнений. Шаг 3. Корректировка значений принадлежности µjk. Учитывая известные cj(t), вычисляются µjk(t), если xk ≠ cj, в противном случае: (9) Шаг 4. Остановка алгоритма. Алгоритм нечеткой кластеризации останавливается при выполнении следующего условия: Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 35 (10) где – матричная норма (например, Евклидова норма); ԑ – заранее задава- емый уровень точности. [11] Алгоритм DBSCAN был предложен Мартином Эстер, Гансом-Питером Кригель и коллегами в 1996 году как решение проблемы разбиения (изначально пространственных) данных на кластеры произвольной формы. Большинство алгоритмов, производящих плоское разбиение, создают кластеры по форме близкие к сферическим, так как минимизируют расстояние документов до центра кластера. Авторы DBSCAN экспериментально показали, что их алгоритм способен распознать кластеры различной формы. Идея, положенная в основу алгоритма, заключается в том, что внутри каждого кластера наблюдается типичная плотность точек (объектов), которая заметно выше, чем плотность снаружи кластера, а также плотность в областях с шумом ниже плотности любого из кластеров. Ещё точнее, что для каждой точки кластера её соседство заданного радиуса должно содержать не менее некоторого числа точек, это число точек задаётся пороговым значением. Для детального изложения принципиальных особенностей алгоритма необходимо ввести ряд определений — ознакомиться с которыми более подробно можно в учебном пособии [1], где также приведен данный алгоритм в общем виде. [19] Алгоритм CLOPE (Clustering with sLOPE) — неиерархический итеративный метод кластерного анализа, предназначенный для обработки больших наборов категориальных данных. Алгоритм был предложен группой исследователей из Шанхайского университета (Yiling Yang, Xudong Guan, Jinyuan You) в статье "CLOPE: A Fast and Effective Clustering Algorithm for Transactional Data" [29] на конференции SIGKDD (Special Interest Group on Knowledge Discovery and Data Mining) в 2002 году.[12] Алгоритм CLOPE в изначальной формулировке является алгоритмом кластеризации транзакционных данных (под транзакцией понимается некоторый произвольный набор объектов конечной длины). Основной идеей данного метода явля- Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 36 ется использование глобального критерия оптимизации на основе максимизации функции стоимости применительно к задачам кластеризации. Во время выполнения алгоритма в оперативной памяти требуется хранить относительно малое количество информации о каждом кластере и производится минимальное число проходов по набору данных. При использовании метода CLOPE количество кластеров подбирается автоматически и зависит от коэффициента отталкивания — параметра, определяющего уровень сходства транзакций внутри кластера. Коэффициент отталкивания задается пользователем: чем больше данный параметр, тем ниже уровень сходства транзакций и, как следствие, большее количество кластеров будет создано.[12] В начале алгоритма происходит инициализация - по порядку перебираются все транзакции, и для каждой из них происходит вычисление цены ее добавления (это действие описано в разделе Вычислительное ядро алгоритма) в существующие кластеры или же в новый, изначально пустой, кластер. Исходя из вычисленных значений, каждой транзакции назначается кластер (какой-либо из уже существующих или новый) - выбирается кластер (при необходимости создается новый), для которого было получено максимальное значение цены добавления данной транзакции. Таким образом, происходит начальное распределение транзакций по кластерам (инициализация кластеризации). Далее могут быть выполнены "уточняющие" итерации, на каждой из которых производится попытка улучшить существующее распределение. В рамках каждой итерации снова производится перебор всех транзакций, и для каждой из них вычисляется цена удаления транзакции из ее текущего кластера, а также происходят вычисления цены добавления транзакции в другие существующие кластеры или в новый кластер. На основании вычисленных значений, принимается решение о перемещении транзакции в другой кластер (а если это должен быть новый кластер, то и о создании нового кластера) или же о том, что данная транзакция остается в текущем кластере. Как и при инициализации, делается таким образом, чтобы суммарная цена за удаление из текущего кластера и добавление в другой кластер была наибольшей (если для всех перемещений суммарная стоимость отрицательна, то транзакция остается на месте). Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 37 Алгоритм заканчивается, если за итерацию не было произведено ни одного перемещения (это означает, что была получена устойчивая кластеризация, которую больше нельзя улучшить при помощи данного метода). [18] Во время исследований алгоритмов наиболее высокие показатели дала комбинация методов k-means и DBScan для числовых значений. 2.4. Программное обеспечение Программа состоит из следующих компонентов, представленных на рисунке 13. Рисунок 13 - Диаграмма компонентов Диаграмма компонентов [14] во многом повторяет диаграмму классов. За счет того, что программа выполнена с применением технологии WPF, логика и верстка приложения находятся в разных файлах [5]. Дизайн окон расположен в файлах формата .xaml. Так же на диаграмме указаны дополнительные компоненты: a. для работы с файлами формата pdf – itextsharp.dll b. для работы с PostgreSql - . Npgsql.dll c. для работы с алгоритмом к-средних – alglibnet2.dll 2.5. Техническое обеспечение 2.5.1. Общие требования Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 38 Для нормального функционирования программы на компьютере должен быть установлен PostgreSQL 2.5.2. Требования к центральному процессору Необходимо использование операционной системы Windows 7 и выше, процессор Intel Core i3 - совместимый с тактовой частотой от 2100 МГц. Данная цифра учитывает как затраты процессора на работу самого приложения, так и затраты, связанные с работой операционной системы. 2.5.3. Требования к оперативному запоминающему устройству Минимальный объем оперативного запоминающего устройства (ОЗУ) необходимый для работы приложения 8Гб и выше. 2.5.4. Требования к наличию сводного места на жестком диске На диске должно быть свободно 30 МБ памяти для установки программы. 2.5.5 Требования к монитору Для работы с программой требуется цветной монитор с разрешением экрана не менее1024×768 пикселей. 2.6. Обеспечение информационной безопасности В программу заносятся учетные данные подключения к СУБД, содержащие в себе пароль. Для обеспечения безопасности используются встроенные технологии защиты WPF, в том числе защищенное поле PasswordBox, который экранирует символы и обеспечивает работу с элементом управления через защищенный тип данных SecurityString.[25] 2.7. Технологическое обеспечение Технологическое обеспечение продемонстрирована с помощью диаграммы потоков данных (рисунок 14). Диаграмма потоков данных (DFD) – один из основных инструментов структурного анализа и проектирования информационных систем; методология графического структурного анализа, описывающая внешние по отношению к системе источники и адресаты данных, логические функции, потоки данных и хранилища данных, к которым осуществляется доступ.[26] Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 39 Рисунок 14 - DFD-диаграмма 2.8. Контрольный пример В качестве примера приведем анализ небольшой базы данных, воспроизведя последовательность действий, описанную на рисунке 9. Исходные данные продемонстрированы на рисунке 15. В таблице все поля, кроме desk,являются числовыми. Рисунок 15 - Исходные данные При запуске программы пользователь видит главное окно программы (рисунок 16). Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 40 Рисунок 16 - Главное окно программы При выборе пункта «Анализ данных» осуществляется переход к окну подключения к базе данных (рисунок 17). Рисунок 17 - Окно подключения к БД При нажатии на кнопку «Далее», осуществляется переход к окну сопоставлений типов данных и алгоритмов их обработки. Для тех типов, методы к котоЛист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 41 рым не указаны, применяется комбинация алгоритма k-means++ и DBScan. (рисунок 18). Рисунок 18 - Окно сопоставления метода и типа данных При нажатии на кнопку «Настроить» рядом с названием метода откроется окно с настройкой параметров для данного метода. В данном случае, для метода k-means (рисунок 19). Рисунок 19 - Окно настройки параметров выбранного метода Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 42 При нажатии на кнопку «Далее» происходит возврат к окну сопоставления типа данных и метода кластеризации. Откуда уже при нажатии кнопки «Далее» осуществляется переход к окну анализа (рисунок 20). Рисунок 20 - Окно анализа На нем пользователь видит, в какое время, какое действие выполняла программа, а также видит прогресс выполнения задачи. По окончанию, становится доступной кнопка далее и осуществляется переход к окну отображения результатов (рисунок 21). Окно результата представлено таблицей, в которой отображена информация о названии таблицы, названии столбца и номере строки, в которых были найдены дефектные данные, а так же само дефектное значение. Нажатие на кнопку «Обзор» позволяет выбрать место сохранения отчета. При нажатии на кнопку «Сохранить» происходит его генерация, сохранение и открытие файла (рисунок 22). Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 43 Рисунок 21 - Окно результата Рисунок 22 - Результат сохранения отчета о сканировании Так как на вход могут поступать абсолютно любые данные, то мы не можем разработать точную методику оценки эффективности разработанных методов безЛист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 44 участия эксперта. Таким образом, точность выполнения программы оценивается экспертом. И в данном конкретном примере были корректно определены все аномалии, однако, так же одна запись была определена неправильно, соответственно точность поиска составляет 0,98. Можно с уверенностью сказать, что программа отработала корректно. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 45 3. ОЦЕНКА ЭФФЕКТИВНОСТИ ПРОЕКТА 3.1. Анализ затрат на ресурсное обеспечение (оценка совокупной стоимости владения) Для оценки экономической эффективности был использован метод объектных указателей. [6] Концептуальная оценка затрат проекта: Количество экранов: 5 (простые) Количество отчетов: 1 (простой) Количество модулей: 5 Тр = NOP/PROD = 57 ∙ (100-%REUSE)/100/13 = 2,3 чел.-мес, где NOP – количество новых объектных указателей, PROD - производительность разработки. Предварительная оценка стоимости проекта: Оплата труда: OТР= 2,3 (чел.-мес)*25 000 (руб-мес)= 57500 руб Фонд заработной платы: ФЗП = 57500*1,2 = 69000 руб Отчисления во внебюджетные фонды: ОВНФ= ФЗП*0,302 = 20838 руб Накладные расходы: НР= ФЗП*0,6=41400 руб Предварительная стоимость разработки: СРАЗР= ФЗП+ ОВНФ+ НР= 131238 руб С учетом резерва в 10%: 144361,8 руб Результаты расчета затрат на разработку программного продукта представлены в таблице 2. Таблица 2 - Расчет затрат на разработку программного продукта Наименование Значение (руб) КРПР 149043,46 СПЗ 24016 Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 46 Продолжение таблицы 2 З`ФОТР 55236,8 ЗФОТР 66284,16 ЗОВФ 20017,8 ЗЭВМ 14421 ЗСПП 0 ЗХОН 8550 РН 39770,5 Затраты на разработку программного продукта рассчитываются по следующей формуле: КРПР=ЗФОТР+ЗОВФ+ЗЭВМ+ЗСПП+ЗХОН+РН, (11) где ЗФОТР – общий фонд оплаты труда разработчиков ПП; ЗОВФ – начисления на заработную плату разработчиков ПП во внебюджетные фонды; ЗЭВМ – затраты, связанные с эксплуатацией техники; ЗСПП – затраты на специальные программные продукты, необходимые для разработки ПП; ЗХОН – затраты на хозяйственно-операционные нужды (бумага, литература, носители информации и т.п.); РН – накладные расходы (РН = 60% от ЗФОТР). При разработке программного продукта общее время разработки ТР составило 2,3 чел-мес. Соответственно, машинное время также составляет 2,3 месяца. Средняя месячная заработная плата разработчиков СЗП СПЗ=∑(ОРj*dРПРj) = 24016*1 = 24016 руб. где ОРj – оклад разработчика =24016 руб; dРПРj – доля разработчика в общем времени работы над проектом Основная заработная плата разработчику: Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 47 З`ФОТР=СПЗ*ТР=24016 * 2,3 = 55236,8 руб, где Тр – трудозатраты проекта в месяцах. Фонд оплаты труда за время работы над программным продуктом с учетом дополнительной заработной платы ЗФОТР=З`ФОТР(1+kД)=55236,8*1,2 = 66284,16 руб., где kД – коэффициент дополнительной зарплаты, kД = 0,2 Сумма начислений на заработную плату во внебюджетные фонды составляет: ЗОВФ = ЗФОТР ∙ kОВФ =66284,16 * 0,302 = 20017,8 руб. где kОВФ – отчисления во внебюджетные фонды, kОВФ = 0,302 Затраты, связанные с использованием вычислительной и оргтехники: ЗЭВМ=ТМРПР*kг*n*См-ч= 404,8*0,95*1*37,5=14421, где kГ – коэффициент готовности ЭВМ, где kГ = 0,95, n – количество единиц техники, равно 1; См-ч – себестоимость машино-часа, 37,5 руб; ТМРПР – машинное время работы над программным продуктом, равно 2,3 мес. = 2,3*22*8 = 404,8 час. Специальные программные продукты, необходимые для разработки ПП закупать не предполагается, следовательно, ЗСПП = 0. Затраты на хозяйственно-организационные нужды ЗХОН=∑ЦТ*КТ= 3000*2+1*2000+3,5*100+40*5 = 8550 руб. где Цτ – цена τ-го товара, руб.; Кτ – количество τ-го товара. Затраты на хозяйственно-организационные нужды представлены в таблице 3. Таблица 3 - Расчет затрат на организационные нужды Наименование Цена за единицу (руб.) Кол-во (шт.) Всего (руб.) Картридж 3000 2 6000 Бумага 1 2000 2000 Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 48 Продолжение таблицы 3 Ручка шариковая 3,5 100 350 Блокнот 40 5 200 Итого 8550 Накладные расходы: РН = ЗФОЗП*kНР=66284,16 * 0,6 = 39770,5 руб, где kНР - коэффициент накладных расходов, kНР = 0,6 Общие затраты на разработку программного продукта составят: КРПР = 66284,16 + 20017,8 + 14421 + 0 + 8550 + 39770,5 = 149043,46 руб. Таким образом, затраты на разработку программного продукта составили КРПР = 149043,46 руб. 3.2. Тестирование ПО 3.2.1. Установочное тестирование Тест №1. Задача: проверка работы программы без XML-файлов с информацией об алгоритмах и их параметрах. Входные данные: отсутствуют. Ожидаемый результат: программа корректно запустятся. Необходимые файлы сгенерируются при запуске программы. Фактический результат: соответствует ожидаемому. Тест №2 Задача: проверка работы программы при отсутствии СУБД PostgreSQL Входные данные: информация для подключения к СУБД (сервер, порт, имя пользователя, пароль, название базы данных). Ожидаемый результат: вывод сообщения об ошибке во время подключения к БД. Фактический результат: соответствует ожидаемому. 3.2.2. Бета-тестирование Тест №1 Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 49 Задача: проверка корректности работы программы Входные данные: информация из таблиц подключенной БД Ожидаемый результат: вывод на окно результатов, на котором отображены выявленные аномалии. Фактический результат: соответствует ожидаемому. Тест №2 Задача: проверка корректности изменений сопоставления типа данных и метода. Входные данные: файл с настройкой. Ожидаемый результат: корректное изменение данных. Фактический результат: соответствует ожидаемому. Тест №3 Задача: проверка корректности сохранения изменения параметров методов. Входные данные: файл с настройкой. Ожидаемый результат: корректное сохранение данных. Фактический результат: соответствует ожидаемому. Тест №4 Задача: проверка корректности сохранения отчета о результатах выявления аномалий. Входные данные: результат анализа БД Ожидаемый результат: корректное сохранение отчета в формате .pdf. Фактический результат: соответствует ожидаемому. Тест №5 Задача: проверка работы программы при условии, что для подключения были введены некорректные данные Ожидаемый результат: сообщение об ошибке. Фактический результат: соответствует ожидаемому. Тест №6 Задача: проверка работы программы при вводе некорректных данных при изменении данных о сопоставлении методов и типов данных. Входные данные: информация о сопоставлении. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 50 Ожидаемый результат: сообщение об ошибке. Фактический результат: соответствует ожидаемому. Тест №7 Задача: проверка работы программы при вводе некорректных данных при изменении значений параметров методов Входные данные: информация о методе. Ожидаемый результат: сообщение об ошибке. Фактический результат: соответствует ожидаемому. Тест №8 Задача: поверка работы программы при вводе некорректного значения в поле пути для сохранения отчета о результатах проверки. Входные данные: результаты проверки БД. Ожидаемый результат: сообщение об ошибке. Фактический результат: соответствует ожидаемому. 3.2.3. Интеграционное тестирование Задача: проверка корректности взаимодействия между компонентами программы. В результате тестирования ошибки не были обнаружены. 3.2.4. Тестирование Usability Задача: проверка удобства пользования программой, корректности работы всех компонентов В результате проверки интерфейс был признан удобным для пользования, благодаря пояснениям на самих окнах программы. Все доступные функции работают корректно. 3.2.5. Эксперименты с системой Оценка эффективности работы методов проводится с помощью экспертной оценки. Точность вычисляется как разница отношения количества обнаруженных верно аномалий и аномалий, находящихся в базе данных и количества, неверно обнаруженных аномалий к общему количеству исследованных данных. Эксперимент 1. Запуск программы на большом объеме данных Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 51 Задача: проверка обработки таблицы БД, содержащей 10 000 строк данных. Входные данные: тестовая таблица, содержащая 20 полей и 10 000 строк кода. Результат: данные обработаны за 2,1 часа. При ручном осмотре таблицы было затрачено 2,7 часа. Точность составляет 0,83. Эксперимент 2. Запуск для всех типов данных метода k-means Задача: проверка обработки данных методом k-means. Входные данные: тестовая таблица из 100 строк, содержавшая числовые и текстовые типы данных. Результат: для численных методов точность составила 0,83, для текстовых данных – 0,67. Эксперимент 3. Запуск для всех типов данных метода FCM Задача: проверка обработки данных методом FCM. Входные данные: тестовая таблица из 100 строк, содержавшая числовые и текстовые типы данных. Результат: для численных методов точность составила 0,76, для текстовых данных – 0,57. Эксперимент 4. Запуск для всех типов данных алгоритма DBscan Задача: проверка обработки данных методом DBscan Входные данные: тестовая таблица из 100 строк, содержащая числовые и текстовые типы данных. Результат: для численных методов точность составила 0,92, для текстовых данных – 0,77. Эксперимент 5. Запуск для текстовых данных алгоритма CLOPE Задача: проверка обработки данных методом DBscan Входные данные: тестовая таблица из 100 строк, содержащая текстовые типы данных. Результат: точность составила 0,82. Эксперимент 6. Запуск метода k-means для очень больших значений Задача: проверка обработки очень больших данных методом k-means Входные данные: тестовая таблица из 100 строк Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 52 Результат: точность составила 0,77. Эксперимент 7. Запуск метода FCM для очень больших значений Задача: проверка обработки очень больших данных методом FCM Входные данные: тестовая таблица из 100 строк Результат: точность составила 0,64. Эксперимент 8. Запуск метода DBscan для очень больших значений Задача: проверка обработки очень больших данных методом DBscan Входные данные: тестовая таблица из 100 строк Результат: точность составила 0,76. Эксперимент 9. Запуск метода CLOPE для очень больших значений Задача: проверка обработки очень больших данных методом CLOPE Входные данные: тестовая таблица из 100 строк Результат: точность составила 0,7 Эксперимент 10. Запуск метода k-means для очень маленьких значений Задача: проверка обработки очень маленьких значений методом k-means Входные данные: тестовая таблица из 100 строк Результат: точность составила 0,71 Эксперимент 11. Запуск метода FCM для очень маленьких значений Задача: проверка обработки очень маленьких значений методом FCM Входные данные: тестовая таблица из 100 строк Результат: точность составила 0,67 Эксперимент 12. Запуск метода DBscan для очень маленьких значений Задача: проверка обработки очень маленьких значений методом FCM Входные данные: тестовая таблица из 100 строк Результат: точность составила 0,78 Эксперимент 13. Запуск метода CLOPE для очень маленьких значений Задача: проверка обработки очень маленьких значений методом CLOPE Входные данные: тестовая таблица из 100 строк Результат: точность составила 0,51 Выводы: наиболее универсальным можно назвать алгоритм k-means, так как он показывает достаточно стабильный результат с различными типами данных. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 53 Для обработки числовых значений наиболее эффективным является алгоритм DBscan, а строки лучше всего обрабатывается алгоритмом CLOPE. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 54 ЗАКЛЮЧЕНИЕ В результате выполнения выпускной квалификационной работы была разработана автоматизированная система выявления аномалий в данных. В ходе проектирования были построены модели предметной области и разработанной системы. Модель предметной области включает в себя диаграммы бизнес-процессов "Как есть" в нотации IDEF0, диаграмму потоков данных, диаграммы бизнес-процессов "Как должно быть" в нотации IDEF0. Модель системы проектировалась в нотации UML и включает в себя описание функциональных возможностей системы, ее логической и физической структуры, а также схему взаимодействия модулей. Полученный программный продукт отвечает требованиям, а также выполнил все задачи и цель ВКР. Разработанная программа позволяет автоматизировать поиск дефектных данных в базах данных пользователя. В дальнейшем планируется провести расширение возможностей системы. Возможно дальнейшее изучение методов обнаружения аномалий, их сравнительный анализ и поиск взаимосвязи типов данных, содержания данных и применяемых методов для повышения эффективности детектирования аномалий. Также возможно расширение взаимодействия системы, одной из которых будет возможность работать с различными СУБД. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 55 СПИСОК ЛИТЕРАТУРЫ Большакова Е.И. Автоматическая обработка текстов на естественном языке и компьютерная лингвистика: учеб. пособие / Большакова Е.И., Клышинский Э.С., Ландэ Д.В., Носков А.А., Пескова О.В., Ягунова Е.В. — М.: МИЭМ, 2011. — 272 с. Наместников, А. М. Базы данных. Практический курс. В 2 ч. Ч. 1. Объектнореляционные базы данных на примере PostgreSQL 9.5 : учебное пособие / А. М. Наместников, А. А. Филиппов. – Ульяновск : УлГТУ, 2017. – 113 с. Шамшев, Ан. Б. Классические элементы пользовательского интерфейса в Windows Presentation Foundation : учебное пособие/ Ан. Б. Шамшев. – Ульяновск: УлГТУ, 2012. – 130 с. Новиков Ф. А., Иванов Д.Ю. Моделирование на UML. Теория, практика, видеокурс. - СПб: Профессиональная литература, Наука и техника, 2010. -660 с. Шамшев, Ан. Б. Основы проектирования интерфейсов с использованием технологии Windows Presentation Foundation : учебное пособие / Ан. Б. Шамшев. – Ульяновск : УлГТУ, 2012. – 163 с. Шанченко, Н. И. Оценка трудоемкости разработки программного продукта : методические указания / Н. И. Шанченко. – Ульяновск : УлГТУ, 2015. – 40 с. Воронина, В. В. Разработка веб-сервисов для анализа слабоструктурированных информационных ресурсов : учебное пособие / В. В. Воронина. – Ульяновск : УлГТУ, 2016. – 165 с. Шамшев, Ан. Б. Ресурсы и стили элементов управления в приложениях Windows Presentation Foundation : учебное пособие / Ан. Б. Шамшев. – Ульяновск : УлГТУ, 2013. – 158 с. Воронина, В. В. Теория и практика машинного обучения : учебное пособие / В. В. Воронина, А. В. Михеев, Н. Г. Ярушкина, К. В. Святов. – Ульяновск: УлГТУ, 2017. – 290 с. Джефф Сазерленд. Scrum. Революционный метод управления проектами. — Манн, Иванов и Фербер, 2016. — 288 с. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 56 Алгоритмы кластеризации| Нечеткая кластеризация [Электронный ресурс]. – Режим доступа: http://life-prog.ru/view_zam.php?id=89. – Загл.с экрана. Алгоритм CLOPE кластеризации категориальных данных [Электронный ресурс]. – Режим доступа: http://algowiki-project.org/ru/Алгоритм_CLOPE_кластеризации_категориальных_данных. – Загл. с экрана. Диаграмма классов [Электронный ресурс]. Режим - доступа: https://ru.wikipedia.org/wiki/Диаграмма_классов. - Загл. с экрана. Диаграмма компонентов [Электронный ресурс]. - Режим доступа: https://ru.wikipedia.org/wiki/Диаграмма_компонентов. - Загл. с экрана. Диаграмма последовательности [Электронный ресурс]. - Режим доступа: https://ru.wikipedia.org/wiki/Диаграмма_последовательности. - Загл. с экрана. Диаграмма прецедентов [Электронный ресурс]. - Режим доступа: https://ru.wikipedia.org/wiki/Диаграмма_прецедентов. - Загл. с экрана. Кластеризация: метод k-средних [Электронный ресурс]. – Режим доступа: http://statistica.ru/theory/klasterizatsiya-metod-k-srednikh. - Загл. с экрана. Кластеризация категорийных данных: масштабируемый алгоритм CLOPE [Электронный ресурс]. – Режим доступа: https://basegroup.ru/community/articles/clope. – Загл. с экрана. Интересные алгоритмы кластеризациию Часть 2 [Электронный ресурс]. - Режим доступа: https://habr.com/post/322034/ - Загл. с экрана. Нормализация данных в базах данных. Виды аномалий. [Электронный ресурс]. – Режим доступа: http://5fan.ru/wievjob.php?id=27101 – Загл. с экрана. НОУ | ИНТУИТ | Анализ проекта [Электронный ресурс]. - Режим доступа: https://www.intuit.ru/studies/courses/496/352/lecture/8397. - Загл. с экрана. В.П Шкодырев. Обзор методов обнаружения точечных аномалий [Электронный ресурс] - Режим доступа: http://ceur-ws.org/Vol-1864/paper_33.pdf - Загл. с экрана Паттерн MVVM [Электронный ресурс]. – Режим доступа: https://metanit.com/sharp/wpf/22.1.php - Загл. с экрана. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 57 Поиск аномалий [Электронный ресурс]. – Режим доступа: https://alexanderdyakonov.wordpress.com/2017/04/19/поиск-аномалий-anomalydetection/. – Загл. с экрана Стратегия безопасности WPF [Электронный ресурс]. – Режим доступа: https://technet.microsoft.com/ru-ru/library/ms743612(v=vs.100) – Загл. с экрана. DFD [Электронный ресурс]. - Режим доступа: https://ru.wikipedia.org/wiki/ DFD. - Загл. с экрана. IDEF0 [Электронный ресурс]. - Режим доступа: https://ru.wikipedia.org/wiki/ IDEF0. - Загл. с экрана. PostgreSQL: Документация к PostgreSQL 9.6.9: Комапния Postgres Professional [Электронный ресурс]. - Режим доступа: https://postgrespro.ru/docs/postgresql/9.6/index. - Загл. с экрана. Yang, Y., Guan, H., You. J. CLOPE: A fast and Effective Clustering Algorithm for Transactional Data In Proc. of SIGKDD’02, July 23-26, 2002, Edmonton, Alberta, Canada [Электронный ресурс]. – Режим доступа: http://www.inf.ufrgs.br/~alvares/CMP259DCBD/clope.pdf. – Загл. с экрана. Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 58 ПРИЛОЖЕНИЕ А. ЛИСТИНГ ПРОГРАММЫ App.xaml <Application x:Class="ASVA1.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentati on" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ASVA1" StartupUri="View/MainWindow.xaml"> <Application.Resources> <Style TargetType="TextBlock" x:Key="TextBlockStyle"> <Setter Property="TextWrapping" Value="Wrap"/> <Setter Property="TextAlignment" Value="Justify"/> </Style> <Style TargetType="Button" x:Key="ButtonStyle"> <Setter Property="Background" Value="White"/> <Setter Property="BorderBrush" Value="Black"/> <Setter Property="BorderThickness" Value="1"/> </Style> <Style TargetType="DataGrid"> <Setter Property="GridLinesVisibility" Value="None"/> <Setter Property="CanUserAddRows" Value="False"/> <Setter Property="CanUserDeleteRows" Value="False"/> </Style> </Application.Resources> </Application> SettingsWindow.xaml <Window x:Class="ASVA1.View.SettingsWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentati on" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markupcompatibility/2006" xmlns:local="clr-namespace:ASVA1.View" mc:Ignorable="d" Title="Настройка методов" Height="439.849" Width="554.378"> <Window.Resources> <Style x:Key="SettiingsWindowButton" TargetType="{x:Type Button}" BasedOn="{StaticResource ButtonStyle}"> <Setter Property="Width" Value="120"/> <Setter Property="Height" Value="40"/> <Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="Margin" Value="10"/> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="2*"/> <RowDefinition Height="7*"/> <RowDefinition Height="2*"/> </Grid.RowDefinitions> <TextBlock Grid.Row="0"> <Run x:Name="titleWindow" FontWeight="Bold">Шаг 2: Настройка параметров</Run> <LineBreak/> Вы можете настроить методы для каждого типа данных. <LineBreak/> Для продолжение работы нажмите <Run x:Name="buttonName" FontWeight="Bold">"Далее"</Run> </TextBlock> <StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Right"> <Button x:Name="CancelButton" Style="{StaticResource SettiingsWindowButton}" Content="Отмена" Click="CancelButton_Click"/> <Button x:Name="NextButton" Style="{StaticResource SettiingsWindowButton}" Content="Далее" Click="NextButton_Click"/> </StackPanel> <DataGrid x:Name="AlgoritmsDataGrid" Grid.Row="1" GridLinesVisibility="None"> <DataGrid.Columns> <DataGridTemplateColumn CanUserReorder="False" CanUserSort="True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate > <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <Button x:Name="SettingsAlgoritm" Content="Настроить" Click="AlgoritmButton_Click"/> </StackPanel> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </Grid> </Window> using ASVA1.ViewModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace ASVA1.View { /// <summary> /// Логика взаимодействия для SettingsWindows.xaml /// </summary> public partial class SettingsWindow : Window { bool saveWindows; public SettingsWindow(bool saveWindows = false) { InitializeComponent(); this.saveWindows = saveWindows; if (saveWindows) { SettingsWindowVM.InitialisationTextBlock(ref titleWindow, ref buttonName, ref NextButton); } SettingsWindowVM.LoadSettings(); SettingsWindowVM.InitDataGrid(ref AlgoritmsDataGrid); } private void CancelButton_Click(object sender, RoutedEventArgs e) { SettingsWindowVM.ReturnMaimMenu(); this.Close(); } private void AlgoritmButton_Click(object sender, RoutedEventArgs e) { int temp = AlgoritmsDataGrid.SelectedIndex; var t = AlgoritmsDataGrid.Items[temp]; SettingsWindowVM.OpenSettingsAlgoritm(t.ToString()); this.Close(); } Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 59 private void NextButton_Click(object sender, RoutedEventArgs e) { if (!saveWindows) { SettingsWindowVM.OpenAnalys(); this.Close(); } else { SettingsWindowVM.SaveSettings(); SettingsWindowVM.ReturnMaimMenu(); } } } } <Window x:Class="ASVA1.View.SettingsParametrsWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentati on" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markupcompatibility/2006" xmlns:local="clr-namespace:ASVA1.View" mc:Ignorable="d" Title="Настройка параметров" Height="597.744" Width="655.263"> <Window.Resources> <Style TargetType="Button" BasedOn="{StaticResource ButtonStyle}"/> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="1*"/> <RowDefinition Height="7*"/> <RowDefinition Height="2*"/> </Grid.RowDefinitions> <TextBlock Grid.Row="0"> <Run x:Name="headerTitle" FontWeight="Bold">Шаг 3: Настройка параметров</Run> <LineBreak/> Вы можете настроить параметры. Для продолжение работы нажмите <Run x:Name="buttonName" FontWeight="Bold">"Далее"</Run> </TextBlock> <DataGrid Grid.Row ="1" x:Name="SettingsParametrDatagrid" AutoGenerateColumns="True"> </DataGrid> <Button Grid.Row="2" x:Name="SaveButton" Width="120" Height="40" Content="Сохранить" HorizontalAlignment="Right" Margin="0,10,5,19" Click="SaveButton_Click"/> <Button Grid.Row="2" x:Name="CancelButton" Width="120" Height="40" Content="Отмена" HorizontalAlignment="Right" Margin="0,10,150,19" Click="CancelButton_Click"/> </Grid> </Window> using ASVA1.ViewModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace ASVA1.View { /// <summary> /// Логика взаимодействия для SettingsParametrs.xaml /// </summary> public partial class SettingsParametrsWindow : Window { bool saveWindow; public SettingsParametrsWindow(string name, bool temp = false) { InitializeComponent(); saveWindow = temp; SettingsParametrsWindowVM.LoadParametrs(); SettingsParametrsWindowVM.LoadMetodsParametr(name, ref SettingsParametrDatagrid); if (temp) SettingsParametrsWindowVM.InitialisationTextBlock(ref headerTitle, ref buttonName, ref SaveButton); } private void SaveButton_Click(object sender, RoutedEventArgs e) { SettingsParametrsWindowVM.SaveParametrs(); SettingsParametrsWindowVM.OpenSettings(); } private void CancelButton_Click(object sender, RoutedEventArgs e) { SettingsParametrsWindowVM.OpenSettings(); } } } <Window x:Class="ASVA1.View.ResultWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentati on" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markupcompatibility/2006" xmlns:local="clr-namespace:ASVA1.View" mc:Ignorable="d" Title="Результат" Height="670.939" Width="692.481"> <Window.Resources> <Style x:Key="ResultWindowButton" TargetType="{x:Type Button}" BasedOn="{StaticResource ButtonStyle}"> <Setter Property="Width" Value="120"/> <Setter Property="Height" Value="40"/> <Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="Margin" Value="10"/> </Style> <Style x:Key="ResultWindowTextBoxStyle" TargetType="TextBox"> <Setter Property="Margin" Value="0,0,0,5"/> <Setter Property="Height" Value="30"/> <Setter Property="VerticalContentAlignment" Value="Center"/> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="2*"/> <RowDefinition Height="7*"/> <RowDefinition Height="Auto"/> <RowDefinition Height="2*"/> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Grid.ColumnSpan="2" Margin="10"> <Run FontWeight="Bold">Результат анализа</Run> <LineBreak/> Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 60 Результат анализа. Для сохранения отчета в формате <Run FontWeight="Bold">.pdf</Run> введите путь до места сохранения и <LineBreak/>нажмите кнопку <Run FontWeight="Bold">"Сохранить"</Run> </TextBlock> <DataGrid x:Name="ResultDataGrid" Grid.Row="1"/> <StackPanel Orientation="Vertical" Grid.Row="2" > <Label Content="Введите путь до места сохранения отчета"/> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> <TextBox x:Name="reportPath" Style="{StaticResource ResultWindowTextBoxStyle}" Width="400"/> <Button x:Name="buttonBrowse" Style="{StaticResource ResultWindowButton}" Content="Oбзор" Click="buttonBrowse_Click"/> <Button x:Name="buttonSave" Style="{StaticResource ResultWindowButton}" Content="Сохранить" Click="buttonSave_Click"/> </StackPanel> </StackPanel> <StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right"> <Button x:Name="buttonNext" Style="{StaticResource ResultWindowButton}" Content="Вернуться в меню" Click="buttonNext_Click"/> </StackPanel> </Grid> </Window> using ASVA1.Model; using ASVA1.ViewModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace ASVA1.View { /// <summary> /// Логика взаимодействия для ResultWindow.xaml /// </summary> public partial class ResultWindow : Window { ResultWindowVM res; public ResultWindow() { InitializeComponent(); ResultDataGrid.Items.Clear(); ResultDataGrid.ItemsSource = GlobalData.deffectData.Distinct(); res = new ResultWindowVM(); } private void buttonNext_Click(object sender, RoutedEventArgs e) { ResultWindowVM.RetirnMAinWindows(); this.Close(); } private void buttonSave_Click(object sender, RoutedEventArgs e) { res.SaveReport(reportPath.Text); } private void buttonBrowse_Click(object sender, RoutedEventArgs e) { reportPath.Text = res.OpenSaveDialog(); } } } <Window x:Class="ASVA1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentati on" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markupcompatibility/2006" xmlns:local="clr-namespace:ASVA1" mc:Ignorable="d" Title="Система обнаружения аномалий" Height="350" Width="525"> <Window.Resources> <Style TargetType="Button" BasedOn="{StaticResource ButtonStyle}"> <Setter Property="Margin" Value="50,10,50,40"/> </Style> <Style TargetType="TextBlock" BasedOn="{StaticResource TextBlockStyle}"> <Setter Property="Margin" Value="10"/> </Style> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="4*"/> <ColumnDefinition Width="5*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="*"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TextBlock Grid.Column="0" Grid.Row="0"> Для начала работы нажмите на кнопку <Run FontWeight="Bold">"Анализ базы данных"</Run> и следуйте инструкциям. </TextBlock> <TextBlock Grid.Column="0" Grid.Row="1"> Для настройки методов выявления аномалий нажмите на кнопку <Run FontWeight="Bold">"Настройка"</Run> </TextBlock> <TextBlock Grid.Column="0" Grid.Row="2"> Для завершения работы - нажмите на кнопку <Run FontWeight="Bold">"Завершить работу"</Run> </TextBlock> <Button x:Name="AnalyseWizardButton" Grid.Column="1" Grid.Row="0" Content="Анализ базы данных" Click="AnalyseWizardButton_Click"/> <Button x:Name="SettingsButton" Grid.Column="1" Grid.Row="1" Content="Настройка" Click="SettingsButton_Click"></Button> <Button x:Name="ExitButton" Grid.Column="1" Grid.Row="2" Content="Завершить работу" Click="ExitButton_Click"></Button> </Grid> </Window> using ASVA1.ViewModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 61 using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ASVA1 { /// <summary> /// Логика взаимодействия для MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void AnalyseWizardButton_Click(object sender, RoutedEventArgs e) { MainWindowVM.OpenAnalysWizard(); this.Close(); } private void ExitButton_Click(object sender, RoutedEventArgs e) { MainWindowVM.ExitSystem(); } private void SettingsButton_Click(object sender, RoutedEventArgs e) { MainWindowVM.OpenSettingsWizard(true); } } } <Window x:Class="ASVA1.LoadDBWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentati on" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markupcompatibility/2006" xmlns:local="clr-namespace:ASVA1" mc:Ignorable="d" Title="Загрузка базы данных" Width="400" Height="431.992"> <Window.Resources> <Style x:Key="LoadDBButtonStyle" TargetType="Button" BasedOn="{StaticResource ButtonStyle}"> <Setter Property="Width" Value="120"/> <Setter Property="Height" Value="40"/> <Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="Margin" Value="3, 3, 0,0"/> </Style> <Style TargetType="TextBlock" BasedOn="{StaticResource TextBlockStyle}"> <Setter Property="Margin" Value="1"/> </Style> <Style x:Key="LoadDBTextBoxStyle" TargetType="TextBox"> <Setter Property="Margin" Value="0,0,0,5"/> <Setter Property="Height" Value="30"/> <Setter Property="VerticalContentAlignment" Value="Center"/> </Style> <Style x:Key="LoadDBPasswordtBoxStyle" TargetType="PasswordBox"> <Setter Property="Margin" Value="0,0,0,5"/> <Setter Property="Height" Value="30"/> <Setter Property="VerticalContentAlignment" Value="Center"/> </Style> </Window.Resources> <Grid HorizontalAlignment="Center"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <StackPanel> <TextBlock Grid.Row="0"><Run FontWeight="Bold" Text="Шаг 1: Загрузка базы данных"/><LineBreak/><Run Text="Заполните все поля"/><Run Text=". Затем нажмите кнопку "/><Run FontWeight="Bold" Text="&quot;Далее&quot;"/></TextBlock> <StackPanel Grid.Row="1" Orientation="Vertical"> <Label Content="Сервер:"/> <TextBox x:Name="serverTextBox" Text="localhost" Style="{StaticResource LoadDBTextBoxStyle}" /> <Label Content="Порт:"/> <TextBox x:Name="portTextBox" Text="5432" Style="{StaticResource LoadDBTextBoxStyle}" /> <Label Content="Пользователь:"/> <TextBox x:Name="userTextBox" Text="postgres" Style="{StaticResource LoadDBTextBoxStyle}" /> <Label Content="Пароль:"/> <PasswordBox x:Name="passwordTextBox" Password="123456" Style="{StaticResource LoadDBPasswordtBoxStyle}" /> <Label Content="База данных:"/> <TextBox x:Name="dataBaseTextBox" Text ="testData" Style="{StaticResource LoadDBTextBoxStyle}" /> </StackPanel> <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right"> <Button x:Name="buttonCancel" Style ="{StaticResource LoadDBButtonStyle}" Content ="Отмена" Click="buttonCancel_Click"/> <Button x:Name="buttonNext" Style ="{StaticResource LoadDBButtonStyle}" Content="Далее" Click="buttonNext_Click"/> </StackPanel> </StackPanel> </Grid> </Window> using ASVA1.ViewModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace ASVA1 { /// <summary> /// Логика взаимодействия для LoadDBWindow.xaml /// </summary> public partial class LoadDBWindow : Window { public LoadDBWindow() { InitializeComponent(); } private void buttonNext_Click(object sender, RoutedEventArgs e) Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 62 { if (LoadDBWindowVM.LoadDB(serverTextBox.Text, portTextBox.Text, userTextBox.Text, passwordTextBox.Password, dataBaseTextBox.Text)) { LoadDBWindowVM.OpenSettingsMetods(); this.Close(); } else { MessageBox.Show("Ошибка при подлючении. Проверьте правильность введенных данных и повторите попытку"); } } private void buttonCancel_Click(object sender, RoutedEventArgs e) { LoadDBWindowVM.ReturnMaimMenu(); this.Close(); } } } <Window x:Class="ASVA1.View.AnalysWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentati on" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markupcompatibility/2006" xmlns:local="clr-namespace:ASVA1.View" mc:Ignorable="d" Title="Анализ данных" Height="433.082" Width="549.248"> <Window.Resources> <Style x:Key="AnalysWindowButton" TargetType="{x:Type Button}" BasedOn="{StaticResource ButtonStyle}"> <Setter Property="Width" Value="120"/> <Setter Property="Height" Value="40"/> <Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="Margin" Value="10"/> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="2*"/> <RowDefinition Height="7*"/> <RowDefinition Height="2*"/> </Grid.RowDefinitions> <TextBlock Grid.Row="0"> <Run FontWeight="Bold">Шаг 4: Анализ базы данных</Run> <LineBreak/> Анализ базы данных. После завершения анализа для продолжения работы нажмите <Run FontWeight="Bold">"Далее"</Run> </TextBlock> <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right"> <Button Grid.Row="2" x:Name="buttonCancel" Style="{StaticResource AnalysWindowButton}" Content="Отмена" Click="buttonCancel_Click"/> <Button Grid.Row="2" x:Name="butonNext" Style="{StaticResource AnalysWindowButton}" Content ="Далее" Click="butonNext_Click"/> </StackPanel> <StackPanel Grid.Row="1"> <ProgressBar x:Name="progressAnalys" Height="20"/> <ScrollViewer VerticalAlignment="Stretch" VerticalScrollBarVisibility="Visible" MaxHeight="235"> <ListBox x:Name="liatBoxAnalysLog" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> </ListBox> </ScrollViewer> </StackPanel> </Grid> </Window> using ASVA1.ViewModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace ASVA1.View { /// <summary> /// Логика взаимодействия для AnalysWindow.xaml /// </summary> public partial class AnalysWindow : Window { AnalysWindowsVM analys; public AnalysWindow() { InitializeComponent(); analys = new AnalysWindowsVM(); analys.AnalysData(ref liatBoxAnalysLog, ref progressAnalys); } private void buttonCancel_Click(object sender, RoutedEventArgs e) { AnalysWindowsVM.RetirnMAinWindows(); this.Close(); } private void butonNext_Click(object sender, RoutedEventArgs e) { AnalysWindowsVM.OpenResultWindows(); this.Close(); } } } using ASVA1.Model; using ASVA1.View; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Controls; namespace ASVA1.ViewModel { public class AnalysWindowsVM { public ListBox logListBox; public ProgressBar prog; Task runAnalys; /// <summary> /// Запускает поток для анализа таблиц /// </summary> /// <returns></returns> public bool AnalysData(ref ListBox list, ref ProgressBar pB) { logListBox = list; prog = pB; Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 63 /// <param name="port">Номер порта</param> /// <param name="user">Имя пользователя</param> /// <param name="password">Пароль</param> /// <param name="database">Название базы данных</param> /// <returns></returns> public static bool LoadDB(string server, string port, string user, string password, string database) { return GlobalData.DB.ConnectionDB(server, port, user, password, database); } } } using ASVA1.View; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; prog.Maximum = GlobalData.dataOfTable.Count(); Analys analus = new Analys(this); runAnalys = Task.Factory.StartNew(() => { analus.RunAlg(); }); return true; } /// <summary> /// Переход к окну результата /// </summary> internal static void OpenResultWindows() { ResultWindow res = new ResultWindow(); res.Show(); } /// <summary> /// Возврат в главное меню /// </summary> internal static void RetirnMAinWindows() { MainWindow res = new MainWindow(); res.Show(); } /// <summary> /// Заполнение лога с анализом /// </summary> /// <param name="text">Текст лога</param> public void SetInfo(string text) { logListBox.Items.Add(DateTime.Now.ToShortTimeString()+" -> "+ text); } /// <summary> /// Отображение текущего прогресса /// </summary> public void SetProgress() { prog.Value++; } } } using ASVA1.Model; using ASVA1.View; using Microsoft.Win32; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ASVA1.ViewModel { public class LoadDBWindowVM { /// <summary> /// Переход к настройке методов /// </summary> public static void OpenSettingsMetods() { SettingsWindow s = new SettingsWindow(); s.Show(); } /// <summary> /// Возврат к главному окну /// </summary> public static void ReturnMaimMenu() { MainWindow s = new MainWindow(); s.Show(); } /// <summary> /// Загрузка базы данных /// </summary> /// <param name="server">Адрес сервера</param> namespace ASVA1.ViewModel { public class MainWindowVM { /// <summary> /// Переход к мастеру анализа БД /// </summary> public static void OpenAnalysWizard() { LoadDBWindow loadDBWindow = new LoadDBWindow(); loadDBWindow.Show(); } /// <summary> /// Переход к настройке методов /// </summary> /// <param name="temp"></param> public static void OpenSettingsWizard(bool temp=false) { SettingsWindow settingsWindows= new SettingsWindow(temp); settingsWindows.Show(); } /// <summary> /// Выход их системы /// </summary> public static void ExitSystem() { Environment.Exit(0); } } } using ASVA1.SaveReport; using Microsoft.Win32; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ASVA1.ViewModel { public class ResultWindowVM { /// <summary> /// Возврат в главное меню /// </summary> public static void RetirnMAinWindows() { MainWindow res = new MainWindow(); res.Show(); } public string OpenSaveDialog() Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 64 { SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "Файлы pdf|*.pdf"; if (saveFileDialog.ShowDialog() == true) { return saveFileDialog.FileName; } return string.Empty; } public void SaveReport(string path) { GenerateReport generate = new GenerateReport(); generate.ReportSave(path); } } using ASVA1.Model; using ASVA1.View; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Documents; namespace ASVA1.ViewModel { class SettingsParametrsWindowVM { public static void OpenSettings() { SettingsWindow s = new SettingsWindow(); s.Show(); } public static void InitialisationTextBlock(ref Run headerWindow, ref Run buttonName, ref Button buttonContext) { headerWindow.Text = "Настройка параметров"; buttonName.Text = "Cохранить"; buttonContext.Content = "Сохранить"; } namespace ASVA1.ViewModel { /// <summary> /// Инициализация DataGrid /// </summary> /// <param name="d">DataGrid</param> public static void InitDataGrid(ref DataGrid d) { d.ItemsSource = GlobalData.algDataType; } /// <summary> /// Переход к окну настроек параметров конкретного метода } internal static void SaveParametrs() { LoadDB DB = new LoadDB(); DB.SaveSettings(); } internal static void LoadParametrs() { LoadDB DB = new LoadDB(); DB.LoadSettings(); } public static void LoadMetodsParametr(string name, ref DataGrid data) { data.ItemsSource = GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals(name)).parametrs; } } } using ASVA1.Model; using ASVA1.View; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; public class SettingsWindowVM { /// </summary> /// <param name="metodName">Название метода</param> public static void OpenSettingsAlgoritm(string metodName) { SettingsParametrsWindow s = new SettingsParametrsWindow(metodName); s.Show(); } /// <summary> /// Переход к окну анализа /// </summary> public static void OpenAnalys() { AnalysWindow s = new AnalysWindow(); s.Show(); } /// <summary> /// ВОзврат в главное меню /// </summary> public static void ReturnMaimMenu() { AnalysWindow s = new AnalysWindow(); s.Show(); } /// <summary> /// Инициализация описания для разных методов входа в систему /// </summary> /// <param name="headerWindow">Заголовок окна</param> /// <param name="buttonName">Название кнопки в описании окна</param> /// <param name="buttonContext">Название кнопки</param> public static void InitialisationTextBlock(ref Run headerWindow, ref Run buttonName, ref Button buttonContext) { headerWindow.Text = "Настройка методов"; buttonName.Text = "Cохранить"; buttonContext.Content = "Сохранить"; } /// <summary> /// ЗАгрузка списка доступных методов /// </summary> public static void LoadSettings() { LoadDB DB = new LoadDB(); DB.LoadAlgOfTable(); } /// <summary> /// Сохранение списка доступных методов /// </summary> public static void SaveSettings() { LoadDB DB = new LoadDB(); DB.SaveAlgOfTAble(); } } } using ASVA1.Model; using iTextSharp.text; using iTextSharp.text.pdf; Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 65 using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; document.Close(); writer.Close(); } Process.Start(filePath); namespace ASVA1.SaveReport { public class GenerateReport { public void ReportSave(string filePath) { if (string.IsNullOrEmpty(filePath)) { MessageBox.Show("Путь не указан"); return; } try { var document = new iTextSharp.text.Document(); using (var writer = PdfWriter.GetInstance(document, new FileStream(filePath, FileMode.OpenOrCreate))) { document.Open(); BaseFont baseFont = BaseFont.CreateFont(@"C:\Windows\Fonts\arial.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); var helvetica = new iTextSharp.text.Font(baseFont, iTextSharp.text.Font.DEFAULTSIZE, iTextSharp.text.Font.NORMAL); var helveticaBase = helvetica.GetCalculatedBaseFont(false); writer.DirectContent.BeginText(); PdfPTable table = new PdfPTable(4); var cell = new PdfPCell(new Phrase(new Phrase("Номер строки", helvetica))); cell.BackgroundColor = iTextSharp.text.BaseColor.LIGHT_GRAY; table.AddCell(cell); cell = new PdfPCell(new Phrase(new Phrase("Название таблицы", helvetica))); cell.BackgroundColor = iTextSharp.text.BaseColor.LIGHT_GRAY; table.AddCell(cell); cell = new PdfPCell(new Phrase(new Phrase("Назименование столбца", helvetica))); cell.BackgroundColor = iTextSharp.text.BaseColor.LIGHT_GRAY; table.AddCell(cell); cell = new PdfPCell(new Phrase(new Phrase("Аномальное значение", helvetica))); cell.BackgroundColor = iTextSharp.text.BaseColor.LIGHT_GRAY; table.AddCell(cell); foreach (var t in GlobalData.deffectData.Distinct()) { cell = new PdfPCell(new Phrase(new Phrase(t.RowIndex.ToString(), helvetica))); table.AddCell(cell); cell = new PdfPCell(new Phrase(new Phrase(t.TableName, helvetica))); table.AddCell(cell); cell = new PdfPCell(new Phrase(new Phrase(t.ColumnName, helvetica))); table.AddCell(cell); cell = new PdfPCell(new Phrase(new Phrase(t.Value, helvetica))); table.AddCell(cell); } document.Add(table); writer.DirectContent.EndText(); } catch { MessageBox.Show("Ошибка при создании файла"); } } } } using ASVA1.Algoritms; using ASVA1.Model.AlgoritmSetting; using Npgsql; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; namespace ASVA1.Model { public class LoadDB { /// <summary> /// Подключение к базе /// </summary> public NpgsqlConnection con; /// <summary> /// Инициация подключения. Загрузка необходимых параметров /// </summary> /// <param name="server">Название сервера</param> /// <param name="port">Номер порта</param> /// <param name="user">Имя пользователя</param> /// <param name="password">Пароль</param> /// <param name="database">Название базы данных</param> /// <returns></returns> public bool ConnectionDB(string server, string port, string user, string password, string database) { string connectionString = $"Server={server};Port={port};User Id={user};Password={password};Database={database};"; con = new NpgsqlConnection(connectionString); try { LoadDataBase(); LoadAlgOfTable(); LoadSettings(); return true; } catch { if (con!=null) con.Close(); return false; } } /// <summary> /// Загрузка информации о базе данных /// </summary> public void LoadDataBase() { NpgsqlCommand com = new NpgsqlCommand("Select table_name, column_name, data_type from information_schema.columns where table_schema = 'public'", con); con.Open(); var result = com.ExecuteReader(); string temp = string.Empty; Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 66 while (result.Read()) { temp = result.GetString(0); if (GlobalData.dataOfTable.FindIndex(i => i.tableName.Equals(temp)) == -1) { GlobalData.dataOfTable.Add(new DataOfTable(temp)); } GlobalData.dataOfTable.Find(i => i.tableName.Equals(temp)).AddShemaInfo(result.GetString(1), result.GetString(2)); } con.Close(); } /// <summary> /// Возвращает количество строк в таблице /// </summary> /// <param name="tableName">Название таблицы</param> /// <returns>Количесво строк в таблице</returns> public int GetRowCount(string tableName) { int countRow = 0; NpgsqlCommand com = new NpgsqlCommand("Select count(*) from \"" + tableName + "\"", con); con.Open(); var result = com.ExecuteReader(); result.Read(); countRow = result.GetInt32(0); con.Close(); return countRow; } /// <summary> /// Возвращает количество уникальных записей в столбце /// </summary> /// <param name="tableName">Название таблицы</param> /// <param name="columnsName">НАзвание столбца</param> /// <returns>Количество уникальных записей в столбце</returns> public int GetDistRowCount(string tableName, string columnsName) { int distRow = 0; NpgsqlCommand com = new NpgsqlCommand("Select count(distinct \"" + columnsName + "\") from \"" + tableName + "\"", con); con.Open(); var result = com.ExecuteReader(); result.Read(); distRow = result.GetInt32(0); con.Close(); return distRow; } /// <summary> /// Выгружает данные из ислледуемого стобца /// </summary> /// <param name="tableName">Название таблицы</param> /// <param name="columnName">Название столбца</param> /// <param name="rowcount">Количество строк в таблице</param> /// <returns>Массив данных из столбца</returns> public object[] LoadColumn(string tableName, string columnName, int rowcount) { NpgsqlCommand com = new NpgsqlCommand("Select \"" + columnName + "\" from \"" + tableName + "\"", con); con.Open(); var result = com.ExecuteReader(); int index = 0; object[] array = new object[rowcount]; while (result.Read()) { array[index] = result.GetValue(0); index++; } con.Close(); return array; } /// <summary> /// Загружает значения параметров методов /// </summary> public void LoadSettings() { //GlobalData.infoAlg.Add(new InfoOfAlgoritms("kmeans")); //GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("k-means")).AddParametrs("Kklast", 0.1f); //GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("k-means")).AddParametrs("repeat", 1); //GlobalData.infoAlg.Add(new InfoOfAlgoritms("FCM")); //GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("FCM")).AddParametrs("e", 0.0001f); //GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("FCM")).AddParametrs("repeat", 1000); //GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("FCM")).AddParametrs("Kklast", 0.1f); //GlobalData.infoAlg.Add(new InfoOfAlgoritms("DBScan")); //GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("DBScan")).AddParametrs("e", 0.1f); //GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("DBScan")).AddParametrs("minPts", 1); //GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("DBScan")).AddParametrs("Kklast", 0.1f); //SaveSettings(); GlobalData.infoAlg.Clear(); XmlSerializer formatter = new XmlSerializer(typeof(List<InfoOfAlgoritms>)); using (FileStream fs = new FileStream("settings.xml", FileMode.OpenOrCreate)) { GlobalData.infoAlg = (List<InfoOfAlgoritms>)formatter.Deserialize(fs); } } /// <summary> /// Загружает список доступных методов /// </summary> public void LoadAlgOfTable() { //GlobalData.algDataType.Add(new AlgoritmSetting.AlgoritmsOfDataType("k-means", "все типы данных")); //GlobalData.algDataType.Add(new AlgoritmSetting.AlgoritmsOfDataType("FCM", "все типы данных")); //GlobalData.algDataType.Add(new AlgoritmSetting.AlgoritmsOfDataType("DBScan", "все типы данных")); //SaveAlgOfTAble(); GlobalData.algDataType.Clear(); XmlSerializer formatter = new XmlSerializer(typeof(List<AlgoritmsOfDataType>)); using (FileStream fs = new FileStream("metods.xml", FileMode.OpenOrCreate)) { GlobalData.algDataType = (List<AlgoritmsOfDataType>)formatter.Deserialize(fs); } } /// <summary> /// Сохраняет список параметров методов /// </summary> public void SaveSettings() { Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 67 // передаем в конструктор тип класса XmlSerializer formatter = new XmlSerializer(typeof(List<InfoOfAlgoritms>)); // получаем поток, куда будем записывать сериализованный объект using (FileStream fs = new FileStream("settings.xml", FileMode.OpenOrCreate)) { formatter.Serialize(fs, GlobalData.infoAlg); } } /// <summary> /// Сохраняет список доступных методов /// </summary> public void SaveAlgOfTAble() { // передаем в конструктор тип класса XmlSerializer formatter = new XmlSerializer(typeof(List<AlgoritmsOfDataType>)); // получаем поток, куда будем записывать сериализованный объект using (FileStream fs = new FileStream("metods.xml", FileMode.OpenOrCreate)) { formatter.Serialize(fs, GlobalData.algDataType); } } } } using ASVA1.Model.AlgoritmSetting; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ASVA1.Model { public class GlobalData { /// <summary> /// Список дефектных данных /// </summary> public static List<DeffectData> deffectData = new List<DeffectData>(); /// <summary> /// СПисок доступных методов /// </summary> public static List<AlgoritmsOfDataType> algDataType = new List<AlgoritmsOfDataType>(); /// <summary> /// Список параметров методов /// </summary> public static List<InfoOfAlgoritms> infoAlg = new List<InfoOfAlgoritms>(); /// <summary> /// ИНформация о таблицах в базе данных /// </summary> public static List<DataOfTable> dataOfTable = new List<DataOfTable>(); public static LoadDB DB = new LoadDB(); } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ASVA1.Model { /// <summary> /// Аномалии /// </summary> public class DeffectData { /// <summary> /// Номер строки с ошибкой /// </summary> int rowIndex; public int RowIndex { get { return rowIndex; } set { rowIndex = value; } } /// <summary> /// Название таблицы /// </summary> string tableName; public string TableName { get { return tableName; } set { tableName = value; } } /// <summary> /// Название столбца /// </summary> string columnName; public string ColumnName { get { return columnName; } set { columnName = value; } } /// <summary> /// Значение /// </summary> string value; public string Value { get { return value; } set { this.value = value; } } public DeffectData() { } public DeffectData(int rowIndex, string columnName, string tableName, string value ) { this.rowIndex = rowIndex; this.tableName = tableName; this.columnName = columnName; this.value = value; } } /// <summary> /// Нормальные данные /// </summary> public class Data<T> { /// <summary> /// Номер строки с ошибкой /// </summary> int rowIndex; public int RowIndex { get { return rowIndex; } set { rowIndex = value; } } /// <summary> /// Название таблицы /// </summary> string tableName; public string TableName { get { return tableName; } set { tableName = value; } } /// <summary> /// Название столбца /// </summary> string columnName; public string ColumnName { get { return columnName; } set { columnName = value; } } /// <summary> /// Значение /// </summary> T value; Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 68 public T Value { get { return value; } set { this.value = value; }} } } public Data() { } public Data(int rowIndex, string columnName, string tableName, T value) { this.rowIndex = rowIndex; this.tableName = tableName; this.columnName = columnName; this.value = value; namespace ASVA1.Model { public class Analys { AnalysWindowsVM anVM; LoadDB DB = new LoadDB(); public Analys(AnalysWindowsVM anVM) { this.anVM = anVM; } public void RunAlg() { GlobalData.deffectData.Clear(); foreach (var table in GlobalData.dataOfTable) { } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ASVA1.Model { /// <summary> /// ИНформация о таблицах в БД /// </summary> public class DataOfTable { /// <summary> /// НАзвание таблицы /// </summary> public string tableName; /// <summary> /// Описание схемы /// </summary> public List<ColumnsOfType> infoColumn; public DataOfTable(string tableName) { this.tableName = tableName; infoColumn = new List<ColumnsOfType>(); } public void AddShemaInfo(string columnName, string type) { infoColumn.Add(new ColumnsOfType(columnName, type)); } } /// <summary> /// Нформация о столбцах /// </summary> public class ColumnsOfType { /// <summary> /// Название столбца /// </summary> public string columnsName; /// <summary> /// Тип данных /// </summary> public string dataType; public ColumnsOfType(string columnsName, string dataType) { this.columnsName = columnsName; this.dataType = dataType; } using ASVA1.Algoritms; using ASVA1.Model; using ASVA1.ViewModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; Application.Current.Dispatcher.Invoke((Action)(() => anVM.SetInfo("Анализ таблицы " + table.tableName))); List<Task> task = new List<Task>(); task.Add(Task.Factory.StartNew(() => { //var table = GlobalData.dataOfTable.Find(i => i.tableName.Equals("test")); foreach (var column in table.infoColumn) { Application.Current.Dispatcher.Invoke((Action)(() => anVM.SetInfo("Анализ столбца " + column.columnsName))); int rowcount = GlobalData.DB.GetRowCount(table.tableName); int distrowcount = GlobalData.DB.GetDistRowCount(table.tableName, column.columnsName); if (distrowcount < 2) { continue; } var result = GlobalData.DB.LoadColumn(table.tableName, column.columnsName, rowcount); if (column.dataType.Equals("integer") || column.dataType.Equals("real") || column.dataType.Equals("numeric") || column.dataType.Equals("double precision") || column.dataType.Equals("float") || column.dataType.Equals("integer")) { AnalysNum(result, rowcount, table.tableName, column.columnsName); } else { AnalysString(result, rowcount, table.tableName, column.columnsName); } } })); Task.WaitAll(task.ToArray()); Application.Current.Dispatcher.Invoke((Action)(() => anVM.SetProgress())); } Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 69 Application.Current.Dispatcher.Invoke((Action)(() => anVM.SetInfo("Анализ завершен успешно"))); } // double[,] data = new double[rowcount, 1]; //for (int i = 0; i < rowcount; i++) //{ // try // { // if (columnStr == null) // { // columnNum.Add(new Data<double>(i, column.columnsName, table.tableName, Convert.ToDouble(result[i])), ); // } // else // { // columnStr.Add(new Data<string>(i, column.columnsName, table.tableName, Convert.ToString(result[i]))); // } // } // catch // { // GlobalData.deffectData.Add(new DeffectData(i, column.columnsName, table.tableName, Convert.ToString(result[i]))); // rowcount--; // } //} // Application.Current.Dispatcher.Invoke((Action)(() => anVM.SetInfo("Предварительный анализ с использованием kmeans++ "))); // var resultKlaserisation = K_means__.Klasterisation(data, rowcount, 1, (int)(distrowcount * (float)(GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("k-means")).parametrs.Find(i => i.settingsName.Equals("Kklast")).value)) + 1, (int)(GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("kmeans")).parametrs.Find(i => i.settingsName.Equals("repeat")).value)); // if (resultKlaserisation != null) // { // int count = resultKlaserisation.Distinct().Count(); // int[] klastCountItem = new int[count]; // for (int j = 0; j < count; j++) // { // klastCountItem[j] = resultKlaserisation.Count(i => i == j); // } // GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("DBScan")).parametrs.Find(i => i.settingsName.Equals("e")).value = (float) DbScanE(data, rowcount); // DBscan dbScan = new DBscan(); // for (int i = 0; i < rowcount; i++) // { // dbScan.AddFeatureData(data[i, 0], resultKlaserisation[i]); // } // Application.Current.Dispatcher.Invoke((Action)(() => anVM.SetInfo("Анализ с использованием DBScan"))); // var resultData = dbScan.DBScanClusterig((double)GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("DBScan")).parametrs.Find(i => i.settingsName.Equals("e")).value, (int)GlobalData.infoAlg.Find(i => i.nameAlgoritms.Equals("DBScan")).parametrs.Find(i => i.settingsName.Equals("minPts")).value); // foreach (var temp in resultData) // { // if (temp.Count() == 1) // { // GlobalData.deffectData.Add(new DeffectData(-1, column.columnsName, table.tableName, temp[0].X.ToString())); // } // } //} // // Application.Current.Dispatcher.Invoke((Action)(() => anVM.SetInfo("Анализ завершен"))); //} public void AnalysString(object[] result, int rowcount, string tablename, string columnname) { List<Data<string>> columnStr = new List<Data<string>>(); for (int i = 0; i < rowcount; i++) { try { columnStr.Add(new Data<string>(i, columnname, tablename, Convert.ToString(result[i]))); } catch { GlobalData.deffectData.Add(new DeffectData(i, columnname, tablename, Convert.ToString(result[i]))); } } if (columnStr.Count < GlobalData.deffectData.FindAll(item => item.ColumnName.Equals(columnname)).Count) { GlobalData.deffectData.RemoveAll(item => item.ColumnName.Equals(columnname)); } if (columnStr.Count > 0) { object[] res = new object[columnStr.Count]; int index = 0; foreach (var t in columnStr) { res[index] = t.Value.Length; index++; } AnalysNum(res, columnStr.Count, tablename, columnname); var temp = GlobalData.deffectData.FindAll(i=>i.ColumnName.Equals(columnname)); foreach(var item in temp) { item.Value = columnStr.Find(i => i.Value.Length == Convert.ToInt32(item.Value)).Value; } } } public void AnalysNum(object[] result, int rowcount, string tablename, string columnname) { List<Data<double>> columnNum = new List<Data<double>>(); for (int i = 0; i < rowcount; i++) { try { columnNum.Add(new Data<double>(i, columnname, tablename, Convert.ToDouble(result[i]))); } catch { GlobalData.deffectData.Add(new DeffectData(i, columnname, tablename, Convert.ToString(result[i]))); } } if (columnNum.Count< GlobalData.deffectData.FindAll(item=>item.ColumnName.Equals(columnn ame)).Count) { Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 70 GlobalData.deffectData.RemoveAll(item => item.ColumnName.Equals(columnname)); } if (columnNum.Count > 0) { double[,] data = new double[columnNum.Count, 1]; int i = 0; foreach (var temn in columnNum) { data[i, 0] = temn.Value; i++; } Application.Current.Dispatcher.Invoke((Action)(() => anVM.SetInfo("Предварительный анализ с использованием kmeans++ "))); var resultKlaserisation = K_means__.Klasterisation(data, columnNum.Count, 1, (int)(columnNum.Distinct().Count() * (float)(GlobalData.infoAlg.Find(item => item.nameAlgoritms.Equals("k-means")).parametrs.Find(item => item.settingsName.Equals("Kklast")).value)) + 1, (int)(GlobalData.infoAlg.Find(item => item.nameAlgoritms.Equals("k-means")).parametrs.Find(item => item.settingsName.Equals("repeat")).value)); if (resultKlaserisation != null) { int countKlast = resultKlaserisation.Distinct().Count(); int[] klastCountItem = new int[countKlast]; for (int j = 0; j < countKlast; j++) { if (resultKlaserisation.Count(item => item == j)==1) { GlobalData.deffectData.Add(new DeffectData(columnNum.Find(item=>item.Value== data[resultKlaserisation.ToList().FindIndex(it => it == j), 0]).RowIndex, columnname, tablename, data[resultKlaserisation.ToList().FindIndex(item => item == j),0].ToString())); continue; } Application.Current.Dispatcher.Invoke((Action)(() => anVM.SetInfo("Анализ с использованием DBScan"))); DBscan dbScan = new DBscan(); var resultData = dbScan.DBScanClusterig((double)GlobalData.infoAlg.Find(item= > item.nameAlgoritms.Equals("DBScan")).parametrs.Find(item=> item.settingsName.Equals("e")).value, (int)GlobalData.infoAlg.Find(item=> item.nameAlgoritms.Equals("DBScan")).parametrs.Find(item=> item.settingsName.Equals("minPts")).value); for (int t = 0; t < columnNum.Count; t++) { if (resultKlaserisation[t] == j) { dbScan.AddFeatureData(data[t, 0], resultKlaserisation[t]); } } double eps = Math.Round(DbScanE(columnNum),0); resultData = dbScan.DBScanClusterig(((eps>0)? eps:0.1), (int)GlobalData.infoAlg.Find(item => item.nameAlgoritms.Equals("DBScan")).parametrs.Find(item => item.settingsName.Equals("minPts")).value); foreach (var temp in resultData) { if (temp.Count() == 1) { GlobalData.deffectData.Add(new DeffectData(columnNum.Find(item => item.Value == temp[0].X).RowIndex, columnname, tablename, temp[0].X.ToString())); continue; } } } } } } public double DbScanE(List<Data<double>>columnNum) { double max = columnNum[0].Value; double min = columnNum[0].Value; foreach (var t in columnNum) { if (max < t.Value) { max = t.Value; } if (min >t.Value) { min = t.Value; } } return (max - min) / columnNum.Count; } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ASVA1.Model { /// <summary> /// Информация об методах /// </summary> [Serializable] public class InfoOfAlgoritms { /// <summary> /// Наименование метода /// </summary> public string nameAlgoritms { get; set; } /// <summary> /// Список параметров /// </summary> public List<AlgoritmParametrs> parametrs { get; set; } public InfoOfAlgoritms() { } public InfoOfAlgoritms (string name) { this.nameAlgoritms = name; parametrs = new List<AlgoritmParametrs>(); } public void AddParametrs(string name, float value) { parametrs.Add(new AlgoritmParametrs(name, value)); } } /// <summary> /// Информация о параметрах /// </summary> [Serializable] public class AlgoritmParametrs { /// <summary> /// Название параметра /// </summary> public string settingsName { get; set; } /// <summary> /// Значение параметра Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 71 /// </summary> public float value { get; set; } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; public AlgoritmParametrs() { } public AlgoritmParametrs(string name, float value) { this.settingsName = name; this.value = value; } namespace ASVA1.Algoritms { public class FCM { public float center; //координата центра public float minz;//минимальное значение //объекта, входящего в кластер public float maxz;//максимальное значение //объекта, входящего в кластер public String name;// имя кластера public int numKl; //номер кластера public int countobj;//количество объектов в //кластере public FCM() { center = 0f; minz = 0f; maxz = 0f; name = ""; countobj = 0; } public int compareTo(Object o) { FCM g = (FCM)o; if (g.minz >= this.minz) return 1; else return -1; } } public class FCMSystem { float[,] StPr;// матрица степеней принадлежности float[] objecti;//массив объектов для кластеризации float mi;//параметр q float ei;//требуемая точность int Iter;// количество итераций int countKlast; //количество кластеров int countObj;// количество объектов FCM[] CenKlast;// массив кластеров float ZF = 0f; public FCMSystem(int ck, int I, float e, float m, int objCount, double[,] arr) { countKlast = ck; countObj = objCount; mi = m; ei = e; Iter = I; CenKlast = new FCM[countKlast]; for (int i = 0; i < countKlast; i++) CenKlast[i] = new FCM(); objecti = new float[objCount]; for (int i =0; i<objCount; i++) objecti[i] = (float)arr[i,0]; } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ASVA1.Model.AlgoritmSetting { /// <summary> /// Информация о доступных методах /// </summary> [Serializable] public class AlgoritmsOfDataType { /// <summary> /// Название метода /// </summary> public string algoritmName { get; set;} /// <summary> /// Тип данных, для которого применяется метод /// </summary> public string typeName { get; set; } public AlgoritmsOfDataType() { } public AlgoritmsOfDataType(string algoritmName, string typeName) { this.algoritmName = algoritmName; this.typeName = typeName; } public override string ToString() { return algoritmName; } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ASVA1.Algoritms { public class K_means__ { public static int result; static double[,] cKlast; public static int[] resultKlaserisation; public static int[] Klasterisation(double[,] array, int rows, int vars, int k, int restart) { alglib.kmeans.kmeansgenerate(array, rows, vars, k, restart, ref result, ref cKlast, ref resultKlaserisation); if (result == 1) { return resultKlaserisation; } else return null; } } public bool FCM_CheckStPr() { for (int i = 0; i < countObj; i++) { int t = -1; for (int j = 0; j < countKlast; j++) { if (StPr[i, j] == 1) { t = j; break; } } if (t >= 0) Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 72 { if (u != 0) u = 1 / u; return u; for (int j = 0; j < countKlast; j++) { if (j != t) StPr[i, j] = 0; } } } } float sum = 0; for (int j = 0; j < countKlast; j++) { sum = sum + (StPr[i, j]); } while (sum - 1 >= 0.01) { float max = 0; int ti = 0; for (int j = 0; j < countKlast; j++) { if (StPr[i, j] > max) { max = StPr[i, j]; ti = j; } } float razn = max - sum + 1; if (razn >= 0) { StPr[i, ti] = razn; sum = 0; } if (razn < 0) { StPr[i, ti] = 0; sum = sum - max; } public float Count_CentKlast(int j) { float c = 0f; float c1 = 0f; for (int i = 0; i < countObj; i++) { c = c + (float)(Math.Pow(StPr[i, j], mi)) * objecti[i]; c1 = c1 + (float)(Math.Pow(StPr[i, j], mi)); } return c / c1; } public void Alg() { } sum = 0; for (int j = 0; j < countKlast; j++) { sum = sum + (StPr[i, j]); } if (sum > 1.01) { return false; } } return true; } public void InitFirstFunction(int N) { Random R = new Random(); StPr = new float[N, countKlast]; for (int i = 0; i < N; i++) for (int j = 0; j < countKlast; j++) { StPr[i, j] = (float)R.NextDouble(); } FCM_CheckStPr(); } public float FCM_CountRasst(float x, float c) { return (float)(Math.Abs(x - c)); } public float FCM_CountOcF(int Znach, int Klast) { float sum = 0f; for (int i = 0; i < Znach; i++) for (int j = 0; j < Klast; j++) { sum = sum + (float)(Math.Pow(StPr[i, j], mi) * FCM_CountRasst(objecti[i], CenKlast[j].center)); } return sum; } public float FCM_CountNewU(int t, int j) { float u = 0f; if (FCM_CountRasst(objecti[t], CenKlast[j].center) == 0) return 1; else { for (int i = 0; i < countKlast; i++) { if (FCM_CountRasst(objecti[t], CenKlast[i].center) == 0) { return 1; } else u=u+ (float)Math.Pow(FCM_CountRasst(objecti[t], CenKlast[j].center) / FCM_CountRasst(objecti[t], CenKlast[i].center), 2 / (mi - 1)); } InitFirstFunction(countObj); for (int c = 0; c < Iter; c++) { string s = ""; for (int i = 0; i < CenKlast.Count(); i++) { CenKlast[i].center = Count_CentKlast(i); } for (int i = 0; i < objecti.Count(); i++) { for (int j = 0; j < CenKlast.Count(); j++) { StPr[i, j] = FCM_CountNewU(i, j); s += StPr[i, j].ToString() + " "; } s += Environment.NewLine; } //MessageBox.Show(s); float temp = FCM_CountOcF(objecti.Count(), CenKlast.Count()); if (Math.Abs(temp - ZF) >= ei) { ZF = temp; } else { return; } } } } } using ASVA1.Algoritms.DBScan; using System; using System.Collections.Generic; namespace ASVA1.Algoritms { public class DBscan { List<DataItems> feData = new List<DataItems>(); HashSet<DataItems[]> clusters; DbscanAlgorithm <DataItems> dbs = new DbscanAlgorithm<DataItems>((x, y) => Math.Sqrt(((x.X - y.X) * (x.X - y.X)) + ((x.Y - y.Y) * (x.Y - y.Y)))); public HashSet<DataItems[]> DBScanClusterig(double epsilon, int minPts) { dbs.CoerDbscan(allPoints: fea.ToArray(), epsilon: epsilon, minPts: minPts, clusters: out clusters); return clusters; } public void AddFeatureData(double x, double y) Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 73 { for (Int32 Cluster = 0; Cluster < m_Clusters.Count(); feata.Add(new DataItems(x, y)); Cluster++) } { } double delta = GetDelta(m_Clusters[Cluster], Da- } using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; ta[Index]); if (delta > delta_max || delta_max == -1) { delta_max = delta; cluMaxIndex = Cluster; } } m_Clusters[cluMaxIndex].AddMovie(Data[Index], true); } namespace ASVA1.Algoritms { class CLOPE { private static List<Cluster> m_Clusters = new List<Cluster>(); public static double GetDelta(Cluster SrcCluster,) { double Width_New = SrcCluster.Width; Int32 cluSizeNew = SrcCluster.Movies.Count() + 1; } } static void Alg() { if (!SrcCluster.Data.Contains(SrcMovie)) Width_New = Width_New + 1; return cluSizeNew * 2 / Math.Pow(Width_New, 2) SrcCluster.Data.Count() / Math.Pow(SrcCluster.Width, do { MatchOption = Console.ReadLine(); PartialMatch = ((MatchOption == "y") || (MatchOption == "yes")) ? (((MatchOption != "n") && (MatchOption != "no")) ? true : false) : false; } while (((MatchOption != "y") && (MatchOption != "yes")) && ((MatchOption != "n") && (MatchOption != "no"))); 2); ("\n"); } static Data Init(string filename, bool partial_match, Int32 attribs_required) { Data Data = new Data(); if ((Data = LoadDataFromFile(filename)) != null) { if (m_Clusters != null && m_Clusters.Count() == 0) { List<Cluster> ClustersInitialSet = new List<Cluster>(); for (Int32 Index = 0; Index < Data.Count(); Index++) { Movie SrcMovie = Data[Index]; SrcMovie.m_PartialMatch = partial_match; SrcMovie.m_AttribsRequired = attribs_required; Cluster TargetCluster = new Cluster(new Data( new List<Movie>() { SrcMovie })); if (!m_Clusters.Contains(TargetCluster)) m_Clusters.Add(TargetCluster); } m_Clusters.AddRange(ClustersInitialSet); } } return Data; } static void Clusterize(Data Data) { for (Int32 Index = 0; Index < Data.Count(); Index++) { bool Exists = false; List<Data> DataList = m_Clusters.Select(Cluster => Cluster.Data).ToList(); for (Int32 DatasIndex = 0; DatasIndex < DataList.Count() && !Exists; DatasIndex++) Exists = (DataList[DatasIndex].Where(Movie => Movie.Equals(Data[Index])).Count() > 0) ? true : false; if (Exists == false) { double delta_max = -1; Int32 cluMaxIndex = -1; Clusterize(Init(filename, PartialMatch, AttribsRequired)); PrintClusters(); Console.ReadKey(); Console.ReadKey(); } private static Data LoadDataFromFile(string filename) static bool IsValidCluster(Cluster TargetCluster) { bool isUnique = false; Movie mvTarget = TargetCluster.Data[0]; isUnique = TargetCluster.Data.Skip(1).Where(Movie => Movie.Equals(mvTarget)).Count() == TargetCluster.Data.Count() ? true : false; return !isUnique; } static void PrintClusters() { for (Int32 Index = 0; Index < m_Clusters.Count(); Index++) { bool IsValid = IsValidCluster(m_Clusters[Index]); ("Cluster {0}: (Valid: {1}, Data: {2})", Index, (IsValid == true) ? "Okey" : "Failed", m_Clusters[Index].Data.Count()); } for (Int32 Index = 0; Index < m_Clusters.Count(); Index++) { Data Data = m_Clusters[Index].Data; ("Cluster {0} (Genre: {1}) (Valid: {2}):", Index, Data[0].Genre, (IsValidCluster(m_Clusters[Index])) ? "Okey" : "Failed"); for (var Movie = 0; Movie < Data.Count(); Movie++) { String movie_row = "\0"; var param_aliases = typeof(Movie).GetProperties(); foreach (var param in param_aliases) movie_row += param.GetValue(Data[Movie]).ToString() + " "; ("{0}", movie_row); Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 74 } (); } } } class GenreComparer : IEqualityComparer<string> { public GenreComparer() { } public List<string> NormalizeGenre(string genre_tags) { List<string> GenreTags = genre_tags.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries).Distinct(). Where(Tag => Tag.Length > 1).ToList(); return GenreTags.Select(Tag => (Tag.IndexOf('-') > -1) ? Tag.Substring(0, Tag.IndexOf('-')) : Tag).Distinct().ToList(); } public bool Equals(string genre_tags1, string genre_tags2) { Int32 EqualsCount = 0; List<string> tags_list1 = NormalizeGenre(genre_tags1); List<string> tags_list2 = NormalizeGenre(genre_tags2); if (tags_list1.SequenceEqual(tags_list2)) return true; for (Int32 Index1 = 0; Index1 < tags_list1.Count(); Index1++) for (Int32 Index2 = 0; Index2 < tags_list2.Count(); Index2++) if (tags_list1[Index1].Equals(tags_list2[Index2])) EqualsCount++; return (EqualsCount > 0) ? true : false; } public int GetHashCode(string obj) { throw new NotImplementedException(); } } class Movie : IEquatable<Movie> { public Movie() { this.ID = "0"; this.Title = "\0"; this.Year = "\0"; this.Starring = "\0"; this.Features = "\0"; this.Studio = "\0"; this.Genre = "\0"; this.Release = "\0"; this.Price = "\0"; } public Movie(string id, string title, string year, string starring, string features, string studio, string genre, string release, string price) { .Release = release; } public bool IsNotEmpty() { } bool IEquatable<Movie>.Equals(Movie other) { var similarity = 0.00; if (this.Genre == other.Genre || ((this.GenreEqualsByPartialMatch(other)) && (this.m_PartialMatch == true))) { similarity += 0.33; similarity += (this.Studio == other.Studio) ? 0.33 : 0; similarity += (this.Starring == other.Starring) ? 0.33 : 0; } return (similarity >= m_AttribsRequired * 0.33); } public bool EqualIDs(Movie other) { return (this.ID == other.ID); } public bool StarringEquals(Movie other) { return (this.Starring == other.Starring); } public bool StudioEquals(Movie other) { return (this.Studio == other.Studio); } public bool GenreEquals(Movie other) { return (this.Genre == other.Genre); } public bool GenreEqualsByPartialMatch(Movie other) { return (new GenreComparer().Equals(this.Genre, other.Genre) != false); } public string ID { get { return m_ID; } set { m_ID = value; } } public string Title { get { return m_Title; } set { m_Title = value; } } public string Year { get { return m_Year; } set { m_Year = value; } } public string Starring { get { return m_Starring; } set { m_Starring = value; } } public string Features { get { return m_Features; } set { m_Features = value; } } public string Studio { get { return m_Studio; } set { m_Studio = value; } } public string Genre { get { return m_Genre; } set { m_Genre = value; } } public string Release { get { return m_Release; } set { m_Release = value; } } public string Price { get { return m_Price; } set { m_Price = value; } } private string m_ID; private string m_Year; private string m_Studio; private string m_Genre; private string m_Title; private string m_Starring; private string m_Features; private string m_Release; private string m_Price; public bool m_PartialMatch; public Int32 m_AttribsRequired; } class MovieItemStats : IEquatable<MovieItemStats> { public MovieItemStats(Movie SrcMovie, Int32 occurrences) { this.Movie = SrcMovie; this.Occurrences = occurrences; } public bool Equals(MovieItemStats other) { return this.Movie.Genre == other.Movie.Genre; } public Movie Movie { get { return m_Movie; } set { m_Movie = value; } } public Int32 Occurrences { get { return m_Occurrences; } set { m_Occurrences = value; } } private Movie m_Movie; private Int32 m_Occurrences; } class Data : IEnumerable<Movie>, IEquatable<List<Movie>> { Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 75 private List<Movie> m_Data; public Data() { m_Data = new List<Movie>(); } public Data(List<Movie> DataTarget) { m_Data = DataTarget; } public bool Equals(List<Movie> other) { return m_Data.SequenceEqual(other); } public Movie this[Int32 Index] { get { return m_Data[Index]; } set { m_Data[Index] = value; } } public void Add(Movie SrcMovie) { m_Data.Add(SrcMovie); } public Data Take(Int32 Count) { return new Data(m_Data.Take(Count).ToList()); } public Data Skip(Int32 Count) { return new Data(m_Data.Skip(Count).ToList()); } public bool SequenceEquals(Data other) { return m_Data.SequenceEqual(other); } public IEnumerator<Movie> GetEnumerator() { return m_Data.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } List<MovieItemStats> Datatats = new List<MovieItemStats>(); for (Int32 Index = 0; Index < Data.Count(); Index++) { Int32 SrcMovie_count = Data.Where(Movie => Movie.GenreEquals(Data[Index])).Count(); if (!Datatats.Contains(new MovieItemStats(Data[Index], SrcMovie_count))) Datatats.Add(new MovieItemStats(Data[Index], SrcMovie_count)); } return Datatats; } private double GetHeight() { List<MovieItemStats> Datatats = GetDataStats(); return Datatats.Sum(Stats => Stats.Occurrences) / (double)Datatats.Count(); } private double GetWidth() { return GetDataStats().Count(); } private void UpdateCluster(bool Initialize = false) { if (Initialize == true) { this.Width = this.Height = 1; } else { this.Width = GetWidth(); this.Height = GetHeight(); } } public void AddMovie(Movie SrcMovie, bool UpdateRequired = false) { m_Data.Add(SrcMovie); if (UpdateRequired == true) this.UpdateCluster(false); } public bool Equals(Cluster other) { return this.Data.SequenceEquals(other.Data); } } class Cluster : IEquatable<Cluster> { public Data m_Data = new Data(); public Cluster() { this.UpdateCluster(true); } public Cluster(Data SrcData) { this.Data = SrcData; this.UpdateCluster(true); } private List<MovieItemStats> GetDataStats() { } } using System; using System.Collections.Generic; using System.Linq; namespace ASVA1.Algoritms.DBScan { /// <summary> /// DBSCAN /// </summary> /// <typeparam name="T">Takes dataset item row (features, preferences, vector) type</typeparam> public class DbscanAlgorithm<T> where T : DatasetItemBase { private readonly Func<T, T, double> _metricFunc; /// <summary> /// Мертрики /// </summary> /// <param name="metricFunc"></param> public DbscanAlgorithm(Func<T, T, double> metricFunc) { _metricFunc = metricFunc; } /// <summary> /// Альгоритм кластеризации /// </summary> /// <param name="allPoints">Dataset</param> /// <param name="epsilon">Desired region ball radius</param> /// <param name="minPts">Minimum number of points to be in a region</param> /// <param name="clusters">returns sets of clusters, renew the parameter</param> public void ComputeClusterDbscan(T[] allPoints, double epsilon, int minPts, out HashSet<T[]> clusters) { DbscanPoint<T>[] allPointsDbscan = allPoints.Select(x => new DbscanPoint<T>(x)).ToArray(); int clusterId = 0; for (int i = 0; i < allPointsDbscan.Length; i++) { Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 76 DbscanPoint<T> p = allPointsDbscan[i]; if (p.IsVisited) continue; p.IsVisited = true; } } DbscanPoint<T>[] neighborPts = null; RegionQuery(allPointsDbscan, p.ClusterPoint, epsilon, out neighborPts); if (neighborPts.Length < minPts) p.ClusterId = (int)ClusterIds.Noise; else { clusterId++; ExpandCluster(allPointsDbscan, p, neighborPts, clusterId, epsilon, minPts); } } clusters = new HashSet<T[]>( allPointsDbscan .Where(x => x.ClusterId > 0) .GroupBy(x => x.ClusterId) .Select(x => x.Select(y => y.ClusterPoint).ToArray()) ); } /// <summary> /// /// </summary> /// <param name="allPoints">Dataset</param> /// <param name="point">point to be in a cluster</param> /// <param name="neighborPts">other points in same region with point parameter</param> /// <param name="clusterId">given clusterId</param> /// <param name="epsilon">Desired region ball range</param> /// <param name="minPts">Minimum number of points to be in a region</param> private void ExpandCluster(DbscanPoint<T>[] allPoints, DbscanPoint<T> point, DbscanPoint<T>[] neighborPts, int clusterId, double epsilon, int minPts) { point.ClusterId = clusterId; for (int i = 0; i < neighborPts.Length; i++) { DbscanPoint<T> pn = neighborPts[i]; if (!pn.IsVisited) { pn.IsVisited = true; DbscanPoint<T>[] neighborPts2 = null; RegionQuery(allPoints, pn.ClusterPoint, epsilon, out neighborPts2); if (neighborPts2.Length >= minPts) { neighborPts = neighborPts.Union(neighborPts2).ToArray(); } } if (pn.ClusterId == (int)ClusterIds.Unclassified) pn.ClusterId = clusterId; } } /// <summary> /// Проверка на соседей /// </summary> /// <param name="allPoints">Dataset</param> /// <param name="point">centered point to be searched neighbors</param> /// <param name="epsilon">radius of center point</param> /// <param name="neighborPts">result neighbors</param> private void RegionQuery(DbscanPoint<T>[] allPoints, T point, double epsilon, out DbscanPoint<T>[] neighborPts) { neighborPts = allPoints.Where(x => _metricFunc(point, x.ClusterPoint) <= epsilon).ToArray(); Лист БР – УлГТУ – 09.03.04 – 14/456 – 2018 Изм. Лист № докум. Подпись Дата 77 “______” ________________ 20__ г. Последний лист бакалаврской работы Бакалаврская работа выполнена мною самостоятельно. Использованные в работе материалы из опубликованной научной, учебной литературы и Интернета имеют ссылки на них. Отпечатано в 1 экземпляре. Библиография 25 наименований. Один экземпляр сдан на кафедру. Фасхутдинова Диляра Альбертовна Дата