AAYMA
RU
Войти

Граф денег

Пайплайн AML-анализа транзакционной сети: роли и priority_score для 2248 узлов, кластеры, SAR-нарративы, анализ устойчивости сети и одностраничный…

Рабочий MVP
Команда «Pixie» 7💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: Pixie
Кейс HackAlem.ai: Финансы — Freedom
Стадия: Рабочий MVP

Задача кейса: «Граф денег»: восстановить структуру организованной группы по сети транзакций (AML)

Суть

Пайплайн AML-анализа транзакционной сети: роли и priority_score для 2248 узлов, кластеры, SAR-нарративы, анализ устойчивости сети и одностраничный граф-вьюер с AI-ассистентом.

Как устроено

main.py загружает edges/nodes/transactions.parquet, строит граф NetworkX, считает метрики узлов, кластеризует сеть Louvain (python-louvain), по правилам и порогам присваивает роли (consolidator, transit, distributor, terminal, coordinator, peripheral) и priority_score. Затем выгружает обязательные CSV, рёбра с признаком in_cycle, SAR-нарративы по топ-узлам и Key Player disruption-анализ (падение наибольшей компоненты при изъятии топ-N узлов). graph_viewer.html на Cytoscape.js показывает граф, кластеры и кривую устойчивости. «Спросить граф» — LLM-ассистент через OpenRouter поверх top_nodes и clusters с ключом пользователя.

Ключевые решения

  • NetworkX
  • Louvain (python-louvain)
  • rule-based роли
  • детекция циклов
  • Key Player disruption analysis (Borgatti 2006)
  • SAR-нарративы

Особенности

Анализ устойчивости сети по Borgatti показывает, как распадается сеть при изъятии приоритетных узлов. Готовые SAR-нарративы для запроса в правоохранительные органы. Подробно разобраны ограничения данных, например обрыв на 4-м колене и занижение входящих сумм у seed-клиентов.

Стек

Python · pandas · NetworkX · python-louvain · Cytoscape.js · PapaParse · HTML/JS

Модели

OpenRouter


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-78e8e63e-pixie.

README

README.md

hack-78e8e63e-pixie

Hackathon team repository for Pixie

Граф денег: восстановление финансовой структуры организованной группы по транзакционной сети

HackAlem AI · направление "Финансы"


1. Проблема

AML-аналитику банка второго уровня известен только нижний уровень цепочки — 81 клиент, ранее выявленный как участник незаконного оборота наркотиков. Кто стоит выше — кто собирает эти деньги, через кого их прогоняют и кто ими распоряжается — до сих пор приходится восстанавливать вручную, трассируя каждый узел на 4 колена.

Реальная сеть вокруг этих 81 клиента — 2 248 узлов. Инструмент строит по ней граф, присваивает каждому узлу роль и приоритет проверки и отвечает на вопрос аналитика: «кого из этих 2 248 клиентов смотреть первым и почему».

Формулировки инструмента — это гипотезы для проверки («признаки консолидации», «кандидат в координаторы»), а не утверждения о виновности. Итоговые материалы предназначены для внутренней приоритизации и последующего запроса в правоохранительные органы, а не для самостоятельных выводов о причастности.

2. Быстрый старт

pip install -r requirements.txt   # pandas, networkx, python-louvain и т.п. — см. main.py
python main.py

Пайплайн:

  1. Загрузка данных (edges.parquet, nodes.parquet, transactions.parquet)
  2. Построение графа
  3. Расчёт метрик для узлов
  4. Кластеризация сети
  5. Определение ролей и расчёт priority_score
  6. Сохранение обязательных выгрузок в CSV
  7. Экспорт рёбер для визуализации
  8. Генерация SAR-нарративов для топ-узлов
  9. Анализ устойчивости сети (Key Player disruption)

Полный пересчёт от сырых .parquet до всех выгрузок укладывается в < 5 минут (ограничение ТЗ) без ручных шагов.

По завершении поднимается локальный сервер с экраном просмотра:

Дэшборд: http://localhost:8765/graph_viewer.html
Ctrl+C — остановить сервер.

Открыть можно и напрямую как файл (graph_viewer.html подхватит CSV/JSON из той же папки автоматически; если запуск не через python main.py, а просто открытием файла — можно догрузить те же файлы вручную кнопками в шапке).

3. Входные данные

ФайлСтрокСодержание
edges.parquet3 119плательщик→получатель, агрегировано за период: src, dst, sum_kzt, n_tx, depth
nodes.parquet2 248уникальный клиент: gid, depth, is_seed
transactions.parquet4 840отдельная транзакция: src, dst, date, sum_kzt

Период: 2026-07-01 — 2026-07-31. Только исходящие переводы от 81 seed-клиента, глубина обхода — 4 колена, порог отсечения — переводы < 5 000 KZT. Суммарный оборот в графе: 365 890 012 KZT. Данные обезличены: gid — синтетический идентификатор без привязки к личности.

4. Выходные файлы

nodes_roles.csv — 2 248 строк, по одной на узел

КолонкаТипСмысл
gidint64идентификатор клиента
rolestrроль из словаря (см. ниже)
role_scorefloatуверенность в роли, 0–1
cluster_idintномер кластера
priority_scorefloatприоритет для аналитика, 0–1
evidencestrпочему присвоена роль, до 200 символов, человекочитаемо

Словарь ролей

РольСмысл
consolidatorточка консолидации — аккумулирует средства от нескольких участников
transitтранзитный счёт — пропускает средства дальше, не удерживая
distributorвеерное распределение средств на много получателей
terminalконечный получатель — деньги приходят и остаются
coordinatorкоординирующий узел, кандидат в организаторы
peripheralпериферия, признаков роли не выявлено

Фактическое распределение по последнему прогону:

peripheral      1625
terminal         444
distributor      104
coordinator       45
consolidator      29
transit            1

clusters.csv — по одной строке на кластер

cluster_id, n_nodes, n_seed, sum_kzt_internal, top_gids, hypothesis

top_nodes.csv — ранжированный список ≥ 20 узлов

rank, gid, role, priority_score, why

Дополнительные выгрузки (сверх обязательного минимума)

ФайлНазначение
edges_export.csvрёбра для визуализации в graph_viewer.html, включая признак in_cycle
sar_narratives.jsonразвёрнутый нарратив по топ-узлам для материалов на запрос в правоохранительные органы (см. п. 6)
network_resilience.csvрезультат disruption-анализа: removed_top_k, largest_component_size, largest_component_pct, n_components

5. Экран просмотра — graph_viewer.html

Одностраничное приложение (Cytoscape.js + PapaParse), без сборки и бэкенда; читает CSV/JSON из той же папки при открытии через python main.py, либо файлы можно догрузить вручную кнопками в шапке.

Вкладки:

  • Граф — схема сети: цвет узла = роль, размер = priority_score, толщина ребра = оборот; циклы переводов (in_cycle) выделены красным и пульсирующим свечением вместе со всеми узлами priority_score ≥ 0.75. Наведение показывает тултип (роль, score, кластер) без клика; клик открывает карточку узла справа и центрирует граф. Поиск по gid, фильтр по кластеру и ролям, переключение «топ-200 / вся сеть».
  • Обзор — KPI (узлов, связей, оборот KZT, seed-клиентов, кластеров, узлов на проверку) + распределение ролей.
  • Кластеры — таблица с гипотезами; клик по строке переключает на «Граф» с фильтром по этому кластеру.
  • Устойчивость — кривая disruption-анализа (методика Borgatti, 2006): как падает размер наибольшей компоненты сети при изъятии топ-N узлов по приоритету.

Рабочие функции, а не только просмотр:

  • «📋 копировать SAR» в карточке узла — копирует готовый нарратив в буфер обмена.
  • «⬇ экспорт отчёта» — выгружает топ-30 узлов с нарративами в .txt, готовый текст для передачи в подразделение.
  • «🤖 Спросить граф» — AI-ассистент поверх top_nodes.csv/clusters.csv: вопрос на естественном языке → ответ со ссылками на конкретные gid из данных, без домыслов. Требует собственный API-ключ OpenRouter, вводимый пользователем локально в браузере — ключ никуда, кроме OpenRouter, не отправляется и не сохраняется на сервере.

6. Соответствие критериям ТЗ (must have)

№КритерийСтатус
1Воспроизводимый пайплайн, один запуск, < 5 минутpython main.py создаёт все выгрузки без ручных шагов
2Роль, role_score, evidence у всех 2 248 узловnodes_roles.csv, все колонки заполнены
3Критерии ролей задокументированы и объяснимыформальные правила/пороги — см. main.py / раздел «Методология»
4Кластеризация сетиclusters.csv + cluster_id у каждого узла в nodes_roles.csv
5Топ-лист приоритетов + визуализация направления потоков и ролейtop_nodes.csv (≥ 20 узлов) + вкладка «Граф»

Реализованные опциональные пункты: оценка устойчивости сети (disruption-анализ), AI-ассистент аналитика, автогенерация карточки узла с нарративом.

Не реализовано в текущей версии (см. «Дальнейшие шаги»): временные паттерны из transactions.parquet (синхронные переводы от нескольких плательщиков в один день, сквозной транзит за 1–2 дня), явное отделение настоящих конечных получателей от артефакта обрыва графа на 4-м колене, автоматический отчёт о полноте данных.

7. Известные ограничения данных (объявлены в ТЗ, учтены при интерпретации)

  • Обрыв на 4-м колене: 444 узла с out_degree = 0 на depth = 4 — это артефакт обхода, а не обязательно «деньги осели»; наивная интерпретация даёт 444 ложных «стока».
  • Только исходящие переводы: входящие потоки на узлы за пределами выборки не видны, полный баланс узла посчитать нельзя.
  • У seed-клиентов входящие суммы занижены (граф собран от них): 354 узла в графе формально «отдают» больше, чем «получили» по имеющимся данным.
  • Порог 5 000 KZT — дробление сумм ниже порога в данных не видно.
  • 19 из 81 seed отсутствуют в рёбрах, ещё 12 — только как получатели; 31 seed не имеет исходящих переводов.
  • 16 слабосвязных компонент: 1 877 узлов (46 seed) в крупнейшей, 352 узла — вне неё.
  • Нет атрибутов клиента (ФИО, тип операции, остатки) — только структура и суммы.
  • Нет размеченных ролей (ground truth) — оценка велась по обоснованности критериев, не по accuracy.

8. Дальнейшие шаги

  • Временные паттерны по transactions.parquet: синхронные переводы от 5+ плательщиков в один день, сквозной транзит «пришло и ушло за 1–2 дня» — сильный сигнал, которого сейчас нет в пайплайне; код небольшой, данные уже загружаются.
  • Автоотчёт о полноте данных: вывод раздела 7 этого README в машиночитаемом виде (какие 19/81 seed без исходящих, 352 узла вне главной компоненты и т.д.) — прямое попадание в критерий «Ценность и применимость».
  • Явная маркировка узлов, «обрезанных» артефактом 4-го колена, отдельно от настоящих конечных получателей.

9. Приватность и назначение данных

Данные обезличены (gid — синтетический идентификатор без привязки к личности) и предоставлены исключительно для использования в рамках хакатона. Инструмент не делает и не должен использоваться для вынесения выводов о виновности — только для приоритизации внутренней проверки и формирования материалов на запрос в правоохранительные органы.

Звёзды
⭐ 0
Форки
0
Язык
HTML
Последний push
в прошлом месяце
Коммиты
5
Авторы
2
Файлы
13
Ветки
1

Авторы коммитов

Aruzhan-kenshbaeva 4marzhanaa 1

История коммитов

  • 2026-09-23 17:48Update README.mdmarzhanaa
  • 2026-09-23 17:40Expand README with project details and instructionsAruzhan-kenshbaeva
  • 2026-09-23 17:38прокAruzhan-kenshbaeva
  • 2026-09-23 17:36проAruzhan-kenshbaeva
  • 2026-09-23 15:06Add files via uploadAruzhan-kenshbaeva
Структура репозитория (13 файлов)
README.md
про/clusters.csv
про/data/edges.parquet
про/data/nodes.parquet
про/data/transactions.parquet
про/edges_export.csv
про/graph_viewer.html
про/main.py
про/network_resilience.csv
про/nodes_roles.csv
про/requirements.txt
про/sar_narratives.json
про/top_nodes.csv

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.