ДЗ-13: Патерни, тренди та кластеризація

Усі завдання · Урок

Урок: Урок-13-Патерни-та-кластеризація

Мета і бюджет часу

Мета — пройти на Elliptic++ увесь ланцюжок із заняття і дійти до одного обґрунтованого ліда. Лід — це адреса з двома незалежними сигналами, альтернативним поясненням і рівнем упевненості. Робота індивідуальна, до 90 хвилин.

ЕтапХвРезультат
Підготовка15база Neo4j з Elliptic++, підрахунки збігаються з еталоном
1. Тренд10графік частки illicit за кроками, 2–3 речення
2. Патерни20три запити з вашими порогами, до кожного число і висновок
3. Спільноти15топ-5 спільнот Louvain з lift, кандидат у ліди
4. Gephi20зображення однієї спільноти, проєкт .gephi
5. Висновок10до 300 слів про один лід
Разом90

Знадобляться ноутбук із 8 ГБ RAM і ≈ 6 ГБ вільного місця, Neo4j 2026.10 з APOC і Graph Data Science, Gephi 0.11 та архів Лекція_13_матеріали.zip (prep.py, *.cypher, gephi_demo/). CSV Elliptic++ (≈ 1,5 ГБ) завантажте заздалегідь — у 90 хвилин це не входить.

Підготовка

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

  1. Завантажте з репозиторію Elliptic++ (посилання на Google Drive — у README) вісім файлів: txs_features.csv, txs_classes.csv, txs_edgelist.csv, wallets_features.csv, wallets_classes.csv, AddrAddr_edgelist.csv, AddrTx_edgelist.csv, TxAddr_edgelist.csv.
  2. Запустіть Neo4j з APOC і Graph Data Science: у Desktop — Plugins → Install, у Docker — командою зі слайда «Neo4j: встановлення». Для завдання 4 потрібен параметр apoc.export.file.enabled=true (Desktop — файл conf/apoc.conf, у Docker-команді він уже є).
  3. Розпакуйте Лекція_13_матеріали.zip і підготуйте компактні CSV у папку import вашої бази: python prep.py <папка_з_csv> <папка_import> (Python 3 з pandas, ≈ 30 с).
  4. Виконайте 01_import.cypher (≈ 5 хв). У Neo4j Browser кожен запит із CALL … IN TRANSACTIONS запускайте з префіксом :auto.
  5. Виконайте два останні запити файлу і збережіть знімок екрана з підрахунками.
Вузли й ребраОчікувана кількість
Transaction203 769
Wallet822 942
FLOWS_TO234 355
INPUT477 117
OUTPUT837 124
SENT_TO2 775 637

Інші числа майже завжди означають, що prep.py прочитав не ті файли або імпорт перервався. Створіть нову базу і повторіть кроки 3–4.

Завдання 1. Тренд · 10 хв

Покажіть, як змінюється частка illicit серед розмічених транзакцій за 49 кроками, і поясніть, що відбувається після кроку 43.

MATCH (t:Transaction) WHERE t.class IN [1, 2]
WITH t.timeStep AS step,
     count(CASE WHEN t.class = 1 THEN 1 END) AS illicit,
     count(*) AS labelled
RETURN step, illicit, labelled,
       round(100.0 * illicit / labelled, 1) AS illicitPct
ORDER BY step;
  1. Завантажте результат як CSV і побудуйте лінійний графік illicitPct за кроками (Excel, Google Sheets або Python). Позначте на ньому крок 43.
  2. Порахуйте частку illicit для кроків 1–42 і 43–49 через суми illicit і labelled, а не як середнє відсотків.
  3. Напишіть 2–3 речення: що змінилося і яке є альтернативне пояснення, крім «злочинців стало менше».

Завдання 2. Патерни · 20 хв

Перевірте три патерни з заняття. До кожного дайте одне число й одне речення висновку.

2.1. Fan-in. Поріг визначте через перцентиль, а не «на око»:

MATCH (w:Wallet)
WITH COUNT { (w)<-[:SENT_TO]-() } AS senders
RETURN percentileDisc(senders, 0.99) AS p99,
       percentileDisc(senders, 0.999) AS p999,
       max(senders) AS max;

Підставте p99.9 як поріг і порахуйте класи гаманців, які його перевищують:

MATCH (w:Wallet)
WITH w, COUNT { (w)<-[:SENT_TO]-() } AS senders
WHERE senders >= 100   // ваш поріг
RETURN w.class AS class, count(*) AS wallets
ORDER BY class;

Порівняйте частку illicit серед цих гаманців із базовою (1,7 %). Чи є fan-in сам по собі ознакою злочинної активності?

2.2. Peel chain. Порахуйте illicit-транзакції, з яких починається ланцюжок із 5 переходів:

MATCH p = (s:Transaction {class: 1})-[:FLOWS_TO*5]->(:Transaction)
WHERE all(t IN nodes(p) WHERE t.nOut = 2 AND t.outMin < 0.1 * t.outMax)
RETURN count(DISTINCT s) AS starts;

Замініть 0.1 на 0.05. Наскільки зменшилася кількість і що це каже про форму ланцюжків?

2.3. Експозиція. Знайдіть три unknown-гаманці, до яких за 1–2 кроки надходили кошти від найбільшої кількості illicit-гаманців (запит може виконуватися до хвилини):

MATCH (i:Wallet {class: 1})-[:SENT_TO*1..2]->(u:Wallet {class: 3})
WITH u, count(DISTINCT i) AS exposure
RETURN u.address AS address, exposure
ORDER BY exposure DESC LIMIT 3;

Для першої адреси подивіться прямих відправників: MATCH (x:Wallet)-[:SENT_TO]->(:Wallet {address: '…'}) RETURN x.address, x.class;. Висока експозиція, що йде через одного відправника, — сильний чи слабкий сигнал?

Завдання 3. Спільноти · 15 хв

Знайдіть спільноти Louvain, де illicit-гаманців непропорційно багато, і виберіть у першій із них кандидата в ліди.

  1. Виконайте весь 03_gds.cypher (≈ 3–4 хв). Він запише гаманцям властивості louvain, leiden, pagerank і inDeg.
  2. Складіть таблицю топ-5 спільнот за часткою illicit. Lift показує, у скільки разів ця частка вища за базову (1,7 %):
MATCH (w:Wallet)
WITH count(*) AS total, count(CASE WHEN w.class = 1 THEN 1 END) AS totalIllicit
MATCH (w:Wallet)
WITH 1.0 * totalIllicit / total AS base, w.louvain AS community, count(*) AS size,
     count(CASE WHEN w.class = 1 THEN 1 END) AS illicit
WHERE size >= 20
RETURN community, size, illicit,
       round(100.0 * illicit / size, 1) AS illicitPct,
       round(illicit / (size * base), 1) AS lift
ORDER BY illicitPct DESC LIMIT 5;
  1. Для спільноти з першого рядка знайдіть unknown-гаманці з найвищим PageRank — це кандидати в ліди:
MATCH (u:Wallet {louvain: 123, class: 3})   // 123 → номер вашої спільноти
RETURN u.address AS lead, round(u.pagerank, 2) AS pagerank, u.inDeg AS senders
ORDER BY pagerank DESC LIMIT 3;

У кожному запуску Louvain номери спільнот різні, тому беріть номер зі своєї таблиці.

Завдання 4. Gephi · 20 хв

Зробіть одне читабельне зображення спільноти із завдання 3, на якому видно, де розташовані illicit-гаманці.

  1. Вивантажте спільноту блоком B із 04_export.cypher, замінивши 123 на свій номер. Якщо експорт не працює, візьміть готові gephi_nodes.csv і gephi_edges.csv з папки gephi_demo/.
  2. У Gephi: File → Import spreadsheet → gephi_nodes.csv як Nodes table, потім gephi_edges.csv як Edges table з опцією Append to existing workspace.
  3. Layout → ForceAtlas2 з Approximate Repulsion. Коли граф стабілізується, увімкніть Prevent Overlap.
  4. Appearance: колір вузлів — Partition за class, розмір — Ranking за pagerank.
  5. Preview → Export у PNG або SVG, потім File → Save project у .gephi.

Під зображенням одним реченням поясніть кольори й розмір вузлів. Друге речення — відповідь: illicit-гаманці утворюють окреме скупчення чи розкидані по спільноті?

Завдання 5. Висновок · 10 хв

Напишіть до 300 слів про один лід — адресу із завдання 2.3 або 3. Висновок має закрити п’ять пунктів:

  • Лід: адреса і чому обрано саме її.
  • Два незалежні сигнали: наприклад, експозиція і спільнота. Сигнали незалежні, якщо один не випливає з іншого.
  • Альтернативне пояснення: біржа, платіжний сервіс, міксер, помилка розмітки.
  • Рівень упевненості: низький, помірний чи високий — і чому.
  • Наступний крок: що перевірити поза датасетом (block explorer, відкриті атрибуції адрес).

Що здати

Один архів Прізвище_Ім'я_ДЗ13.zip:

  • report.pdf — відповіді на завдання 1–3 (графік тренду, числа, таблиця спільнот) і висновок;
  • queries.cypher — усі запити з вашими порогами й номером спільноти;
  • community.png або community.svg і community.gephi — результат завдання 4;
  • import.png — знімок екрана з підрахунками з підготовки.

Критерії оцінювання

Зараховано від 60 балів зі 100.

ЗавданняБалиПовний бал, якщо
Підготовка5підрахунки на знімку збігаються з еталоном
1. Тренд15графік із позначеним кроком 43, дві частки, альтернативне пояснення
2. Патерни30три запити виконано, поріг fan-in обґрунтовано, до кожного патерну є висновок
3. Спільноти20таблиця топ-5 з lift, обрано кандидата в ліди
4. Gephi15зображення читабельне, кольори й розмір пояснено
5. Висновок15закрито всі п’ять пунктів, сигнали справді незалежні
Разом100

Самоперевірка

Ці значення отримано на повному Elliptic++. Використовуйте їх, щоб перевірити запити, а не замість власних висновків.

ПеревіркаЗначення
Частка illicit серед розмічених, кроки 1–42 → 43–4910,97 % → 2,53 %
Fan-in: p99 / p99.9 / максимум відправників46 / 103 / 11 213
Peel chain, поріг 0,1: illicit-стартів366
Найбільша експозиція unknown-гаманця1 061
Louvain: кількість спільнот / модулярність≈ 410–450 / ≈ 0,93
Найвища частка illicit у спільноті від 20 гаманців28,2 %, lift 16,3 (у нашому запуску)

Типові помилки:

  • Запит із CALL … IN TRANSACTIONS у Neo4j Browser без префікса :auto завершується помилкою.
  • Експорт APOC не працює без apoc.export.file.enabled=true. У такому разі беріть файли з gephi_demo/.
  • Louvain щоразу дає інші номери спільнот, тому номер із чужого звіту у вашій базі не знайдеться.