Повний посібник із ієрархічної кластеризації за допомогою Python і Scikit-Learn PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Повний посібник з ієрархічної кластеризації за допомогою Python і Scikit-Learn

Вступ

У цьому посібнику ми зосередимося на реалізації Алгоритм ієрархічної кластеризації з Scikit-Learn вирішити маркетингову проблему.

Прочитавши посібник, ви зрозумієте:

  • Коли застосовувати ієрархічну кластеризацію
  • Як візуалізувати набір даних, щоб зрозуміти, чи придатний він для кластеризації
  • Як попередньо обробити функції та створити нові функції на основі набору даних
  • Як зменшити розмірність набору даних за допомогою PCA
  • Як використовувати та читати дендрограмму на окремі групи
  • Які різні методи зв’язування та метрики відстані застосовуються до дендрограм і алгоритмів кластеризації
  • Що таке стратегії агломераційної та роздільної кластеризації та як вони працюють
  • Як реалізувати агломеративну ієрархічну кластеризацію за допомогою Scikit-Learn
  • Які проблеми найчастіше виникають при роботі з алгоритмами кластеризації та як їх вирішити

Примітка: Ви можете завантажити блокнот, який містить увесь код у цьому посібнику тут.

мотивація

Уявіть собі сценарій, у якому ви є частиною команди обробки даних, яка взаємодіє з відділом маркетингу. Маркетинг вже деякий час збирає дані про покупки клієнтів, і вони хочуть зрозуміти на основі зібраних даних, чи є подібності між клієнтами. Ці подібності поділяють клієнтів на групи, а наявність груп клієнтів допомагає в націлюванні кампаній, рекламних акціях, конверсіях і створенні кращих стосунків з клієнтами.

Чи можна якось допомогти визначити, які клієнти схожі? Скільки з них належить до однієї групи? А скільки там різних груп?

Один із способів відповісти на ці запитання – використовувати a Кластеризація алгоритми, такі як K-Means, DBSCAN, ієрархічна кластеризація тощо. Загалом, алгоритми кластеризації знаходять подібності між точками даних і групують їх.

У цьому випадку наших маркетингових даних досить мало. Маємо інформацію лише про 200 клієнтів. Для маркетингової групи важливо, щоб ми могли чітко пояснити їм, як приймалися рішення на основі кількості кластерів, а отже, пояснити їм, як насправді працює алгоритм.

Оскільки наші дані невеликі, а зрозумілість є головним фактором, ми можемо використовувати Ієрархічна кластеризація щоб вирішити цю проблему. Цей процес також відомий як Ієрархічний кластерний аналіз (HCA).

Однією з переваг HCA є те, що його можна інтерпретувати та добре працює на невеликих наборах даних.

Ще одна річ, яку слід взяти до уваги в цьому сценарії, це те, що HCA є без нагляду алгоритм. Під час групування даних у нас не буде можливості перевірити, чи правильно ми ідентифікуємо належність користувача до певної групи (ми не знаємо груп). Немає міток, з якими можна порівняти наші результати. Якщо ми правильно визначили групи, це буде пізніше підтверджено відділом маркетингу на щоденній основі (що вимірюється такими показниками, як ROI, коефіцієнти конверсії тощо).

Тепер, коли ми зрозуміли проблему, яку намагаємося вирішити, і як її вирішити, ми можемо почати дивитися на наші дані!

Короткий дослідницький аналіз даних

Примітка: Ви можете завантажити набір даних, який використовується в цьому посібнику тут.

Після завантаження набору даних зверніть увагу, що це a CSV (значення, розділені комами) файл називається shopping-data.csv. Щоб легше досліджувати та маніпулювати даними, ми завантажимо їх у a DataFrame за допомогою Pandas:

import pandas as pd


path_to_file = 'home/projects/datasets/shopping-data.csv'
customer_data = pd.read_csv(path_to_file)

Маркетинг заявив, що зібрав 200 записів про клієнтів. Ми можемо перевірити, чи завантажені дані повні з 200 рядками, використовуючи shape атрибут. Він скаже нам, скільки у нас рядків і стовпців відповідно:

customer_data.shape

Це призводить до:

(200, 5)

Чудово! Наші дані містять 200 рядків (записи клієнтів) і ми також маємо 5 стовпців (особливості). Щоб побачити, які характеристики відділ маркетингу зібрав від клієнтів, ми можемо переглянути назви стовпців із columns атрибут. Для цього виконайте:

customer_data.columns

Наведений вище сценарій повертає:

Index(['CustomerID', 'Genre', 'Age', 'Annual Income (k$)',
       'Spending Score (1-100)'],
      dtype='object')

Тут ми бачимо, що маркетинг породив a CustomerID, зібрав Genre, Age, Annual Income (в тисячах доларів), і a Spending Score від 1 до 100 для кожного з 200 клієнтів. На запит про роз’яснення вони сказали, що значення в Spending Score стовпець показує, як часто людина витрачає гроші в торговому центрі за шкалою від 1 до 100. Іншими словами, якщо клієнт має оцінку 0, ця людина ніколи не витрачає гроші, а якщо оцінка 100, ми щойно помітили найбільше витрачає.

Давайте коротко подивимося на розподіл цієї оцінки, щоб перевірити витрати користувачів у нашому наборі даних. Ось де панди hist() метод приходить на допомогу:

customer_data['Spending Score (1-100)'].hist()

img

Дивлячись на гістограму, ми бачимо, що понад 35 клієнтів мають бали 40 та 60, тоді менше 25 балів між ними 70 та 80. Такими є більшість наших клієнтів збалансовані витрати, за якими йдуть помірні та великі витрати. Ми також бачимо, що після цього є рядок 0, ліворуч від розподілу, і інший рядок перед 100, праворуч від розподілу. Ці пробіли, ймовірно, означають, що розподіл не містить тих, хто не витрачає кошти, які мали б оцінку 0, і що також немає великих витрат із оцінкою 100.

Щоб перевірити, чи це правда, ми можемо подивитися на мінімальне та максимальне значення розподілу. Ці значення можна легко знайти як частину описової статистики, тому ми можемо використовувати describe() метод для розуміння інших розподілів числових значень:


customer_data.describe().transpose()

Це дасть нам таблицю, з якої ми зможемо прочитати розподіли інших значень нашого набору даних:

 						count 	mean 	std 		min 	25% 	50% 	75% 	max
CustomerID 				200.0 	100.50 	57.879185 	1.0 	50.75 	100.5 	150.25 	200.0
Age 					200.0 	38.85 	13.969007 	18.0 	28.75 	36.0 	49.00 	70.0
Annual Income (k$) 		200.0 	60.56 	26.264721 	15.0 	41.50 	61.5 	78.00 	137.0
Spending Score (1-100) 	200.0 	50.20 	25.823522 	1.0 	34.75 	50.0 	73.00 	99.0

Наша гіпотеза підтверджується. The min значення Spending Score is 1 а максимум є 99. Отже, ми не маємо 0 or 100 оцінити витрати. Тоді давайте поглянемо на інші стовпці транспонованого describe стіл. Дивлячись на mean та std стовпців, ми бачимо, що для Age mean is 38.85 і std приблизно 13.97. Те саме відбувається для Annual Income, При mean of 60.56 та std 26.26, А для Spending Score з mean of 50 та std of 25.82. Для всіх функцій, mean далеко від стандартного відхилення, яке вказує наші дані мають високу мінливість.

Щоб краще зрозуміти, як змінюються наші дані, побудуємо графік Annual Income розподіл:

customer_data['Annual Income (k$)'].hist()

Що дасть нам:

img

Зверніть увагу на гістограму, що більшість наших даних, понад 35 клієнтів, зосереджено біля числа 60, на нашому mean, по горизонтальній осі. Але що відбувається, коли ми рухаємося до кінців розподілу? Якщо рухатися ліворуч, від середнього 60.560 доларів США, наступне значення, яке ми зустрінемо, дорівнює 34.300 доларів США – середнє значення (60.560 доларів США) мінус стандартний варіант (26.260 доларів США). Якщо ми підемо ліворуч від нашого розподілу даних, буде застосовано аналогічне правило, ми віднімаємо стандартну варіацію ($26.260) від поточного значення ($34.300). Таким чином, ми зустрінемося зі значенням $8.040. Зверніть увагу, як швидко наші дані зросли з 60 до 8 тисяч доларів. Щоразу він «стрибає» на 26.260 XNUMX доларів США – сильно змінюючись, і тому така велика варіабельність.

img

Варіабельність і розмір даних є важливими в аналізі кластеризації, оскільки вимірювання відстані більшості алгоритмів кластеризації чутливі до величини даних. Різниця в розмірі може змінити результати кластеризації, змушуючи одну точку здаватися ближчою або віддаленішою до іншої, ніж вона є насправді, спотворюючи фактичне групування даних.

Наразі ми бачили форму наших даних, деякі їх розподіли та описову статистику. За допомогою Pandas ми також можемо перерахувати наші типи даних і побачити, чи всі наші 200 рядків заповнені чи є null значення:

customer_data.info()

Це призводить до:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 5 columns):
 #   Column                  Non-Null Count  Dtype 
---  ------                  --------------  ----- 
 0   CustomerID              200 non-null    int64 
 1   Genre                   200 non-null    object
 2   Age                     200 non-null    int64 
 3   Annual Income (k$)      200 non-null    int64 
 4   Spending Score (1-100)  200 non-null    int64 
dtypes: int64(4), object(1)
memory usage: 7.9+ KB

Тут ми бачимо, що їх немає null значення в даних і що ми маємо лише один категорійний стовпець – Genre. На цьому етапі важливо мати на увазі, які функції здаються цікавими для додавання до моделі кластеризації. Якщо ми хочемо додати стовпець Genre до нашої моделі, нам потрібно буде трансформувати його значення категоричний до числовий.

Подивимося як Genre заповнюється шляхом швидкого перегляду перших 5 значень наших даних:

customer_data.head() 

Це призводить до:

    CustomerID 	Genre 	Age 	Annual Income (k$) 	Spending Score (1-100)
0 	1 			Male 	19 		15 					39
1 	2 			Male 	21 		15 					81
2 	3 			Female 	20 		16 					6
3 	4 			Female 	23 		16 					77
4 	5 			Female 	31 		17 					40

Здається, що має тільки Female та Male категорії. Ми можемо переконатися в цьому, подивившись на його унікальні цінності unique:

customer_data['Genre'].unique()

Це підтверджує наше припущення:

array(['Male', 'Female'], dtype=object)

Наразі ми знаємо, що у нас є лише два жанри, якщо ми плануємо використовувати цю функцію в нашій моделі, Male можна перетворити на 0 та Female до 1. Важливо також перевірити пропорції між жанрами, щоб побачити, чи вони збалансовані. Ми можемо зробити це за допомогою value_counts() метод і його аргумент normalize=True щоб показати відсоток між Male та Female:

customer_data['Genre'].value_counts(normalize=True)

Це виводить:

Female    0.56
Male      0.44
Name: Genre, dtype: float64

У нас 56% жінок у наборі даних і 44% чоловіків. Різниця між ними лише 16%, а наші дані не 50/50, а є достатньо збалансований щоб не завдати клопоту. Якби результати були 70/30, 60/40, тоді, можливо, потрібно було або зібрати більше даних, або застосувати якусь техніку збільшення даних, щоб зробити це співвідношення більш збалансованим.

Дотепер усі функції, але Age, були коротко досліджені. У чому стосується Age, як правило, цікаво розділити його на контейнери, щоб мати можливість сегментувати клієнтів за їхніми віковими групами. Якщо ми це зробимо, нам потрібно буде перетворити вікові категорії в одне число, перш ніж додати їх до нашої моделі. Таким чином, замість того, щоб використовувати категорію 15-20 років, ми б підрахували, скільки клієнтів є в 15-20 категорія, і це буде число в новому стовпці під назвою 15-20.

Поради: У цьому посібнику ми подаємо лише короткий дослідницький аналіз даних. Але ви можете йти далі і ви повинні йти далі. Ви можете побачити, чи існують відмінності в доходах і оцінках залежно від жанру та віку. Це не тільки збагачує аналіз, але й призводить до кращих результатів моделі. Щоб глибше ознайомитись із дослідницьким аналізом даних, перегляньте Розділ EDA в “Практичний прогноз ціни на нерухомість – машинне навчання на Python" Керований проект.

Після припущення про те, що можна зробити з обома категоричними – або категоричними бути – Genre та Age стовпці, застосуємо те, що обговорювалося.

Кодування змінних і розробка функцій

Почнемо з поділу Age на групи, які відрізняються по 10, так що ми маємо 20-30, 30-40, 40-50 і так далі. Оскільки нашому наймолодшому клієнту 15 років, ми можемо почати з 15 і закінчити в 70, тобто вік найстаршого клієнта в даних. Починаючи з 15 і закінчуючи 70, у нас буде 15-20, 20-30, 30-40, 40-50, 50-60 і 60-70 інтервалів.

Щоб згрупувати або Бен Age значення в ці інтервали, ми можемо використовувати Pandas cut() щоб розрізати їх на контейнери, а потім призначити нові контейнери Age Groups стовпчик:

intervals = [15, 20, 30, 40, 50, 60, 70]
col = customer_data['Age']
customer_data['Age Groups'] = pd.cut(x=col, bins=intervals)


customer_data['Age Groups'] 

Це призводить до:

0      (15, 20]
1      (20, 30]
2      (15, 20]
3      (20, 30]
4      (30, 40]
         ...   
195    (30, 40]
196    (40, 50]
197    (30, 40]
198    (30, 40]
199    (20, 30]
Name: Age Groups, Length: 200, dtype: category
Categories (6, interval[int64, right]): [(15, 20] < (20, 30] < (30, 40] < (40, 50] < (50, 60] < (60, 70]]

Зауважте, що під час перегляду значень стовпця також є рядок, який вказує, що у нас є 6 категорій, і відображає всі інтервали даних у групі. Таким чином ми класифікували наші попередні числові дані та створили нові Age Groups функцію.

І скільки у нас клієнтів у кожній категорії? Ми можемо швидко це дізнатися, згрупувавши стовпець і підрахувавши значення groupby() та count():

customer_data.groupby('Age Groups')['Age Groups'].count()

Це призводить до:

Age Groups
(15, 20]    17
(20, 30]    45
(30, 40]    60
(40, 50]    38
(50, 60]    23
(60, 70]    17
Name: Age Groups, dtype: int64

Легко помітити, що більшість клієнтів мають вік від 30 до 40 років, за ними йдуть клієнти від 20 до 30, а потім клієнти від 40 до 50. Це також хороша інформація для відділу маркетингу.

На даний момент ми маємо дві категоричні змінні, Age та Genre, які нам потрібно перетворити на числа, щоб мати можливість використовувати в нашій моделі. Є багато різних способів здійснити цю трансформацію – ми використаємо Pandas get_dummies() метод, який створює новий стовпець для кожного інтервалу та жанру, а потім заповнює його значення 0 і 1. Така операція називається одноразове кодування. Давайте подивимося, як це виглядає:


customer_data_oh = pd.get_dummies(customer_data)

customer_data_oh 

Це дасть нам попередній перегляд результуючої таблиці:

img

З виведенням легко побачити, що стовпець Genre було розбито на колони – Genre_Female та Genre_Male. Коли клієнт жінка, Genre_Female дорівнює 1, і коли клієнт чоловічої статі, це дорівнює 0.

Крім того, Age Groups стовпець був розділений на 6 стовпців, по одному для кожного інтервалу, наприклад Age Groups_(15, 20], Age Groups_(20, 30], і так далі. Таким же чином, як Genre, коли замовнику 18 років, Age Groups_(15, 20] значення є 1 а значення всіх інших стовпців дорівнює 0.

Команда перевагу одноразового кодування — це простота представлення значень стовпців, просто зрозуміти, що відбувається — тоді як недолік полягає в тому, що тепер ми створили 8 додаткових стовпців, щоб підсумувати стовпці, які у нас уже були.

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

Одночасне кодування також додає 0 до наших даних, роблячи їх більш розрідженими, що може бути проблемою для деяких алгоритмів, чутливих до розрідженості даних.

Для наших потреб у кластеризації кодування з одним чатом, здається, працює. Але ми можемо побудувати дані, щоб побачити, чи справді існують окремі групи, які ми можемо згрупувати.

Базове малювання та зменшення розмірності

Наш набір даних має 11 стовпців, і ми можемо кількома способами візуалізувати ці дані. Перший – побудувати його в 10 вимірах (бажаю успіху). Десять, тому що Customer_ID колонка не розглядається. Другий – шляхом побудови наших початкових числових характеристик, а третій – шляхом перетворення наших 10 характеристик у 2 – отже, виконання зменшення розмірності.

Побудова кожної пари даних

Оскільки побудувати 10 вимірів трохи неможливо, ми виберемо другий підхід – ми побудуємо наші початкові об’єкти. Ми можемо вибрати два з них для аналізу кластеризації. Один із способів побачити всі наші пари даних у поєднанні — це Seaborn pairplot():

import seaborn as sns


customer_data = customer_data.drop('CustomerID', axis=1)

sns.pairplot(customer_data)

Який відображає:

img

З першого погляду ми можемо помітити діаграми розсіювання, які, здається, містять групи даних. Цікавим є діаграма розсіювання, яка поєднує Annual Income та Spending Score. Зауважте, що немає чіткого поділу між іншими змінними діаграмами розсіювання. Щонайбільше, ми можемо сказати, що є дві різні концентрації точок у Spending Score vs Age Діаграма розкиду.

Обидві діаграми розсіювання, що складаються з Annual Income та Spending Score по суті однакові. Ми можемо побачити це двічі, тому що осі x і y помінялися місцями. Поглянувши на будь-яку з них, ми побачимо п’ять різних груп. Давайте зобразимо ці дві особливості на Seaborn scatterplot() придивитися ближче:

sns.scatterplot(x=customer_data['Annual Income (k$)'],
                y=customer_data['Spending Score (1-100)'])

img

Придивившись ближче, ми можемо виділити 5 різних груп даних. Здається, наших клієнтів можна об’єднати в групи залежно від того, скільки вони заробляють за рік і скільки витрачають. Це ще один актуальний момент у нашому аналізі. Важливо, що ми беремо до уваги лише дві особливості, щоб групувати наших клієнтів. Будь-яка інша інформація, яку ми маємо про них, не входить до рівняння. Це надає аналізу сенс – якщо ми знаємо, скільки заробляє та витрачає клієнт, ми можемо легко знайти потрібні нам подібності.

img

Це чудово! Наразі ми вже маємо дві змінні для побудови нашої моделі. Крім того, що це представляє, це також робить модель простішою, скупішою та зрозумілішою.

Ознайомтеся з нашим практичним практичним посібником із вивчення Git з передовими методами, прийнятими в галузі стандартами та включеною шпаргалкою. Припиніть гуглити команди Git і фактично вчитися це!

Примітка: Data Science зазвичай віддає перевагу максимально простим підходам. Не лише тому, що це легше пояснити для бізнесу, але й тому, що це більш прямо – завдяки 2 функціям і пояснювальній моделі стає зрозуміло, що робить модель і як вона працює.

Побудова графіка даних після використання PCA

Здається, наш другий підхід, ймовірно, найкращий, але давайте також подивимося на наш третій підхід. Це може бути корисно, коли ми не можемо побудувати дані, оскільки вони мають забагато вимірів, або коли немає концентрації даних чи чіткого розподілу на групи. Коли виникають такі ситуації, рекомендується спробувати зменшити розміри даних за допомогою методу під назвою Аналіз основних компонентів (PCA).

Примітка: Більшість людей використовують PCA для зменшення розмірності перед візуалізацією. Існують інші методи, які допомагають візуалізувати дані перед кластеризацією, наприклад Просторова кластеризація додатків із шумом на основі щільності (DBSCAN) та Самоорганізуючі карти (SOM) кластеризація. Обидва є алгоритмами кластеризації, але також можуть використовуватися для візуалізації даних. Оскільки аналіз кластеризації не має золотого стандарту, важливо порівнювати різні візуалізації та різні алгоритми.

PCA зменшить розміри наших даних, намагаючись зберегти якомога більше інформації. Давайте спочатку отримаємо уявлення про те, як працює PCA, а потім ми зможемо вибрати, до скількох вимірів даних ми будемо скорочувати наші дані.

Для кожної пари функцій PCA перевіряє, чи більші значення однієї змінної відповідають більшим значенням іншої змінної, і робить те саме для менших значень. Таким чином, він по суті обчислює, наскільки значення ознак відрізняються одне від одного – ми називаємо це їхніми коваріація. Потім ці результати організовуються в матрицю, отримуючи a коваріаційна матриця.

Отримавши коваріаційну матрицю, PCA намагається знайти лінійну комбінацію ознак, яка найкраще пояснює це – вона підходить до лінійних моделей, доки не ідентифікує ту, яка пояснює максимальний кількість дисперсії.

примітки: PCA — це лінійне перетворення, а лінійність залежить від масштабу даних. Тому PCA працює найкраще, коли всі значення даних знаходяться в одній шкалі. Це можна зробити шляхом віднімання стовпчика значити від його значень і ділення результату на стандартне відхилення. Це називається стандартизація даних. Перш ніж використовувати PCA, переконайтеся, що дані масштабовані! Якщо ви не знаєте як, прочитайте наш «Дані масштабування функцій за допомогою Scikit-Learn для машинного навчання на Python»!

З знайденою найкращою лінією (лінійною комбінацією) PCA отримує напрямки своїх осей, які називаються власні вектори, і його лінійні коефіцієнти, власні значення. Комбінація власних векторів і власних значень – або напрямків осей і коефіцієнтів – є Основні компоненти PCA. І саме тоді ми можемо вибрати нашу кількість вимірів на основі поясненої дисперсії кожної функції, розуміючи, які головні компоненти ми хочемо залишити або відкинути на основі того, яку дисперсію вони пояснюють.

Після отримання головних компонентів PCA використовує власні вектори для формування вектора ознак, які переорієнтовують дані з вихідних осей на осі, представлені головними компонентами – таким чином зменшуються розміри даних.

Примітка: Одна важлива деталь, яку слід взяти до уваги, полягає в тому, що через свою лінійну природу PCA зосередить більшу частину поясненої дисперсії в перших основних компонентах. Отже, дивлячись на пояснену дисперсію, зазвичай наших перших двох компонентів буде достатньо. Але в деяких випадках це може вводити в оману, тому спробуйте продовжувати порівнювати різні графіки та алгоритми під час кластеризації, щоб побачити, чи дають вони подібні результати.

Перш ніж застосувати PCA, нам потрібно вибрати між Age стовпець або Age Groups у наших попередньо закодованих даних. Оскільки обидва стовпці представляють однакову інформацію, її подвійне введення впливає на дисперсію даних. Якщо Age Groups вибрано стовпець, просто видаліть Age стовпець за допомогою Pandas drop() метод і перепризначити його на customer_data_oh змінна:

customer_data_oh = customer_data_oh.drop(['Age'], axis=1)
customer_data_oh.shape 

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

Давайте зробимо це за допомогою Scikit-Learn PCA. Ми обчислимо пояснену дисперсію кожного розміру, задану за explained_variance_ratio_ , а потім подивіться на їх сукупну суму за допомогою cumsum() :

from sklearn.decomposition import PCA

pca = PCA(n_components=10)
pca.fit_transform(customer_data_oh)
pca.explained_variance_ratio_.cumsum()

Наші сукупні пояснені відхилення:

array([0.509337  , 0.99909504, 0.99946364, 0.99965506, 0.99977937,
       0.99986848, 0.99993716, 1.        , 1.        , 1.        ])

Ми бачимо, що перший вимір пояснює 50% даних, а в поєднанні з другим виміром вони пояснюють 99% відсотків. Це означає, що перші 2 параметри вже пояснюють 99% наших даних. Отже, ми можемо застосувати PCA з 2 компонентами, отримати основні компоненти та побудувати їх:

from sklearn.decomposition import PCA

pca = PCA(n_components=2)
pcs = pca.fit_transform(customer_data_oh)

pc1_values = pcs[:,0]
pc2_values = pcs[:,1]
sns.scatterplot(x=pc1_values, y=pc2_values)

img

Діаграма даних після PCA дуже схожа на графік, який використовує лише два стовпці даних без PCA. Зауважте, що точки, які утворюють групи, розташовані ближче та трохи більше концентруються після PCA, ніж раніше.

img

Візуалізація ієрархічної структури за допомогою дендрограм

Наразі ми досліджували дані, одноразово закодовані категоричні стовпці, вирішували, які стовпці придатні для кластеризації, і зменшили розмірність даних. Діаграми вказують на те, що ми маємо 5 кластерів у наших даних, але є також інший спосіб візуалізувати зв’язки між нашими точками та допомогти визначити кількість кластерів – створивши дендрограма (зазвичай неправильно пишеться як дендограма). Дендро засоби дерево латиною.

Команда дендрограма є результатом зв’язування точок у наборі даних. Це візуальне представлення ієрархічного процесу кластеризації. І як працює процес ієрархічної кластеризації? Ну… це залежить – напевно, відповідь ви вже багато чули в Data Science.

Розуміння ієрархічної кластеризації

Коли Алгоритм ієрархічної кластеризації (HCA) починає зв’язувати точки та знаходити кластери, він може спочатку розділити точки на 2 великі групи, а потім розділити кожну з цих двох груп на 2 менші групи, маючи загалом 4 групи, що є подільний та з верху до низу підходу.

Крім того, він може зробити навпаки – він може переглянути всі точки даних, знайти 2 точки, які ближче одна до одної, зв’язати їх, а потім знайти інші точки, які є найближчими до цих пов’язаних точок, і продовжувати будувати 2 групи від від низу до верху. Що є агломераційний підхід, який ми розробимо.

Етапи виконання агломеративної ієрархічної кластеризації

Щоб зробити агломеративний підхід ще більш зрозумілим, є кроки Агломеративна ієрархічна кластеризація (AHC) алгоритм:

  1. На початку розглядайте кожну точку даних як один кластер. Таким чином, кількість кластерів на початку буде K, тоді як K є цілим числом, що представляє кількість точок даних.
  2. Сформуйте кластер, об’єднавши дві найближчі точки даних, утворивши кластери K-1.
  3. Сформуйте більше кластерів, об’єднавши два найближчі кластери, утворивши кластери K-2.
  4. Повторіть описані вище три кроки, доки не утвориться одне велике скупчення.

примітки: Для спрощення ми говоримо про «дві найближчі» точки даних у кроках 2 і 3. Але існує більше способів зв’язати точки, як ми побачимо трохи пізніше.

Якщо ви інвертуєте кроки алгоритму ACH, переходячи від 4 до 1 – це будуть кроки до *Роздільна ієрархічна кластеризація (DHC)*.

Зауважте, що HCA можуть бути або роздільними та спрямованими зверху вниз, або агломеративними та спрямованими знизу вгору. Низхідний підхід DHC працює найкраще, коли у вас менше, але більших кластерів, отже, це дорожче з точки зору обчислень. З іншого боку, підхід AHC знизу вгору підходить, коли у вас багато менших кластерів. Він обчислювально простіший, більш використовуваний і доступніший.

Примітка: Зверху вниз або знизу вгору дендрограмне представлення процесу кластеризації завжди починатиметься з поділу на дві частини й закінчуватиметься розрізненням кожної окремої точки, коли її базова структура стане бінарним деревом.

Давайте побудуємо дендрограму наших даних про клієнтів, щоб візуалізувати ієрархічні зв’язки даних. Цього разу ми скористаємося scipy бібліотека для створення дендрограми для нашого набору даних:

import scipy.cluster.hierarchy as shc
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 7))
plt.title("Customers Dendrogram")


selected_data = customer_data_oh.iloc[:, 1:3]
clusters = shc.linkage(selected_data, 
            method='ward', 
            metric="euclidean")
shc.dendrogram(Z=clusters)
plt.show()

Результат сценарію виглядає так:

img

У наведеному вище сценарії ми створили кластери та підкластери з нашими точками, визначили, як наші точки будуть зв’язуватися (шляхом застосування ward метод) і як виміряти відстань між точками (за допомогою euclidean метрика).

За допомогою графіка дендрограми можна візуалізувати описані процеси DHC і AHC. Щоб візуалізувати підхід зверху вниз, почніть з верхньої частини дендрограми та опустіться вниз, і зробіть навпаки, починаючи вниз і рухаючись вгору, щоб візуалізувати підхід знизу вгору.

Методи зв'язування

Існує багато інших методів зв’язування, і, дізнавшись більше про те, як вони працюють, ви зможете вибрати відповідний для своїх потреб. Крім того, кожен з них при застосуванні дасть різні результати. У кластерному аналізі немає фіксованого правила, якщо можливо, вивчіть природу проблеми, щоб побачити, який підходить найкраще, протестуйте різні методи та перевірте результати.

Деякі з методів підключення:

  • Одинарна тяга: також згадується як Найближчий сусід (NN). Відстань між кластерами визначається відстанню між їхніми найближчими членами.

img

  • Повне зчеплення: також згадується як Найдальший сусід (FN), Алгоритм найдальшої точкиабо Алгоритм Voor Hees. Відстань між кластерами визначається відстанню між їх найдальшими членами. Цей метод обчислювально дорогий.

img

  • Середня тяга: також відомий як UPGMA (Метод незваженої групи пар із середнім арифметичним). Відсоток кількості точок кожного кластера розраховується відносно кількості точок двох кластерів, якщо вони були об’єднані.

img

  • Зважене зв'язування: також відомий як WPGMA (Метод зваженої групи пар із середнім арифметичним). Окремі точки двох кластерів сприяють сукупній відстані між меншим і більшим кластерами.
  • Центроїд зв'язку: також згадується як UPGMC (Метод незважених парних груп із використанням центроїдів). Точка, визначена середнім значенням усіх точок (центроїд), обчислюється для кожного кластера, а відстань між кластерами є відстанню між їхніми відповідними центроїдами.

img

  • Уорд зв'язка: Також відомий як MISSQ (Мінімальне збільшення суми квадратів). Він визначає відстань між двома кластерами, обчислює суму квадратів помилок (ESS) і послідовно вибирає наступні кластери на основі меншої ESS. Метод Уорда прагне мінімізувати збільшення ESS на кожному кроці. Тому мінімізація помилки.

img

Метрика відстані

Окрім зв’язку, ми також можемо вказати деякі з найбільш використовуваних показників відстані:

  • Евклідова: також згадується як Піфагорова або пряма відстань. Він обчислює відстань між двома точками простору, вимірюючи довжину відрізка, що проходить між ними. Він використовує теорему Піфагора, а значення відстані є результатом (С) рівняння:

$$
c^2 = a^2 + b^2
$$

  • Манхеттен: також називається Сіті-квартал, таксі відстань. Це сума абсолютних різниць між мірами в усіх вимірах двох точок. Якщо цих розмірів два, це аналогічно повороту вправо, а потім уліво під час проходження одного кварталу.

img

  • Мінковський: це узагальнення як евклідової, так і манхеттенської відстаней. Це спосіб обчислення відстаней на основі абсолютних різниць у порядку метрики Мінковського p. Хоча це визначено для будь-якого p> 0, він рідко використовується для значень, відмінних від 1, 2 і ∞ (нескінченність). Відстань Мінковського дорівнює відстані Манхеттена, коли p = 1, і така ж, як евклідова відстань, коли p = 2.

$$
Dleft(X,Yright) = left(sum_{i=1}^n |x_i-y_i|^right)^{frac{1}{p}}
$$

img

  • Чебишева: також відомий як Шахова дошка відстань. Це граничний випадок відстані Мінковського. Коли ми використовуємо нескінченність як значення параметра p (p = ∞), ми отримуємо метрику, яка визначає відстань як максимальну абсолютну різницю між координатами.
  • косинус: це кутова косинусна відстань між двома послідовностями точок або векторів. Косинус подібності — це скалярний добуток векторів, поділений на добуток їх довжин.
  • Жаккард: вимірює подібність між кінцевими наборами точок. Він визначається як загальна кількість точок (мощність) у спільних точках у кожному наборі (перетині), поділена на загальну кількість точок (мощність) загальних точок обох наборів (об’єднання).
  • Дженсен-Шеннон: на основі розбіжності Кульбака-Лейблера. Він розглядає розподіли ймовірностей точок і вимірює подібність між цими розподілами. Це популярний метод теорії ймовірностей і статистики.

Ми вибрали Підопічний та Евклідова для дендрограми, оскільки вони є найбільш часто використовуваним методом і метрикою. Зазвичай вони дають хороші результати, оскільки Уорд зв’язує точки на основі мінімізації помилок, а Евклідова добре працює в нижчих вимірах.

У цьому прикладі ми працюємо з двома функціями (стовпцями) маркетингових даних і 200 спостереженнями або рядками. Оскільки кількість спостережень більша за кількість ознак (200 > 2), ми працюємо в низьковимірному просторі.

При кількості ознак (Е) більше, ніж кількість спостережень (N) – здебільшого пишеться як f >> N, це означає, що ми маємо a великий розмірний простір.

Якщо ми включимо більше атрибутів, тож у нас буде понад 200 функцій, евклідова відстань може працювати не дуже добре, оскільки виникнуть труднощі з вимірюванням усіх малих відстаней у дуже великому просторі, який тільки збільшується. Іншими словами, підхід до евклідової відстані має труднощі при роботі з даними розрідженість. Це питання, що називається прокляття розміреності. Значення відстані стають настільки малими, ніби вони «розбавляються» у більшому просторі, спотворюються, поки не стануть нульовими.

Примітка: Якщо ви коли-небудь зіткнетеся з набором даних із f >> стор, ви, ймовірно, використовуватимете інші показники відстані, наприклад Махаланобіс відстань. Крім того, ви також можете зменшити розміри набору даних, використовуючи Аналіз основних компонентів (PCA). Ця проблема часто виникає, особливо при кластеризації даних біологічного секвенування.

Ми вже обговорювали показники, зв’язки та те, як кожен із них може вплинути на наші результати. Давайте продовжимо аналіз дендрограми та подивимося, як він може дати нам інформацію про кількість кластерів у нашому наборі даних.

Знайти цікаву кількість кластерів у дендрограмі те саме, що знайти найбільший горизонтальний простір, який не має жодної вертикальної лінії (простір із найдовшими вертикальними лініями). Це означає, що між кластерами більше розриву.

Ми можемо провести горизонтальну лінію, яка проходить через цю найдовшу відстань:

plt.figure(figsize=(10, 7))
plt.title("Customers Dendogram with line")
clusters = shc.linkage(selected_data, 
            method='ward', 
            metric="euclidean")
shc.dendrogram(clusters)
plt.axhline(y = 125, color = 'r', linestyle = '-')

img

Визначивши горизонтальну лінію, ми підраховуємо, скільки разів наші вертикальні лінії перетиналися нею – у цьому прикладі 5 разів. Отже, 5 здається хорошим показником кількості кластерів, які мають найбільшу відстань між собою.

примітки: Дендрограмму слід розглядати лише як орієнтир, коли вона використовується для вибору кількості кластерів. Він може легко отримати це число далеко, і повністю залежить від типу зв’язку та показників відстані. При проведенні поглибленого кластерного аналізу рекомендується дивитися на дендрограми з різними зв’язками та метриками та дивитися на результати, отримані з першими трьома рядками, у яких кластери мають найбільшу відстань між собою.

Реалізація агломеративної ієрархічної кластеризації

Використання оригінальних даних

Наразі ми розрахували запропоновану кількість кластерів для нашого набору даних, які підтверджують наш початковий аналіз і аналіз PCA. Тепер ми можемо створити нашу агломеративну ієрархічну модель кластеризації за допомогою Scikit-Learn AgglomerativeClustering і дізнайтеся позначки маркетингових точок с labels_:

from sklearn.cluster import AgglomerativeClustering

clustering_model = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')
clustering_model.fit(selected_data)
clustering_model.labels_

Це призводить до:

array([4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3,
       4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 1,
       4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 0, 2, 0, 2,
       1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 1, 2, 0, 2, 0, 2, 0, 2,
       0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2,
       0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2,
       0, 2])

Ми багато досліджували, щоб дійти до цього моменту. І що означають ці мітки? Тут кожна точка наших даних позначена групою від 0 до 4:

data_labels = clustering_model.labels_
sns.scatterplot(x='Annual Income (k$)', 
                y='Spending Score (1-100)', 
                data=selected_data, 
                hue=data_labels,
                pallete="rainbow").set_title('Labeled Customer Data')

img

Це наші остаточні кластеризовані дані. Ви можете побачити кольорові точки даних у формі п’яти кластерів.

Точки даних унизу праворуч (мітка: 0, фіолетові точки даних) належать клієнтам із високими зарплатами, але низькими витратами. Це клієнти, які дбайливо витрачають гроші.

Так само клієнти вгорі праворуч (мітка: 2, зелені точки даних), це клієнти з високими зарплатами та великими витратами. Це тип клієнтів, на яких орієнтуються компанії.

Клієнти посередині (мітка: 1, сині точки даних) – це ті, хто має середній дохід і середні витрати. Саме до цієї категорії відноситься найбільше клієнтів. Компанії також можуть орієнтуватися на цих клієнтів, враховуючи той факт, що їх величезна кількість.

Клієнти внизу ліворуч (мітка: 4, червоний) – це клієнти з низькими зарплатами та малими витратами, їх можна залучити, пропонуючи рекламні акції.

І, нарешті, клієнти у верхньому лівому куті (мітка: 3, помаранчеві точки даних) – це ті, що мають високий дохід і низькі витрати, на які ідеально орієнтується маркетинг.

Використання результату PCA

Якби ми були в іншому сценарії, за якого нам довелося зменшити розмірність даних. Ми також можемо легко побудувати кластеризовані результати PCA. Це можна зробити, створивши іншу модель агломеративної кластеризації та отримавши мітку даних для кожного головного компонента:

clustering_model_pca = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')
clustering_model_pca.fit(pcs)

data_labels_pca = clustering_model_pca.labels_

sns.scatterplot(x=pc1_values, 
                y=pc2_values,
                hue=data_labels_pca,
                palette="rainbow").set_title('Labeled Customer Data Reduced with PCA')

img

Зауважте, що обидва результати дуже схожі. Основна відмінність полягає в тому, що перший результат з вихідними даними набагато легше пояснити. Зрозуміло, що клієнтів можна розділити на п’ять груп за їх річним доходом і витратами. У той час як у підході PCA ми беремо до уваги всі наші функції, незважаючи на те, що ми можемо дивитися на відмінності, пояснені кожною з них, цю концепцію складніше зрозуміти, особливо під час звітування відділу маркетингу.

Чим менше ми маємо для трансформації наших даних, тим краще.

Якщо у вас є дуже великий і складний набір даних, у якому ви повинні виконати зменшення розмірності перед кластеризацією, спробуйте проаналізувати лінійні зв’язки між кожною ознакою та її залишками, щоб підтвердити використання PCA та підвищити зрозумілість процесу. Створивши лінійну модель для кожної пари функцій, ви зможете зрозуміти, як вони взаємодіють.

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

Ви завжди можете вибрати різні методи візуалізації кластеризації відповідно до характеру ваших даних (лінійні, нелінійні) і поєднати або протестувати їх усі, якщо необхідно.

Висновок

Техніка кластеризації може бути дуже зручною, коли йдеться про немарковані дані. Оскільки більшість даних у реальному світі є немаркованими, а анотування даних вимагає дорожчих витрат, для маркування немаркованих даних можна використовувати методи кластеризації.

У цьому посібнику ми розглянули реальну проблему науки про дані, оскільки методи кластеризації широко використовуються в маркетинговому аналізі (а також у біологічному аналізі). Ми також пояснили багато етапів дослідження, щоб отримати хорошу ієрархічну модель кластеризації та як читати дендрограми, і поставили запитання, чи є PCA необхідним кроком. Наша головна мета полягає в тому, щоб охопити деякі підводні камені та різні сценарії, в яких ми можемо знайти ієрархічну кластеризацію.

Щасливого кластеризування!

Часова мітка:

Більше від Stackabuse