Здравствуйте, уважаемые читатели Хабра!
Это заключительная третья часть (первая и вторая) о создании основного функционала MVP (Minimum Viable Product) системы по управлению цифровыми активами для базы данных PostGIS. Полный перечень возможностей разрабатываемого проекта представлен на картинке ниже.

В этой публикации рассмотрим применение тематического моделирования для анализа имеющихся данных и визуализации семантических связей между таблицами.
Содержание
Введение
Напомню, что в базе данных PostGIS находятся более 1200 никак несвязанных между собой таблиц с суммарным кол-вом 300 млн. записей.

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


Требуется решить две задачи:
Автоматический анализ имеющейся информации в таблице. Бо'льшая часть таблиц и схем не имеют осмысленных наименований. Например, имя таблицы может быть '_1059._1524'. Это затрудняет ориентирование в огромном океане данных. Лишь для некоторых таблиц существует составленная вручную метаинформация с описанием их предназначения. Обычно разработчик или сотрудник, чтобы узнать, что хранит таблица, вынужден вначале посмотреть на несколько её строк (SELECT * FROM ...) и проанализировать их. Поэтому было бы хорошо иметь функционал, автоматически проводящий анализ информации в таблице и выводящий краткое сведение о её содержимом.
Установление семантических связей между таблицами. Информация об одних и тех же объектах может быть разбросана по нескольким таблицам. Поэтому необходим механизм, позволяющий связывать разрозненные данные.
При решении обеих задач будем проводить анализ на уровне таблиц. То есть будем делать выводы на основе всех записей таблицы. Объединим все числовые и текстовые колонки каждой записи таблицы в одно текстовое поле text, как это сделали в предыдущей статье. Оно послужит описанием для объекта.

Для решения этих задач к нам на помощь приходит тематическое моделирование.
Тематическое моделирование
Тематическое моделирование (англ. topic modeling) — способ построения модели коллекции текстовых документов, которая определяет к каким темам относится каждый из документов. Вероятностные тематические модели осуществляют «мягкую» кластеризацию, позволяя документу или термину относиться сразу к нескольким темам с различными вероятностями. Вероятностные тематические модели описывает каждую тему дискретным распределением на множестве терминов, каждый документ — дискретным распределением на множестве тем.
Рассмотрим, как с помощью двух подходов - LDA и BERTopic, можно решить поставленные задачи.
LDA
Латентное размещение Дирихле (LDA, от англ. Latent Dirichlet Allocation) — применяемая в машинном обучении и информационном поиске порождающая модель, позволяющая объяснять результаты наблюдений с помощью неявных групп, благодаря чему возможно выявление причин сходства некоторых частей данных. Например, если наблюдениями являются слова, собранные в документы, утверждается, что каждый документ представляет собой смесь небольшого количества тем и что появление каждого слова связано с одной из тем документа.
В LDA каждый документ может рассматриваться как набор различных тематик. Подобный подход схож с вероятностным латентно-семантическим анализом (pLSA) с той разницей, что в LDA предполагается, что распределение тематик имеет в качестве априори распределения Дирихле.
Вероятностные тематические модели основаны на следующих предположениях:
Порядок документов в коллекции не имеет значения
Порядок слов в документе не имеет значения, документ – мешок слов
Слова, встречающиеся часто в большинстве документов, не важны для определения тематики
Коллекцию документов можно представить как выборку пар документ-слово
Каждая тема описывается неизвестным распределением на множестве слов
Каждый документ описывается неизвестным распределением на множестве тем
Гипотеза условной независимости
Более подробно с теоретической частью тематического моделирования можно ознакомиться здесь. Больше информации об алгоритме LDA тут.
Перейдём к практической части. Так будет выглядеть одна запись в датафрейме.
{ "text": "1 533 Смольная ул., д. 61 А Постановления Правительства Москвы О внесении изменений в постановление Правительства Москвы 120-ПП 2017-03-28 00:00:00+00 - 719-ПП 27.09.2017 ППМ ГБУ \"ГлавАПУ\" 77-02-11-000062 1_10 77-02-11-000062 3.5.1.0 3.5.1 10448.2684799489 407.078766206456 2017 сентябрь old", "schema_name": "_29778", "table_name": "_29805" }
И для некоторых таблиц, как было сказано выше, существует метаинформация. Она представлена в виде иерархической структуры наподобие организации путей в файловой системе. Используем её в качестве тегов.
"tags": ["МКА. Геоданные", "209 Внесение изменений в ПЗЗ", "Внесение изменений в ПЗЗ", "2017", "Сентябрь", "ППМ"],
Произведём очистку текста. Удалим цифры, url'ы, знаки препинания, стоп-слова, приведём всё к нижнему регистру. Обработанный текст занесём в колонку clean_split_text датафрейма.
Реализация на Python метода очистки текста
def clean_text(self, text: str)->str: """ Функция для очистки текста. Возвращает обработанную строку. :param text - водная строка :return str """ # Удаление URL text = re.sub(r'http\S+|www\S+|https\S+', ' ', text, flags=re.MULTILINE) # Удаление цифр и специальных символов text = re.sub(r'\d+', ' ', text) # Оставляем только буквы text = re.sub(r'[^a-zA-Zа-яА-ЯёЁ]', ' ', text) # Удаление пунктуации translator = str.maketrans(string.punctuation, ' ' * len(string.punctuation)) text = text.translate(translator) # Приведение к нижнему регистру text = text.lower() # Разбиение на слова по пробелам words = text.split() # Удален��е коротких и стоп-слов words = [word for word in words if word not in self.stop_words and len(word) > 2] # Объединяем слова и возвращаем обработанную строку return ' '.join(words)
Для LDA понадобятся вспомогательные функции сопоставления каждому слову уникального идентификатора, получения корпуса.
Реализация вспомогательных функций
def gen_words_for_dataframe(self)->None: """ Формирует список слов для датафрейма и каждому уникальному слову задаёт id :return None """ self.words_list = self.gen_words(self.dataframe['clean_split_text']) # каждому уникальному слову задаётся id self.id2word = corpora.Dictionary(self.words_list) def get_corpus_for_dataframe(self)->None: """ Создаёт корпус для датафрейма :return None """ self.corpus = self.get_corpus(self.dataframe['clean_split_text']) def get_corpus(self, texts)->List: """ Возвращает корпус для текстов :return [] """ corpus = [] for text in texts: new = self.id2word.doc2bow(text) corpus.append(new) return corpus
Кроме создания обычного "мешка слов" можно объединить токены в биграммы и триграммы для получения смысловых связок в виде словосочетаний.
И теперь обучим модель на наших подготовленных данных. Ниже представлена функция для обучения и сохранения модели. Обязательно указываем желаемое количество кластеров.
def get_and_save_lda_model(self, save_model_directory: str, num_topics: int = 7): """ Функция для создания и сохранения модели :param save_model_directory - директория для сохранения модели :param num_topics - кол-во топиков (кластеров) :return None """ self.lda_model = gensim.models.ldamodel.LdaModel(corpus=self.corpus, id2word=self.id2word, num_topics=num_topics, random_state=100, update_every=1, chunksize=100, passes=10, alpha="auto", per_word_topics=True) self.lda_model.save(save_model_directory)
После получаем в формате html визуализацию построенных кластеров.
def get_clusters_visualization(self, save_clusterization_path: Union[Path, str])->None: """ Сохранение визаулизации кластеризации :param:save_clasterization_path - путь для сохранения html файла """ vis = pyLDAvis.gensim.prepare(self.lda_model, self.corpus, self.id2word, mds="mmds", R=30) pyLDAvis.save_html(vis, save_clusterization_path)

Чем ближе расположены кластера, тем более похожими они являются. Если имеет место вложенность кластеров, то следует уменьшить общее желаемое их количество (или объединить вложенные). Размер кластера зависит от количества попавших в него объектов. Для каждого кластера справа выводится список наиболее характерных для него слов.
Благодаря получившейся обученной модели можно узнать вероятностное распределение произвольного текста на множестве кластеров.
Получение распределения текста на множестве кластеров
# загрузим сохранённую LDA-модель lda_model = gensim.models.ldamodel.LdaModel.load(temp_file) text_samples = ['Смольная ул., д. 61 А Постановления Правительства Москвы'] cleaned_test_text_list = [clean_text(text_sample) for text_sample in text_samples] cleaned_test_texts_split_list = [cleaned_test_text.split() for cleaned_test_text in cleaned_test_text_list] other_corpus = [id2word.doc2bow(text) for text in cleaned_test_texts_split_list] # классифицируем первый текст unseen_doc = other_corpus[0] vector = lda_model.get_document_topics(unseen_doc) vector = sorted(vector, key=lambda x: x[1], reverse=True)
# vector [ (4, 0.5476772), (5, 0.263907), (1, 0.080080785), (6, 0.045159835), (0, 0.022513434), (2, 0.021443361), (3, 0.01921838) ]
Ниже представлена гистограмма распределения текста по тематикам. По вертикали - вероятность, по горизонтали - имя темы, составленное из её номера и трёх наиболее характеризующих слов.

Для каждого текста датафрейма определим его распределение на множестве кластеров.
Реализация на Python метода для распределения описаний объектов датафрейма по темам
def predict_topics_for_dataframe(self): """ Распределение вероятностей описаний объектов датафрейма по темам. :return None """ # добавим колонки для тематик topic_columns_list = [f'topic_{i}' for i in range(self.lda_model.num_topics)] for topic in topic_columns_list: self.dataframe[topic] = 0.0 for row_id, row in self.dataframe.iterrows(): cleaned_text = row['cleaned_text'] cleaned_test_text_split_list = cleaned_text.split() document = self.id2word.doc2bow(cleaned_test_text_split_list) # классифицируем первый текст vector = self.lda_model.get_document_topics(document) topic_dict = dict() for i in range(len(vector)): topic_name = 'topic_' + str(vector[i][0]) topic_prob = vector[i][1] topic_dict[topic_name] = topic_prob for topic, prob in topic_dict.items(): self.dataframe.loc[row_id, topic] = prob

Наша задача узнать какие таблицы входят вместе в один кластер. Для этого есть два варианта:
Жёсткая кластеризация. Использовать пороговое значение 0.5 (threshold=0.5). То есть присваиваем объекту тот кластер, в котором модель точно уверена.
Мягкая кластеризация. Использовать argmax. Тогда, в случае, когда у объекта есть несколько кластеров с одинаковой вероятностью (например, 4 кластера с p=0.25), объект будет принадлежит им всем.
Выберем более жёсткий первый вариант. Считаем, что строка должна принадлежать только одному кластеру. Это позволит более чётко увидеть различия в данных, так как в таком случае в каждый кластер попадают только характерные для него объекты. Однако, при этом из рассмотрения выбрасываются объекты, которые модель не смогла точно сопоставить (p_topic_i < 0,5) к какому-либо одному кластеру.
Далее проведём анализ и визуализацию данных после применения жёсткого варианта клаcтеризации. Для каждой таблицы в кластере отобразим суммарное кол-во её строк; кол-во строк, попавших в кластер; ratio – второе поделённое на первое в процентном соотношении.

По показателю ratio можно сказать о хорошей семантической связи между таблицами '_46379._47923', '_46379.47925' и '_46379._47928' т.к. все их строки полностью находятся в одном кластере (ratio = 1).
Для каждого кластера отобразим в порядке возрастания наиболее часто встречаемые в нём теги, схемы, таблицы и слова (WorldCloud).

Для более наглядного представления семантических связей создадим с помощью библиотеки pyvis два интерактивных графа в формате html:
Граф связей таблиц с кластерами
Граф связей таблиц друг с другом


Ромбы - кластера. Круги - таблицы. Чем толще дуги между объектами, тем сильнее связи. Сила связи между кластером и таблицей рассчитывается в процентном соотношении как кол-во строк таблицы, вошедших в кластер поделённое на кол-во строк в ней. А между двумя таблицами как общее кол-во их строк в одинаковых кластерах, поделённое на общую сумму строк двух таблиц. Также присутствуют несвязанные кластера - они появились из-за выбранного жёсткого подхода.


И теперь отобразим связи между таблицами (напрямую без кластеров).




И для каждой таблицы можно вывести её силу связи с остальными таблицами.

BERTopic
BERTopic — это метод тематического моделирования, в котором используются трансформеры и c-TF-IDF для создания плотных кластеров, позволяющих легко интерпретировать темы и при этом сохранять важные слова в описаниях тем.
BERTopic можно рассматривать как последовательность шагов по созданию тематических представлений. Этот процесс состоит из шести (пяти обязательных) этапов:


Алгоритм BERTopic состоит из следующих этапов:
Векторизация. Каждый документ преобразуется в вектор чисел (эмбеддинг, массив с большим кол-вом значений) с использованием предобученной BERT-модели. Эти вектора фиксируют семантическое значение слов в контексте документа.
Снижение размерности. Например, алгоритм UMAP отлично походит для борьбы с "проклятием размерности" извлечённых эмбедингов.
Кластеризация. Уменьшенные вектора документов группируются в тематики с использованием алгоритма кластеризации, например такого как HDBSCAN. Следует указать желаемое кол-во кластеров, иначе получится слишком много мелких тематик.
Токенизация. Получение "мешка слов" каждого кластера. Также возможно извлечение биграмм и триграмм для получения осмысленных словосочетаний и контекста.
Создание тематических представлений. Для каждого кластера извлекаются наиболее релевантные слова, которые и формируют тематическое представление. BERTopic использует алгоритм c-TF-IDF для определения важности слов в каждом кластере. На этом этапе определяются слова, наиболее всего характеризующие каждый кластер и отличающие его от всех остальных.
Представление темы при помощи LLM (опционально). На предыдущем этапе сформированы наименования кластеров как их номера с набором характерных слов. Например, тематика может именоваться как
4_протокол_метро_пункт. А осмысленное представление темы в человекоподобной форме можно получить при помощи промпта LLM на основе характерных слов кластера и его наиболее репрезентативных документов.
Визуализируем получившиеся кластера BERTopic так же, как и в LDA.

Благодаря иерархической кластеризации "из коробки" можно определиться с количеством тематик, увидеть связи между ними.



На основе значений тепловой карты схожести тем можно определить какие кластера наиболее близки (похожи) и объединить (merge) их.



Выводы и замечания
LDA и BERTopic могут демонстрировать разное качество работы в зависимости от входных данных: на одних наборах точнее сработает LDA, на других — BERTopic. Успех здесь также напрямую зависит от возможности корректно интерпретировать результаты и подбора параметров алгоритмов.
LDA - давно известный и проверенный подход, основанный на подсчёте токенов как «мешка слов». BERTopic сочетает современные языковые модели и c-TF-IDF, активно развивается, имеет более богатую встроенную визуализацию.
Сильные стороны LDA:
Проверенность и предсказуемость: Алгоритм изучен вдоль и поперек, его поведение хорошо понятно.
Стабильность: Менее чувствителен к размеру датасета, всегда выдаёт заданное число тем.
Скорость и масштабируемость: Быстрее обрабатывает очень большие коллекции текстов.
Прозрачная модель: Предоставляет чёткие вероятностные распределения для документов и тем.
Сильные стороны BERTopic:
Качество и связность тем: Темы, как правило, более осмысленные и релевантные для человека.
Контекстное понимание: Эффективно работает с синонимами, многозначными словами и сложными языковыми конструкциями.
Отличная работа с короткими текстами: Идеален для твитов, отзывов, комментариев.
Минимальная предобработка: Экономит время на этапе подготовки данных.
Для работы с большим объёмом данных следует воспользоваться итерационным подходом - обучать не на всём датасете сразу, а на последовательно приходящих записях. Это позволит уменьшить объём требуемой оперативной памяти и в случае необходимости дообучить модель на новых данных. Для этого варианта у BERTopic существует Online Topic Modeling.
Для ускорения вычисления эмбеддингов в BERTopic стоит использовать GPU (cuda). Также можно воспользоваться уже вычисленными эмбеддингами, например из таблицы embedding_table (см. предыдущую статью).
Аналогичные интерактивные графы для визуализации связей можно построить на основе геометрий объектов (см. первую статью).
Для ускорения нахождения объектов по их описанию имеет смысл провести поиск сначала по кластерам аналогично тому, как это делалось в первой статье для поиска объектов по геометрии. То есть сначала определяем к каким кластерам наиболее всего подходит данное описание объекта. И затем переходим к поиску объектов среди содержащихся в этих кластерах таблиц.
Существуют другие и появляются новые методы тематического моделирования. Алгоритм LDA может быть взят из библиотеки gensim как в данном случае либо из библиотеки sklearn.
Дополнительный функционал
Далее вкратце рассмотрим функционал по расширению возможностей системы.
Модуль нахождения изменений в таблицах
Бывает, что в базе данных происходят переименования столбцов таблиц. Из-за чего QGIS-плагины выдают ошибку о не существующем столбце. Или же сильно поменялись сами данные в столбце, что также приводит к некорректной работе или к возникновению исключений.
Для решения этой проблемы можно воспользоваться supervised классификацией BERTopic. То есть вместо кластеризации переходим к классификации. В роли классов выступят наименования столбцов таблицы. На рисунке ниже схематично показаны шаги для реализации данной идеи.

Шаги построения и применения supervised модели BERTopic:
Обучим модель в момент времени T1 на таблице
old_table. Классы - имена столбцов. Значения - отдельные последовательные значения в столбцах. Обучаем модель сопоставлять классы и значения. Например, для таблицыold_tableобучаем модель сопоставлять столбецfield_cсоответствующими ему значениями.Применим обученную модель. Затем, когда произошли изменения в таблице
old_tableв момент времени T2 (T2 > T1) и она сталаcurrent_table, отправляем наборы данных в колонках на классификацию и усредняем результаты. Например, из колонкиfield_dклассифицируем 100 записей и затем произведём усреднение их результатов.Анализируем результаты и делаем выводы. По распределению вероятностей определяем к какому столбцу или столбцам наиболее вероятнее всего относятся данные. Если есть несовпадения, то нашли изменения. Например, данные были взяты из столбца
field_dтекущей таблицыcurrent_table, но по классификации модель определила, что он соответствует столбцуfield_c.
Извлечение именованных сущностей
Тег (от англ. tag — «метка, бирка, ярлык») — ключевое слово или метка, которая помогает структурировать, классифицировать или выделять информацию. Теги упрощают поиск и навигацию по информации, кратко передают суть текстов. Для их получения воспользуемся извлечением именованных сущностей (Named Entity Recognition) из описаний объектов при помощи библиотеки SpaCy.
Основные категории именованных сущностей:
PERSON- Имена людей. Примеры:"Александр Пушкин","Мария Иванова"ORG- Организации, включая компании, учреждения, органы власти и т.д. Примеры:"Газпром","МГУ"GPE(Geo-Political Entity) - Геополитические объекты. Это страны, города, регионы, штаты. Примеры:"Россия","Москва".LOC(Location) - Не-GPE объекты, то есть географические локации, не являющиеся политическими образованиями. Примеры:"Эверест","Байкал".DATE- Абсолютные или относительные даты, периоды. Примеры:"5 мая","2023 год".TIME- Время суток, периоды меньше дня. Примеры:"два часа ночи","полдень.MONEY- Денежные суммы, включая валюту. Примеры:"50 рублей","€100".PERCENT- Проценты. Примеры:"100%","несколько процентов".FAC(Facility) - Объекты инфраструктуры, здания, аэропорты, шоссе и т.д. Примеры:"Кремль","аэропорт Шереметьево"LAW- Правовые документы, законы, нормативные акты. Примеры:"Конституция РФ","Федеральный закон № 123"
Реализация на Python метода извлечения и визуализации именованных сущностей из текста
# Загружаем модель для русского языка # если она не найдена, то установим командой: python -m spacy download ru_core_news_lg # также можно попробовать модель deeppavlovru_core_news_lg nlp = spacy.load("ru_core_news_lg") def extract_and_visualize_entities_from_text(self, text: str, save_directory: Path)->None: """ Извлекает и визуализирует именованные сущности. :param save_directory - путь для сохранения визуализации :param text - текст :return None """ html_save_path = save_directory.joinpath('entity_visualization.html') text = text doc = self.nlp(text) html_page = displacy.render(doc, style="ent", page=True) with open(html_save_path, 'w', encoding='utf-8') as file: file.write(html_page)

Также можно обучить модель на своих данных, ввести новые категории именованных сущностей. Например, имена заказчиков, поставщиков. Тег может быть сделан в поисковой системе кликабельным и по нажатию предоставлять дополнительную информацию.
Модуль проверки текстовых данных на опечатки
Никому не нравятся опечатки в отчётах. Поэтому воспользуемся библиотекой symspellpy для проверки корректности текстовых данных.
Реализация класса на Python для проверки текста на опечатки
class Typos: def __init__(self, vocab_path: Path, max_dictionary_edit_distance=2, prefix_length=6, count_threshold=1): """ :param vocab_path - путь к словарю :param max_dictionary_edit_distance - максимальное расстояние редактирования :param prefix_length - длина префикса :param count_threshold - минимальная частота слова для учета в словаре """ self.dataframe = None nltk.download('stopwords') # Загрузка стоп-слов (один раз при старте) self.stop_words = set(stopwords.words('russian')) # print(f"stop_words = {self.stop_words}") self.max_dictionary_edit_distance = max_dictionary_edit_distance self.prefix_length = prefix_length self.count_threshold = count_threshold self.sym_spell = symspellpy.SymSpell( max_dictionary_edit_distance=self.max_dictionary_edit_distance, # Позволяет исправлять 2 ошибки в слове prefix_length=self.prefix_length, # Оптимально для слов от 5 символов count_threshold=self.count_threshold # Учитывать даже редкие слова ) self.sym_spell.load_dictionary(vocab_path, term_index=0, count_index=1, encoding='utf-8') def check_text_for_typos(self, text, top_k=3): """ Проверяет текст на опечатки и возвращает предложения исправлений. Параметры: text - строка для проверки top_k - количество предлагаемых исправлений Возвращает: dict: { 'has_typo': bool, 'corrections': {слово: [исправления]} } """ words = text.split() result = {'has_typo': False, 'corrections': {}} for word in words: # Игнорируем слова с цифрами/спецсимволами if not word.isalpha(): continue suggestions = self.sym_spell.lookup(word, symspellpy.Verbosity.TOP, max_edit_distance=2) if suggestions and (suggestions[0].term != word.lower()): result['has_typo'] = True result['corrections'][word] = [sug.term for sug in suggestions[:top_k]] return result vocab_path = Path(f'../vocabs/ru-100k.txt') typos_object = Typos(vocab_path=vocab_path)
В каждой строке словаря записано слово с его частотностью (популярностью в текстах). Необходимо расширить словарь словами из предметной области, добавить аббревиатуры.

Модуль нахождения выбросов в числовых полях
Числовые выбросы сильно влияют на результаты вычислений и приводят к неправильным выводам в отчётах. Для их определения в простейшем случае будем проверять лежат ли числовые значения записей в диапазоне межквартильного размаха. Если выходят за его пределы, то это выброс.
Реализации метода для определения числовых выбросов в датафрейме
def get_outliers(self)->Dict: """ Возвращает словарь, где ключами явлются имена колонок с числовыми выбросами. А значениями - сами записи. :return dict """ result = defaultdict(list) for column in self.dataframe.select_dtypes(include=['number']).columns: Q1 = self.dataframe[column].quantile(0.25) Q3 = self.dataframe[column].quantile(0.75) IQR = Q3 - Q1 lower_bound = Q1 - 1.5 * IQR upper_bound = Q3 + 1.5 * IQR # print(f"lower_bound = {lower_bound}, upper_bound = {upper_bound}") outliers = self.dataframe[(self.dataframe[column] < lower_bound) | (self.dataframe[column] > upper_bound)] print(f"Кол-во выбросов в колонке '{column}': {len(outliers)}") if len(outliers) > 0: # print(outliers) for _, outlier in outliers.iterrows(): result[column].append(outlier.tolist()) print(outlier.tolist()) return result


Заключение
В рамках цикла из трех статей мы рассмотрели реализацию ключевого функционала системы.
Главные возможности системы:
Интеллектуальный поиск объектов. Система решает проблему поиска одинаковых или похожих объектов по их текстовому описанию и/или геометрии в масштабах огромного хранилища. Благодаря комбинации кластеризации по геометрии и тематического моделирования для текста, поиск выполняется быстро даже среди тысяч таблиц и сотен миллионов записей.
Глубинная геоаналитика. Различные варианты геометрической кластеризации позволяют не просто группировать объекты на карте, но и проводить содержательный анализ. Это даёт возможность автоматически выявлять аномальные зоны — как аномально плотные скопления объектов, так и области их критического разрежения.
Наведение порядка в данных. Тематическое моделирование позволило автоматизировать анализ информации в таблицах; связать воедино разбросанные данные, объединив их в единую, логичную систему; визуализировать семантические связи между таблицами.
Помимо основных функций, мы также кратко затронули важные механизмы, обеспечивающие качество и надежность данных:
Мониторинг целостности структуры данных. Представлен подход для быстрого обнаружения изменений в названиях колонок и структуре самих таблиц. Это позволяет оперативно устранять неполадки в работе QGIS-плагинов, вызванные подобными правками.
Обогащение данных. Извлечение именованных сущностей (NER) позволяет автоматически получать ключевые теги. Это значительно повышает информативность системы и упрощает навигацию по данным.
Очистка данных от ошибок ввода. Реализована борьба с опечатками в тексте и статистическими выбросами в числах. Автоматизация этого процесса исключает влияние человеческого фактора при заполнении данных, что гарантирует корректность отчётов и достоверность последующих выводов и расчётов.
В совокупности представленные технологии и подходы формируют основу для построения надежной и эффективной системы по управления цифровыми активами в базе данных PostGIS.
Спасибо за внимание!
Ссылки, источники и полезные материалы
Хорошая статья про анализ отзывов с помощью тематического моделирования
В этой статье рассматриваются различные методы тематического моделирования
Забавное применение тематического моделирования для анализа анекдотов
Учёный в области машинного обучения Maarten Grootendorst рассказывает о BERTopic
Лекция профессора Воронцова К.В. про тематическое моделирование
