AAYMA
RU
Войти

Граф денег

Локальный MVP для AML-анализа сети переводов: эвристические роли узлов, Louvain-кластеры, top-20 приоритетов с объяснениями и Streamlit-панель с…

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

О проекте

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

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

Суть

Локальный MVP для AML-анализа сети переводов: эвристические роли узлов, Louvain-кластеры, top-20 приоритетов с объяснениями и Streamlit-панель с графом потоков и путём от seed.

Как устроено

Пайплайн src.pipeline читает три Parquet, считает признаки потоков (включая быстрый транзит по датам, синхронные и похожие переводы), назначает роли по правилам в порядке consolidator → distributor → coordinator → transit → terminal → peripheral с учётом обрыва на depth 4. priority_score = 0.35·role_score + 0.25·norm(log1p(turnover)) + 0.20·norm(degree) + 0.20·clip(out/in); кластеры — Louvain на неориентированном взвешенном графе (seed 42). Streamlit + Plotly показывают карточки узлов, кратчайший путь от seed и гипотезы кластеров. LLM не используется.

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

  • Louvain
  • NetworkX shortest paths
  • rule-based roles
  • weighted priority formula
  • date-based fast transit features

Метрики

2 248 узлов, 89 кластеров, top-20; пайплайн ~10,57 с

Особенности

Явный учёт обрезки графа на 4-м колене (узел без исходящих на последнем уровне не считается terminal) и неполноты входящих потоков seed; прозрачная формула приоритета.

Стек

Python · pandas · PyArrow · NetworkX · NumPy · Streamlit · Plotly


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

README

README.md

Граф денег

Локальный MVP для первичного анализа обезличенной сети переводов. Помогает AML-аналитику банка исследовать связи известных клиентов, находить структурные признаки консолидации, транзита и распределения средств и выбирать узлы для дальнейшей проверки.

Результаты — аналитические признаки и гипотезы, а не вывод о виновности. В датасете нет персональных атрибутов и подтверждённых меток ролей.

Проблема и решение

По условию кейса аналитик получает список известных клиентов и ограниченную выгрузку их исходящих переводов. Ручное прохождение цепочек занимает время, оставляет значительную часть сети незаметной и затрудняет выбор узлов для проверки.

Проект автоматизирует первичную обработку графа: рассчитывает признаки потоков, присваивает узлам объяснимые эвристические роли, выделяет сообщества, ранжирует кандидатов по приоритету и показывает их в локальной веб-панели. Это даёт аналитику воспроизводимую отправную точку для проверки.

Что реализовано

  • Пайплайн от трёх Parquet-файлов до трёх CSV-выгрузок.
  • Роль, структурный role_score, кластер, приоритет и текстовое evidence для каждого узла.
  • Louvain-кластеризация на взвешенном неориентированном графе.
  • Top-20 узлов с why, ранжированных по priority_score.
  • Streamlit-панель со сводкой сети, top-листом, поиском по gid, карточкой узла, историей видимых транзакций и визуализацией направленных связей.
  • Подсветка найденного кратчайшего направленного пути от seed и просмотр гипотезы выбранного кластера.
  • Учёт обрыва графа на depth 4: узел без исходящих связей на последнем колене автоматически не считается terminal.

В имеющихся выходных файлах: 2 248 узлов, 89 кластеров и top-20. README проекта фиксирует контрольное время пайплайна около 10,57 секунды на использованном ноутбуке; фактическое время зависит от оборудования.

Как работает решение

  1. Аналитик получает Parquet-выгрузку графа и кладёт её в data/.
  2. Команда python -m src.pipeline читает узлы, агрегированные рёбра и отдельные транзакции, считает признаки, роли, приоритеты и кластеры.
  3. Пайплайн сохраняет nodes_roles.csv, clusters.csv и top_nodes.csv в output/.
  4. Аналитик запускает панель, рассматривает top-лист или вводит произвольный gid.
  5. Карточка показывает объяснение роли и приоритета, входящие/исходящие связи и, если он существует в наблюдаемой сети, путь от seed. Кластерная гипотеза помогает сформулировать дальнейшие вопросы для проверки.

Схема обработки: solution-schema.md.

Технологии

  • Python 3.10+.
  • pandas и PyArrow — таблицы и чтение Parquet.
  • NetworkX — графовые метрики, кратчайшие пути и Louvain-кластеризация.
  • NumPy — численные расчёты.
  • Streamlit — локальный веб-интерфейс.
  • Plotly — графики и визуализация потоков/связей.

В проекте не используются обученные AI/ML-модели, LLM API или внешние сервисы. Роли и приоритет рассчитываются локальными детерминированными правилами. Интернет нужен только для установки Python-зависимостей, если их ещё нет в окружении.

Архитектура проекта

data/*.parquet
     │
     ▼
src/analytics.py ── признаки узлов и эвристические роли
     │
     ▼
src/pipeline.py ─── приоритеты, Louvain-кластеры, объяснения
     │
     ├── output/nodes_roles.csv
     ├── output/clusters.csv
     └── output/top_nodes.csv
                │
                ▼
       src/app.py (Streamlit + Plotly)
                │
                ▼
     поиск, карточки, граф потоков

Корневой app.py — точка запуска Streamlit, которая передаёт управление src/app.py. streamlit_app.py — альтернативная точка входа. Пайплайн загружается как Python-модуль src.pipeline.

Установка и запуск

Требуются файлы data/nodes.parquet, data/edges.parquet, data/transactions.parquet. Запускайте команды из корня репозитория:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python -m src.pipeline
streamlit run app.py

Откройте http://localhost:8501. Для остановки нажмите Ctrl+C.

Чтобы обработать файлы из другого каталога или сохранить результат отдельно:

python -m src.pipeline --data-dir /path/to/data --output-dir /path/to/output

Панель по умолчанию читает data/ и output/ относительно корня проекта. Пакеты перечислены в requirements.txt.

Как проверить решение

Повторяемый сценарий для жюри:

  1. Убедиться, что три входных файла находятся в data/.
  2. Выполнить команды установки и запуска пайплайна из раздела выше.
  3. Проверить, что в output/ появились три CSV. В nodes_roles.csv ожидаются колонки gid, role, role_score, cluster_id, priority_score, evidence; в clusters.csv — cluster_id, n_nodes, n_seed, sum_kzt_internal, top_gids, hypothesis; в top_nodes.csv — rank, gid, role, priority_score, why.
  4. Запустить панель и открыть http://localhost:8501.
  5. Выбрать узел из top-20 и проследить его карточку, направление потоков и путь от seed, если путь найден.
  6. Ввести другой gid из nodes_roles.csv, включая узел без рёбер, и посмотреть его роль, evidence и кластер.

Пайплайн содержит проверки полноты выходных строк, уникальности gid, заполненности обязательных полей, диапазона score и сортировки top-листа.

Данные и интеграции

Проект использует только локальную обезличенную выгрузку из data/, внешние источники и интеграции не подключены.

ФайлСодержание
nodes.parquetgid, минимальная глубина depth, признак seed is_seed.
edges.parquetНаправленная агрегированная пара src → dst, сумма sum_kzt, количество переводов n_tx, глубина ребра.
transactions.parquetОтдельные операции: src, dst, дата и сумма.

По описанию предоставленного датасета: июль 2026 года, 81 seed-клиент, обход исходящих переводов до четырёх колен, порог 5 000 KZT, 2 248 узлов, 3 119 агрегированных рёбер и 4 840 транзакций. Подробности схемы находятся в README_DATASET.md.

Аналитические критерии

Каждому узлу назначается одна роль по первому подходящему правилу в порядке consolidator → distributor → coordinator → transit → terminal → peripheral.

РольЭвристическое правило
consolidatorНе seed; минимум 2 входящих ребра; входящая сумма ≥ 1,25 × исходящей. Seed исключены из-за неполноты входящих потоков.
distributorМинимум 2 исходящих ребра; исходящая сумма ≥ 1,25 × входящей.
coordinatorМинимум 4 инцидентных ребра, есть входящее и исходящее.
transitЕсть входящее и исходящее; отношение исходящей суммы к входящей от 0,5 до 2 (или входящая сумма нулевая).
terminalЕсть входящее, нет исходящего, глубина меньше 4 или неизвестна.
peripheralИные случаи, в том числе узлы без рёбер и обрезанные на depth 4.

role_score показывает выраженность структурных признаков по фиксированной формуле в диапазоне 0–1; это не вероятность. priority_score рассчитывается как 0.35 × role_score + 0.25 × norm(log1p(turnover)) + 0.20 × norm(in_degree + out_degree) + 0.20 × clip(out_amount / in_amount, 0, 1). Нормализация использует максимум соответствующей метрики в текущем наборе; при нулевой входящей сумме отношение принимается за 0.

Кластеры строятся алгоритмом Louvain на неориентированном представлении графа с весом sum_kzt и фиксированным seed 42. Направленность используется в анализе потоков и путей. Текстовые evidence, why и гипотезы — объяснение наблюдаемых признаков, а не подтверждение умысла.

Ограничения

  • Граф обрывается на четырёх переходах; исходящие связи дальше не наблюдаются.
  • Граф собран обходом исходящих переводов seed; их входящие суммы неполны.
  • Переводы меньше 5 000 KZT отсутствуют. Нет данных о балансах, ФИО, типах операций и иных атрибутах клиента.
  • Размеченных истинных ролей нет, поэтому точность правил и приоритетного рейтинга по ground truth не оценивалась. Приоритет относителен к текущей выгрузке.
  • «Быстрый транзит» оценивается по датам отдельных операций; одинаковая дата не позволяет восстановить точный порядок или отследить те же деньги.
  • На последнем колене отсутствие исходящих связей может быть эффектом обрезки, а не признаком конечного получателя.
  • Визуализация показывает выбранную окрестность и ключевые узлы кластера для читаемости, не полный граф или полный состав каждого сообщества.
  • Реализация рассчитана на датасет кейса. Для масштаба около миллиона узлов понадобятся индексированное хранилище рёбер/признаков, пакетный пересчёт метрик и серверная выдача ограниченной окрестности вместо загрузки всего графа в интерфейс.

Развёрнутая версия

Опубликовать приложение можно бесплатно в Streamlit Community Cloud:

  1. Загрузите репозиторий в GitHub. В репозитории должны быть app.py, src/, requirements.txt, а также каталоги data/ и output/ с входными Parquet-файлами и готовыми CSV-результатами. При каждом новом деплое приложение читает эти файлы из репозитория; пайплайн автоматически при старте не запускается.
  2. Войдите на share.streamlit.io через GitHub и нажмите Create app.
  3. Выберите репозиторий, ветку и главный файл app.py в корне репозитория, затем нажмите Deploy.
  4. После сборки откройте выданный Streamlit URL и проверьте, что отображаются сводка, top-20 и карточка узла.

Если обновились исходные данные, сначала локально выполните python -m src.pipeline, затем добавьте в GitHub новые файлы из output/ и передеплойте приложение. Дополнительные секреты и переменные окружения не требуются. Учитывайте, что файлы в GitHub доступны тем, у кого есть доступ к репозиторию; публикуйте только данные, которые разрешено размещать в выбранном репозитории.

Звёзды
⭐ 1
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
31
Авторы
3
Файлы
26
Ветки
6

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

lackoftalentt 13Bakdaulet Yelubek 13Your Name 5

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

  • 2026-09-23 17:51Document Streamlit deploymentlackoftalentt
  • 2026-09-23 17:13Merge remote-tracking branch 'origin/main'lackoftalentt
  • 2026-09-23 17:12docs: finalize project readmeslackoftalentt
  • 2026-09-23 17:07Merge pull request #2 from BAITC-Hacks/feature/rolesBeybarys
  • 2026-09-23 17:03added README_MVPlackoftalentt
  • 2026-09-23 16:28Merge remote-tracking branch 'origin/integration/final' into feature/roleslackoftalentt
  • 2026-09-23 16:22Polish gid labels and cluster metricsBakdaulet Yelubek
  • 2026-09-23 16:22Add flow-first analyst visualizationBakdaulet Yelubek
Все коммиты (31)
  • 2026-09-23 16:16Strengthen analyst dashboard viewsBakdaulet Yelubek
  • 2026-09-23 16:10Merge remote-tracking branch 'origin/integration/final' into feature/roleslackoftalentt
  • 2026-09-23 16:10Integrate latest analyst dashboardBakdaulet Yelubek
  • 2026-09-23 15:58Add graph zoom and richer hover detailsYour Name
  • 2026-09-23 15:56Clarify the solution flow diagramYour Name
  • 2026-09-23 15:55Improve analyst dashboard and path viewYour Name
  • 2026-09-23 15:41Complete analyst dashboard frontendYour Name
  • 2026-09-23 15:41Clarify date-level transit evidencelackoftalentt
  • 2026-09-23 15:39Clarify missing seed path explanationBakdaulet Yelubek
  • 2026-09-23 15:34Complete AML dashboard documentation and polishBakdaulet Yelubek
  • 2026-09-23 15:32Improve priority explanations in dashboardBakdaulet Yelubek
  • 2026-09-23 15:30Add analyst priority review listBakdaulet Yelubek
  • 2026-09-23 15:28Normalize large gids in dashboard graphBakdaulet Yelubek
  • 2026-09-23 15:22Merge remote-tracking branch 'origin/feature/ui' into feature/pipelineBakdaulet Yelubek
  • 2026-09-23 15:20Add local money graph dashboardYour Name
  • 2026-09-23 15:18Add synchronous and similar transfer featureslackoftalentt
  • 2026-09-23 15:10Explain seed paths and cluster resilienceBakdaulet Yelubek
  • 2026-09-23 15:07Merge remote-tracking branch 'origin/feature/pipeline' into feature/beibarys-analyticslackoftalentt
  • 2026-09-23 15:01Add date-based fast transit featureslackoftalentt
  • 2026-09-23 14:57Build reproducible graph exports pipelineBakdaulet Yelubek
  • 2026-09-23 14:55Merge remote-tracking branch 'origin/feature/beibarys-analytics' into feature/pipelineBakdaulet Yelubek
  • 2026-09-23 14:51feature/analyticslackoftalentt
  • 2026-09-23 13:58first commitlackoftalentt
Структура репозитория (26 файлов)
.gitignore
README.md
README_DATASET.md
README_MVP.md
__MACOSX/starter/._README.md
__MACOSX/starter/._requirements.txt
__MACOSX/starter/._starter.py
app.py
data.zip
data/edges.parquet
data/nodes.parquet
data/transactions.parquet
dataset.md
output/clusters.csv
output/nodes_roles.csv
output/top_nodes.csv
requirements.txt
solution-schema.md
src/analytics.py
src/app.py
src/pipeline.py
starter.zip
starter/README.md
starter/requirements.txt
starter/starter.py
streamlit_app.py
Ветки (6)

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

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

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