О проекте
Команда: 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 секунды на использованном ноутбуке; фактическое время зависит от оборудования.
Как работает решение
- Аналитик получает Parquet-выгрузку графа и кладёт её в
data/. - Команда
python -m src.pipelineчитает узлы, агрегированные рёбра и отдельные транзакции, считает признаки, роли, приоритеты и кластеры. - Пайплайн сохраняет
nodes_roles.csv,clusters.csvиtop_nodes.csvвoutput/. - Аналитик запускает панель, рассматривает top-лист или вводит произвольный
gid. - Карточка показывает объяснение роли и приоритета, входящие/исходящие связи и, если он существует в наблюдаемой сети, путь от 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.
Как проверить решение
Повторяемый сценарий для жюри:
- Убедиться, что три входных файла находятся в
data/. - Выполнить команды установки и запуска пайплайна из раздела выше.
- Проверить, что в
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. - Запустить панель и открыть
http://localhost:8501. - Выбрать узел из top-20 и проследить его карточку, направление потоков и путь от seed, если путь найден.
- Ввести другой
gidизnodes_roles.csv, включая узел без рёбер, и посмотреть его роль, evidence и кластер.
Пайплайн содержит проверки полноты выходных строк, уникальности gid, заполненности обязательных полей, диапазона score и сортировки top-листа.
Данные и интеграции
Проект использует только локальную обезличенную выгрузку из data/, внешние источники и интеграции не подключены.
| Файл | Содержание |
|---|---|
nodes.parquet | gid, минимальная глубина 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:
- Загрузите репозиторий в GitHub. В репозитории должны быть
app.py,src/,requirements.txt, а также каталогиdata/иoutput/с входными Parquet-файлами и готовыми CSV-результатами. При каждом новом деплое приложение читает эти файлы из репозитория; пайплайн автоматически при старте не запускается. - Войдите на share.streamlit.io через GitHub и нажмите Create app.
- Выберите репозиторий, ветку и главный файл
app.pyв корне репозитория, затем нажмите Deploy. - После сборки откройте выданный Streamlit URL и проверьте, что отображаются сводка, top-20 и карточка узла.
Если обновились исходные данные, сначала локально выполните python -m src.pipeline, затем добавьте в GitHub новые файлы из output/ и передеплойте приложение. Дополнительные секреты и переменные окружения не требуются. Учитывайте, что файлы в GitHub доступны тем, у кого есть доступ к репозиторию; публикуйте только данные, которые разрешено размещать в выбранном репозитории.
Авторы коммитов
История коммитов
- 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
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.