ДЗ-13: Патерни, тренди та кластеризація
Урок: Урок-13-Патерни-та-кластеризація
Мета і бюджет часу
Мета — пройти на Elliptic++ увесь ланцюжок із заняття і дійти до одного обґрунтованого ліда. Лід — це адреса з двома незалежними сигналами, альтернативним поясненням і рівнем упевненості. Робота індивідуальна, до 90 хвилин.
| Етап | Хв | Результат |
|---|---|---|
| Підготовка | 15 | база Neo4j з Elliptic++, підрахунки збігаються з еталоном |
| 1. Тренд | 10 | графік частки illicit за кроками, 2–3 речення |
| 2. Патерни | 20 | три запити з вашими порогами, до кожного число і висновок |
| 3. Спільноти | 15 | топ-5 спільнот Louvain з lift, кандидат у ліди |
| 4. Gephi | 20 | зображення однієї спільноти, проєкт .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.
- Завантажте з репозиторію 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. - Запустіть Neo4j з APOC і Graph Data Science: у Desktop — Plugins → Install, у Docker — командою зі слайда «Neo4j: встановлення». Для завдання 4 потрібен параметр
apoc.export.file.enabled=true(Desktop — файлconf/apoc.conf, у Docker-команді він уже є). - Розпакуйте Лекція_13_матеріали.zip і підготуйте компактні CSV у папку
importвашої бази:python prep.py <папка_з_csv> <папка_import>(Python 3 з pandas, ≈ 30 с). - Виконайте
01_import.cypher(≈ 5 хв). У Neo4j Browser кожен запит ізCALL … IN TRANSACTIONSзапускайте з префіксом:auto. - Виконайте два останні запити файлу і збережіть знімок екрана з підрахунками.
| Вузли й ребра | Очікувана кількість |
|---|---|
| Transaction | 203 769 |
| Wallet | 822 942 |
| FLOWS_TO | 234 355 |
| INPUT | 477 117 |
| OUTPUT | 837 124 |
| SENT_TO | 2 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;- Завантажте результат як CSV і побудуйте лінійний графік
illicitPctза кроками (Excel, Google Sheets або Python). Позначте на ньому крок 43. - Порахуйте частку illicit для кроків 1–42 і 43–49 через суми
illicitіlabelled, а не як середнє відсотків. - Напишіть 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-гаманців непропорційно багато, і виберіть у першій із них кандидата в ліди.
- Виконайте весь
03_gds.cypher(≈ 3–4 хв). Він запише гаманцям властивостіlouvain,leiden,pagerankіinDeg. - Складіть таблицю топ-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;- Для спільноти з першого рядка знайдіть 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-гаманці.
- Вивантажте спільноту блоком B із
04_export.cypher, замінивши123на свій номер. Якщо експорт не працює, візьміть готовіgephi_nodes.csvіgephi_edges.csvз папкиgephi_demo/. - У Gephi: File → Import spreadsheet →
gephi_nodes.csvяк Nodes table, потімgephi_edges.csvяк Edges table з опцією Append to existing workspace. - Layout → ForceAtlas2 з Approximate Repulsion. Коли граф стабілізується, увімкніть Prevent Overlap.
- Appearance: колір вузлів — Partition за
class, розмір — Ranking заpagerank. - 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. Gephi | 15 | зображення читабельне, кольори й розмір пояснено |
| 5. Висновок | 15 | закрито всі п’ять пунктів, сигнали справді незалежні |
| Разом | 100 |
Самоперевірка
Ці значення отримано на повному Elliptic++. Використовуйте їх, щоб перевірити запити, а не замість власних висновків.
| Перевірка | Значення |
|---|---|
| Частка illicit серед розмічених, кроки 1–42 → 43–49 | 10,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 щоразу дає інші номери спільнот, тому номер із чужого звіту у вашій базі не знайдеться.