Ви маєте рацію, що кластеризація k-означає не повинна проводитися з даними змішаних типів. Оскільки k-означає, по суті, простий алгоритм пошуку для пошуку розділу, який мінімізує евклідові відстані між кластером в межах кластера між кластеризованими спостереженнями та центроїдом кластера, він повинен використовуватися лише з даними, де квадрати евклідової відстані мали б значення.
Коли ваші дані складаються із змінних змішаних типів, вам потрібно використовувати відстань Гоувера. @Ttnphns користувача CV має великий огляд відстані Гоуер в тут . По суті, ви обчислюєте матрицю відстані для своїх рядків для кожної змінної по черзі, використовуючи тип відстані, відповідний для цього типу змінної (наприклад, евклідова для безперервних даних тощо); кінцева відстань рядка до - це (можливо, зважене) середнє відстань для кожної змінної. Слід пам’ятати, що відстань Гоуера насправді не є метрикою . Тим не менше, зі змішаними даними, відстань Гоувера є значною мірою єдиною грою в місті. ii'
На даний момент ви можете використовувати будь-який метод кластеризації, який може працювати над матрицею відстані замість необхідності вихідної матриці даних. (Зверніть увагу, що k-засоби потребують останнього.) Найпопулярніший вибір - це розділення навколо медоїдів (PAM, який по суті є таким же, як k-засоби, але використовує найбільш центральне спостереження, а не центроїд), різні ієрархічні підходи кластеризації (наприклад, , медіана, однозв'язковість та повна зв’язок; за допомогою ієрархічної кластеризації вам потрібно буде вирішити, де « вирізати дерево », щоб отримати остаточні завдання кластера) та DBSCAN, який дозволяє набагато більш гнучкими формами кластера.
Ось проста R
демонстрація (nb, насправді є 3 кластери, але дані в основному виглядають так, як 2 кластери є відповідними):
library(cluster) # we'll use these packages
library(fpc)
# here we're generating 45 data in 3 clusters:
set.seed(3296) # this makes the example exactly reproducible
n = 15
cont = c(rnorm(n, mean=0, sd=1),
rnorm(n, mean=1, sd=1),
rnorm(n, mean=2, sd=1) )
bin = c(rbinom(n, size=1, prob=.2),
rbinom(n, size=1, prob=.5),
rbinom(n, size=1, prob=.8) )
ord = c(rbinom(n, size=5, prob=.2),
rbinom(n, size=5, prob=.5),
rbinom(n, size=5, prob=.8) )
data = data.frame(cont=cont, bin=bin, ord=factor(ord, ordered=TRUE))
# this returns the distance matrix with Gower's distance:
g.dist = daisy(data, metric="gower", type=list(symm=2))
Ми можемо почати з пошуку різної кількості кластерів з PAM:
# we can start by searching over different numbers of clusters with PAM:
pc = pamk(g.dist, krange=1:5, criterion="asw")
pc[2:3]
# $nc
# [1] 2 # 2 clusters maximize the average silhouette width
#
# $crit
# [1] 0.0000000 0.6227580 0.5593053 0.5011497 0.4294626
pc = pc$pamobject; pc # this is the optimal PAM clustering
# Medoids:
# ID
# [1,] "29" "29"
# [2,] "33" "33"
# Clustering vector:
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
# 1 1 1 1 1 2 1 1 1 1 1 2 1 2 1 2 2 1 1 1 2 1 2 1 2 2
# 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
# 1 2 1 2 2 1 2 2 2 2 1 2 1 2 2 2 2 2 2
# Objective function:
# build swap
# 0.1500934 0.1461762
#
# Available components:
# [1] "medoids" "id.med" "clustering" "objective" "isolation"
# [6] "clusinfo" "silinfo" "diss" "call"
Ці результати можна порівняти з результатами ієрархічної кластеризації:
hc.m = hclust(g.dist, method="median")
hc.s = hclust(g.dist, method="single")
hc.c = hclust(g.dist, method="complete")
windows(height=3.5, width=9)
layout(matrix(1:3, nrow=1))
plot(hc.m)
plot(hc.s)
plot(hc.c)
Середній метод пропонує 2 (можливо, 3) кластери, єдиний підтримує лише 2, але повний метод міг би запропонувати 2, 3 або 4 для мого ока.
Нарешті, ми можемо спробувати DBSCAN. Для цього потрібно вказати два параметри: eps, "відстань досяжності" (наскільки близько два спостереження повинні бути пов'язані між собою) та minPts (мінімальна кількість точок, які потрібно з'єднати один з одним, перш ніж ви будете готові називати їх a 'кластер'). Основне правило для minPts полягає в тому, щоб використовувати один розмір більше, ніж кількість розмірів (у нашому випадку 3 + 1 = 4), але мати занадто мале число не рекомендується. Значення за замовчуванням dbscan
- 5; ми будемо дотримуватися цього. Один із способів думати про відстань досяжності - бачити, який відсоток відстаней менший за будь-яке задане значення. Ми можемо це зробити, вивчивши розподіл відстаней:
windows()
layout(matrix(1:2, nrow=1))
plot(density(na.omit(g.dist[upper.tri(g.dist)])), main="kernel density")
plot(ecdf(g.dist[upper.tri(g.dist)]), main="ECDF")
Самі відстані, схоже, скупчуються на групи, що помічають «ближче» та «далі». Значення .3, здається, найбільш чітко розрізняє дві групи відстаней. Щоб дослідити чутливість виводу до різних варіантів eps, ми можемо також спробувати .2 та .4:
dbc3 = dbscan(g.dist, eps=.3, MinPts=5, method="dist"); dbc3
# dbscan Pts=45 MinPts=5 eps=0.3
# 1 2
# seed 22 23
# total 22 23
dbc2 = dbscan(g.dist, eps=.2, MinPts=5, method="dist"); dbc2
# dbscan Pts=45 MinPts=5 eps=0.2
# 1 2
# border 2 1
# seed 20 22
# total 22 23
dbc4 = dbscan(g.dist, eps=.4, MinPts=5, method="dist"); dbc4
# dbscan Pts=45 MinPts=5 eps=0.4
# 1
# seed 45
# total 45
Використання eps=.3
дає дуже чисте рішення, яке (принаймні якісно) узгоджується з тим, що ми бачили з інших методів вище.
Оскільки немає жодної значущості 1 кластерності кластеру , ми повинні бути обережними, намагаючись узгодити, які спостереження називаються "кластером 1" з різних кластерів. Натомість ми можемо сформувати таблиці, і якщо більшість спостережень, що називаються «кластер 1» в одному підході, називаються «кластером 2» в іншому, ми бачимо, що результати все ще істотно схожі. У нашому випадку різні кластери здебільшого дуже стабільні і щоразу ставлять однакові спостереження в одних і тих же кластерах; відрізняється лише повна ієрархічна кластеризація зв'язків:
# comparing the clusterings
table(cutree(hc.m, k=2), cutree(hc.s, k=2))
# 1 2
# 1 22 0
# 2 0 23
table(cutree(hc.m, k=2), pc$clustering)
# 1 2
# 1 22 0
# 2 0 23
table(pc$clustering, dbc3$cluster)
# 1 2
# 1 22 0
# 2 0 23
table(cutree(hc.m, k=2), cutree(hc.c, k=2))
# 1 2
# 1 14 8
# 2 7 16
Звичайно, немає гарантії, що будь-який аналіз кластерів відновить справжні латентні кластери у ваших даних. Відсутність справжніх міток кластеру (які були б доступні, скажімо, в ситуації з логістичною регресією) означає, що величезна кількість інформації недоступна. Навіть при дуже великих наборах даних кластери можуть бути недостатньо добре відокремлені, щоб їх можна було повністю відновити. У нашому випадку, оскільки ми знаємо справжнє членство в кластері, ми можемо порівняти його з результатом, щоб побачити, наскільки це було добре. Як я зазначав вище, насправді є 3 латентні кластери, але дані дають вигляд двох кластерів:
pc$clustering[1:15] # these were actually cluster 1 in the data generating process
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# 1 1 1 1 1 2 1 1 1 1 1 2 1 2 1
pc$clustering[16:30] # these were actually cluster 2 in the data generating process
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
# 2 2 1 1 1 2 1 2 1 2 2 1 2 1 2
pc$clustering[31:45] # these were actually cluster 3 in the data generating process
# 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
# 2 1 2 2 2 2 1 2 1 2 2 2 2 2 2