คุณมีสิทธิ์ที่การจัดกลุ่ม k หมายถึงไม่ควรทำกับข้อมูลประเภทผสม เนื่องจาก k-mean นั้นเป็นอัลกอริธึมการค้นหาแบบง่าย ๆ เพื่อค้นหาพาร์ติชันที่ลดระยะห่างระหว่างยูคลิดสแควร์ภายในกระจุกระหว่างการสังเกตแบบกระจุกดาวกับคลัสเตอร์เซนทรอยด์ดังนั้นจึงควรใช้กับข้อมูลที่ระยะทางยูคลิด
เมื่อข้อมูลของคุณประกอบด้วยตัวแปรประเภทผสมคุณต้องใช้ระยะทางของโกเวอร์ @ttnphns ใช้ CV มีภาพรวมที่ดีของระยะทางโกเวอร์ที่นี่ ในสาระสำคัญคุณคำนวณเมทริกซ์ระยะทางสำหรับแถวของคุณสำหรับแต่ละตัวแปรในทางกลับกันโดยใช้ชนิดของระยะทางที่เหมาะสมสำหรับตัวแปรประเภทนั้น (เช่น Euclidean สำหรับข้อมูลต่อเนื่องเป็นต้น); ระยะทางสุดท้ายของแถวถึงคือค่าเฉลี่ยของระยะทางสำหรับตัวแปรแต่ละตัว สิ่งหนึ่งที่ต้องระวังก็คือว่าระยะทางโกเวอร์ไม่จริงตัวชี้วัด อย่างไรก็ตามด้วยข้อมูลที่หลากหลายระยะทางของโกเวอร์จึงเป็นเกมเดียวในเมือง ผม'
ณ จุดนี้คุณสามารถใช้วิธีการจัดกลุ่มใด ๆ ที่สามารถทำงานบนเมทริกซ์ระยะทางแทนการต้องการเมทริกซ์ข้อมูลดั้งเดิม (โปรดทราบว่า 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 (จำนวนจุดต่ำสุดที่ต้องเชื่อมต่อกันก่อนที่คุณจะเรียกพวกมันว่า 'กลุ่ม') กฎง่ายๆสำหรับ 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 ที่แตกต่างกันเราสามารถลอง. 0.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-nessเราควรระมัดระวังในการพยายามจับคู่การสังเกตที่เรียกว่า 'คลัสเตอร์ 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 กลุ่ม แต่ข้อมูลให้ลักษณะของกลุ่มที่ 2 แทน:
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