Bạn đúng rằng phân cụm k-nghĩa không nên được thực hiện với dữ liệu của các loại hỗn hợp. Vì k-mean về cơ bản là một thuật toán tìm kiếm đơn giản để tìm một phân vùng thu nhỏ khoảng cách Euclide bình phương trong cụm giữa các quan sát cụm và tâm khối, nên chỉ được sử dụng với dữ liệu trong đó khoảng cách Euclide bình phương sẽ có ý nghĩa.
Khi dữ liệu của bạn bao gồm các biến của các loại hỗn hợp, bạn cần sử dụng khoảng cách của Gower. Người dùng CV @ttnphns có một cái nhìn tổng quan tuyệt vời về khoảng cách của Gower tại đây . Về bản chất, bạn lần lượt tính toán một ma trận khoảng cách cho các hàng của mình cho từng biến, sử dụng một loại khoảng cách phù hợp với loại biến đó (ví dụ: Euclide cho dữ liệu liên tục, v.v.); khoảng cách cuối cùng của hàng đến là trung bình (có thể có trọng số) của khoảng cách cho mỗi biến. Một điều cần lưu ý là khoảng cách của Gower không thực sự là một số liệu . Tuy nhiên, với dữ liệu hỗn hợp, khoảng cách của Gower phần lớn là trò chơi duy nhất trong thị trấn. i 'tôitôi'
Tại thời điểm này, bạn có thể sử dụng bất kỳ phương pháp phân cụm nào có thể hoạt động trên ma trận khoảng cách thay vì cần ma trận dữ liệu gốc. (Lưu ý rằng k-mean cần cái sau.) Các lựa chọn phổ biến nhất là phân vùng xung quanh medoid (PAM, về cơ bản giống như k-mean, nhưng sử dụng quan sát trung tâm nhất thay vì centroid), các cách tiếp cận phân cấp khác nhau (ví dụ: , trung vị, liên kết đơn và liên kết hoàn chỉnh, với phân cụm theo phân cấp, bạn sẽ cần phải quyết định nơi ' cắt cây ' để có được các bài tập cụm cuối cùng) và DBSCAN cho phép hình dạng cụm linh hoạt hơn nhiều.
Đây là một R
bản demo đơn giản (nb, thực tế có 3 cụm, nhưng dữ liệu chủ yếu trông giống như 2 cụm là phù hợp):
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))
Chúng ta có thể bắt đầu bằng cách tìm kiếm trên các cụm khác nhau với 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"
Những kết quả này có thể được so sánh với kết quả của phân cụm phân cấp:
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)
Phương pháp trung bình gợi ý 2 cụm (có thể là 3), đơn chỉ hỗ trợ 2, nhưng phương pháp hoàn chỉnh có thể gợi ý 2, 3 hoặc 4 cho mắt tôi.
Cuối cùng, chúng ta có thể thử DBSCAN. Điều này yêu cầu chỉ định hai tham số: eps, 'khoảng cách có thể tiếp cận' (khoảng cách hai quan sát phải được liên kết với nhau) và minPts (số điểm tối thiểu cần được kết nối với nhau trước khi bạn sẵn sàng gọi chúng là 'cụm'). Một nguyên tắc nhỏ đối với minPts là sử dụng nhiều hơn một số lượng kích thước (trong trường hợp của chúng tôi là 3 + 1 = 4), nhưng không nên sử dụng số lượng quá nhỏ. Giá trị mặc định cho dbscan
là 5; chúng tôi sẽ gắn bó với điều đó. Một cách để suy nghĩ về khoảng cách có thể tiếp cận là xem phần trăm khoảng cách nhỏ hơn bất kỳ giá trị nào. Chúng ta có thể làm điều đó bằng cách kiểm tra phân phối khoảng cách:
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")
Khoảng cách dường như tập hợp thành các nhóm rõ ràng 'gần hơn' và 'xa hơn'. Giá trị .3 dường như phân biệt rõ ràng nhất giữa hai nhóm khoảng cách. Để khám phá độ nhạy của đầu ra với các lựa chọn khác nhau của eps, chúng ta cũng có thể thử .2 và .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
Sử dụng eps=.3
không cung cấp một giải pháp rất sạch, mà (ít nhất là về mặt chất lượng) đồng ý với những gì chúng ta thấy từ các phương pháp khác ở trên.
Vì không có cụm 1-ness có ý nghĩa , chúng ta nên cẩn thận khi cố gắng khớp các quan sát nào được gọi là 'cụm 1' từ các cụm khác nhau. Thay vào đó, chúng ta có thể tạo các bảng và nếu hầu hết các quan sát được gọi là 'cụm 1' trong một phù hợp được gọi là 'cụm 2' trong một bảng khác, chúng ta sẽ thấy rằng kết quả vẫn tương tự nhau. Trong trường hợp của chúng tôi, các cụm khác nhau chủ yếu là rất ổn định và đặt các quan sát giống nhau trong cùng một cụm mỗi lần; chỉ phân cụm liên kết phân cấp hoàn chỉnh khác nhau:
# 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
Tất nhiên, không có gì đảm bảo rằng bất kỳ phân tích cụm nào sẽ phục hồi các cụm tiềm ẩn thực sự trong dữ liệu của bạn. Sự vắng mặt của các nhãn cụm thực sự (sẽ có sẵn trong một tình huống hồi quy logistic) có nghĩa là một lượng lớn thông tin không có sẵn. Ngay cả với các bộ dữ liệu rất lớn, các cụm có thể không được phân tách đủ tốt để có thể phục hồi hoàn hảo. Trong trường hợp của chúng tôi, vì chúng tôi biết thành viên cụm thực sự, chúng tôi có thể so sánh điều đó với đầu ra để xem nó đã làm tốt như thế nào. Như tôi đã lưu ý ở trên, thực tế có 3 cụm tiềm ẩn, nhưng dữ liệu cho sự xuất hiện của 2 cụm thay thế:
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