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

Встраивание узлов полезно, когда вы хотите захватить сетевую информацию в векторе фиксированного размера и использовать его в последующем рабочем процессе машинного обучения.
Я наткнулся на пакет Karate Club в поисках реализации различных моделей встраивания узлов. Я позволю автору Бенедек Роземберчки объяснить, в чем его цель:
Karate Club состоит из современных методов неконтролируемого обучения на основе структурированных данных с графами. Проще говоря, это швейцарский армейский нож для небольших исследований по добыче графов. Во-первых, он предоставляет методы встраивания сети на уровне узла и графа. Во-вторых, он включает в себя множество перекрывающихся и неперекрывающихся методов обнаружения сообществ. Реализованные методы охватывают широкий спектр сетевых наук (NetSci, Complenet), интеллектуального анализа данных (ICDM, CIKM, KDD), искусственного интеллекта (AAAI, IJCAI) и машинного обучения ( NeurIPS, ICML, ICLR) конференции, семинары и статьи из известных журналов.
Особенности проекта Karate Club:
- 10+ моделей обнаружения сообществ
- 25+ моделей встраивания узлов
- 10+ моделей встраивания графов
Как вы знаете, я люблю хранить информацию о своей сети в Neo4j. В этом сообщении в блоге я продемонстрирую, как извлечь сетевую информацию из Neo4j и использовать ее в качестве входных данных для API клуба карате. Это прямое преобразование. Нам нужно преобразовать граф Neo4j в модель графа NetworkX, поскольку Karate Club использует структуру NetworkX, и мы готовы к работе. Как всегда, я подготовил блокнот Google Colab, если вы хотите продолжить.
Модель данных
Мы будем использовать простой игрушечный граф вселенной Гарри Поттера, который я создал в моем предыдущем посте в блоге. Я подготовил CSV-файл со структурой сети, поэтому вам не нужно выполнять НЛП самостоятельно.

Сеть основана на книге «Гарри Поттер и философский камень». Узлы представляют персонажа в книге, а отношения ИНТЕРАКТЫ представляют собой совпадения в тексте между символами. Чтобы импортировать эту сеть, выполните следующий запрос Cypher:
P.s. Если вы следуете вместе с записной книжкой Colab, я предлагаю вам открыть пустой Neo4j Sandbox project.
LOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/tomasonjo/blog-datasets/main/HP/hp_1.csv" as row
MERGE (s:Character{name:row.source})
MERGE (t:Character{name:row.target})
MERGE (s)-[r:INTERACTS]-(t)
SET r.weight = row.weight
RETURN distinct 'import successful' as result
Теперь, когда наша сеть импортирована, мы можем изучить структуру сообщества и рассчитать встраивание узла с помощью пакета Karate Club.
Обнаружение сообщества
Для тех из вас, кто совершенно не знаком с Neo4j, я должен сообщить, что плагин Neo4j Graph Data Science предоставляет несколько алгоритмов обнаружения сообщества из коробки. Я быстро продемонстрирую, как использовать алгоритм Лувена в библиотеке GDS.
CALL gds.louvain.write({
nodeProjection:'Character',
relationshipProjection:{INTERACTS:{orientation:'UNDIRECTED'}},
writeProperty:'louvain'
})
Важной деталью сетевого анализа является то, что сеть взаимодействия между персонажами не направлена. Я визуализирую результаты алгоритма Лувена с NEuler. NEuler - это игровая площадка Neo4j Graph Data Science, которая помогает выполнять алгоритмы графов и визуализировать их результаты.

Я не буду вдаваться в теорию алгоритмов или их плюсы и минусы. Цель этого сообщения в блоге - помочь вам начать работу по интеграции Karate Club и Neo4j. Идеи и различия алгоритмов могут быть описаны в другом сообщении в блоге. Теперь давайте запустим несколько алгоритмов в KC. KC работает только тогда, когда узлы в графе имеют последовательные идентификаторы. Я не знаю причины этого выбора; вот так оно и есть. Мы можем легко создать сопоставление с последовательными идентификаторами и сохранить его в Neo4j.
MATCH (c:Character) WITH count(*) as number, collect(c) as nodes UNWIND range(0, number - 1) as index WITH nodes[index] as node, index SET node.index = index
Теперь мы должны экспортировать соответствующие сетевые данные и построить из них графическую модель NetworkX. Граф NetworkX можно построить, предоставив только список ребер. Синтаксис списка ребер:
["1 2 {'weight': 3}", "2 3 {'weight': 27}", "3 4 {'weight': 3.0}"]
Здесь у нас есть три отношения. Каждая взаимосвязь содержит информацию об исходном и целевом узлах, а также любые дополнительные свойства взаимосвязи. Этот синтаксис можно легко создать с помощью Cypher. Во-первых, я определил функцию, которая считывает результаты запроса Cypher и преобразует их в фрейм данных Pandas:
Теперь мы можем продолжить и построить графическую модель NetworkX вселенной Гарри Поттера.
Обратите особое внимание на параметр create_using. В этом случае я хотел определить неориентированный граф, поэтому я использовал параметр nx.Graph. Если вы имеете дело с ориентированным графом или даже с мультиграфом, выберите соответствующий параметр create_using.

Теперь, когда мы построили граф NetworkX, мы можем приступить к тестированию алгоритмов KC. Начнем с алгоритма обнаружения сообщества BigClam. Мы рассчитаем структуру сообщества и запишем результаты обратно в Neo4j.
KC API очень прост в использовании. Вы просто определяете желаемый алгоритм графа и вводите модель графа NetworkX в методе подгонки, и все. Что может быть проще? Я добавил дополнительный код, который затем сохраняет результаты в Neo4j. Давайте снова визуализируем результаты с помощью NEuler.

С первого взгляда мы можем заметить, что структура сообщества немного отличается от того, когда мы использовали алгоритм Лувена. Вы можете протестировать другие десять алгоритмов обнаружения сообщества и сообщить мне, если найдете что-нибудь интересное.
Вложения узлов
Опять же, библиотека Neo4j GDS предоставляет алгоритмы встраивания узлов, такие как FastRP, node2vec и GraphSAGE. Я покажу синтаксис алгоритма FastRP, но, опять же, не буду особо углубляться в оптимизацию гиперпараметров.
CALL gds.fastRP.write({
nodeProjection: 'Character',
relationshipProjection: {
INTERACTS: {
orientation: 'UNDIRECTED'
}
},
embeddingDimension: 64,
writeProperty: 'fastrp'})
Параметр embeddingDimension является обязательным и определяет размер вектора внедрения для каждого узла. Помимо этого, мы снова определили сеть взаимодействия, которая должна рассматриваться как ненаправленная. Наконец, чтобы сравнить результаты моделей внедрения узлов, мы визуализируем график разброса t-SNE вложений.

Теперь давайте опробуем некоторые алгоритмы внедрения узлов в пакете KC. Сначала мы определим функцию, которая будет рисовать диаграмму разброса t-SNE результатов внедрения.
Начнем с алгоритма NetMF. Алгоритм NetMF попадает в категорию встраивания узлов на основе сообщества. Если вы хотите узнать больше о технических деталях, прочтите исходный документ или изучите код.
На этот раз я использовал диаграмму рассеяния Seaborn, чтобы визуализировать результаты t-SNE вложений.

Вложения узлов кажутся совсем другими, чем когда мы использовали алгоритм FastRP. В библиотеке KC также есть алгоритм NEU m. Процедура использует произвольное вложение и дополняет его близостью более высокого порядка с помощью рекурсивного алгоритма метаобучения.
И результат встраивания t-SNE:

Другой категорией алгоритмов внедрения узлов является категория внедрения структурных ролей. Вместо того, чтобы фиксировать сходство между узлами, близкими в сети (соседями), мы хотим зафиксировать сходство между узлами с похожими структурными ролями. Одним из таких алгоритмов является алгоритм Role2Vec.
Значение по умолчанию walk_length равно 80. Учитывая, что наш примерный график имеет только 100+ узлов, я решил использовать меньшее значение walk_length. Помимо этого, есть место для дополнительной настройки гиперпараметров. Результирующий график t-SNE:

Вычисление внедрения узла на основе схожести ролей узла - захватывающая область. Вместо того, чтобы сравнивать близость узлов в сети, мы хотим зафиксировать сходство структурных ролей между узлами. Затем мы можем использовать встраивание структурных ролей, чтобы вывести сеть kNN, и запустить алгоритм обнаружения сообщества, чтобы попытаться сегментировать узлы на основе их сетевых ролей. Во-первых, мы должны сохранить результаты Role2vec обратно в Neo4j.
Алгоритм kNN представлен в библиотеке GDS. Алгоритм K-Nearest Neighbors вычисляет значение расстояния для всех пар узлов в графе и создает новые отношения между каждым узлом и его k ближайшими соседями. Расстояние рассчитывается на основе свойств узла.
Мы воспользуемся преимуществом функции каталога графиков, поскольку мы последовательно запустим два алгоритма построения графиков. Сначала мы сохраняем проекцию сети в виде именованного графа, используя следующий синтаксис:
CALL gds.graph.create('role2vec', 'Character', '*', {nodeProperties:['role2vec']})
Нас не волнуют ненаправленные отношения INTERACTS, поскольку мы не будем их использовать. Важно то, что мы включили вложение узла role2vec в нашу проекцию. Теперь мы можем изменить алгоритм kNN. Используя метод mutate, мы сохраняем результаты алгоритма обратно в спроектированный именованный граф вместо сохраненного графа Neo4j. Таким образом, мы можем использовать результаты алгоритма kNN в качестве входных данных для алгоритма обнаружения сообщества.
CALL gds.beta.knn.mutate('role2vec',
{topK: 5,
nodeWeightProperty:'role2vec',
mutateProperty:'weight',
mutateRelationshipType:'SIMILAR_ROLE'})
Мы будем хранить полученные отношения под типом SIMILAR_ROLE. Один из параметров - topK, который определяет количество соседей, которые нужно найти для каждого узла. Возвращаются K-ближайшие соседи. Наконец, мы можем изучить структуру сообщества полученной сети подобия с помощью алгоритма Лувена.
CALL gds.louvain.write('role2vec',
{relationshipTypes:['SIMILAR_ROLE'],
writeProperty:'louvain_role'})
Конечно, остается очевидное, что нужно сделать - это визуализировать получившуюся сеть подобия и ее структуру сообщества.

Этот пример, в котором я сначала вычислил вложения структурных ролей, а затем вывел сеть подобия с помощью алгоритма kNN, может рассматриваться как первая деривация сети. Вместо использования алгоритма обнаружения сообщества для исследования исходной сетевой структуры мы проверяем структурную сегментацию узлов по ролям. Это может пригодиться в различных сетевых проектах.
Заключение
Пакет Karate Club включает модели встраивания узлов, которые также учитывают свойства узлов. К сожалению, у нас нет никаких свойств узла в нашей простой сети Гарри Поттера, поэтому я пропустил их. Тем не менее, область исследований внедрения узлов интересна, и существует множество подходов к тому, какой тип информации вы хотите извлечь из сети. Надеюсь, эта простая интеграция проекта Neo4j и Karate Club поможет вам использовать модели встраивания узлов, которые подойдут вам лучше всего. Я рекомендую вам открыть экземпляр Neo4j Sandbox и протестировать различные подходы. Дай мне знать, если появится что-нибудь интересное.
Как всегда, код доступен на GitHub.