我有应用k均值的数据集,并且有两个聚类,但是从特定点(x,y)到两个聚类的距离相同,然后该点将进入哪个聚类。请帮我。 预先感谢。
答案 0 :(得分:3)
在平局的情况下,k-均值聚类将随机将歧义点分配给聚类。 (这是基于R对k均值聚类kmeans
的实现。)
iris
数据的具体示例让我们从加载必要的R库开始
library(broom)
library(tidyverse)
在此示例中,我们将使用Petal.Length
数据集中的Petal.Width
和iris
测量值,为简单起见,将“ virginica”测量值排除在外,以便“ setosa”和“多功能”测量值构成了我们的两组。
df <- iris %>%
filter(Species != "virginica") %>%
select(starts_with("Petal"), Species)
我们现在使用k = 2的k均值聚类,并为每个(Petal.Length
,Petal.Width
)度量分配聚类标签;由于哪个组是“ 1”而哪个组是“ 2”的分配是随机的,因此我们使用固定的种子来提高可重复性。
set.seed(2018)
kcl <- kmeans(df %>% select(-Species), 2)
df <- augment(kcl, df)
我们显示了Petal.Length
与Petal.Width
的散点图;已知的Species
标签用不同的颜色显示,推断的聚类关联用不同的符号显示。
ggplot(df, aes(Petal.Length, Petal.Width, colour = Species)) +
geom_point(aes(shape = .cluster), size = 3)
让我们手动计算成对成对距离的集群内和;因为我们以后也会需要它,所以我们将创建一个函数calculate_d
。
calculate_d <- function(df) {
df %>%
select(.cluster, Petal.Length, Petal.Width) %>%
group_by(.cluster) %>%
nest() %>%
mutate(dist = map_dbl(data, ~sum(as.matrix(dist(.x)^2)) / (2 * nrow(.x)))) %>%
pull(dist)
}
calculate_d(df)
#[1] 2.0220 12.7362
请注意,距离与集群内平方和(WCSS)的距离如何相同
kcl$withinss
#[1] 2.0220 12.7362
现在,让我们添加一个新的度量,该度量到两个聚类中心的距离是相同的欧几里得距离:为此,如果您将它们以直线连接,则选择正好位于两个聚类中心之间的中间的点。然后,我们需要的是一些基本的三角函数来构造该点:
z <- kcl$centers[2, ] - kcl$center[1, ]
theta <- atan(z[2] / z[1])
dy <- sin(theta) * dist(kcl$centers) / 2
dx <- cos(theta) * dist(kcl$centers) / 2
x <- as.numeric(kcl$centers[1, 1] + dx)
y <- as.numeric(kcl$centers[1, 2] + dy)
我们将新点和2个聚类中心存储在新的data.frame
中。前两行给出聚类“ 1”和“ 2”的位置,第三行包含我们的新点。
df2 <- bind_rows(as.data.frame(kcl$centers), c(Petal.Length = x, Petal.Width = y))
让我们在(Petal.Length
,Petal.Width
)测量的顶部显示新点以及聚类中心。
df2 <- bind_rows(as.data.frame(kcl$centers), c(Petal.Length = x, Petal.Width = y))
ggplot(df, aes(Petal.Length, Petal.Width)) +
geom_point(aes(colour = Species, shape = .cluster), size = 3) +
geom_point(data = df2, aes(Petal.Length, Petal.Width), size = 4)
我们确认新点和每个聚类中心之间的平方欧几里得距离确实相同;为此,我们计算新点“ 3”到聚类中心“ 1”和“ 2”的成对距离:
as.matrix(dist(df2))[, 3]
# 1 2 3
#1.4996 1.4996 0.0000
现在,让我们将新点添加到(Petal.Length
,Petal.Width
)测量中,并计算成对平方距离的簇内和,首先将新点分配给簇“ 1” ”,然后将新点分配给群集“ 2”。
# Add new point and assign to cluster "1"
df.1 <- df %>%
bind_rows(cbind.data.frame(
Petal.Length = x,
Petal.Width = y,
Species = factor("setosa", levels = levels(df$Species)),
.cluster = factor(1, levels = 1:2)))
calculate_d(df.1)
#[1] 4.226707 12.736200
# Add new point and assign to cluster "2"
df.2 <- df %>%
bind_rows(cbind.data.frame(
Petal.Length = x,
Petal.Width = y,
Species = factor("versicolor", levels = levels(df$Species)),
.cluster = factor(2, levels = 1:2)))
calculate_d(df.2)
#[1] 2.02200 14.94091
请注意,即使新点到任一聚类中心的距离都完全相同,聚类内部平方对的距离也不同。但是请注意,集群内平方对距离的 sum 相同!
sum(calculate_d(df.1))
#[1] 16.96291
sum(calculate_d(df.2))
#[1] 16.96291
identical(sum(calculate_d(df.2)), sum(calculate_d(df.1)))
# [1] TRUE
为表明kmeans
将新点随机分配给任一聚类,我们反复对数据进行聚类。为此,我们定义了一个便利函数,该函数在k均值聚类之后返回新点的相应Species
。
kmeans_cluster_data <- function(df) {
kcl <- kmeans(df %>% select(-Species), 2)
df <- augment(kcl, df)
map_cluster_to_Species <- df[1:(nrow(df) - 1), ] %>%
count(Species, .cluster) %>%
split(., .$.cluster)
map_cluster_to_Species[[
df[nrow(df), ] %>%
pull(.cluster) %>%
as.character()]]$Species %>% as.character()
}
我们现在将同一数据重复群集100次。
bind_cols(
Iteration = 1:100,
Species = map_chr(1:100, ~kmeans_cluster_data(df.1 %>% select(-.cluster)))) %>%
ggplot(aes(Iteration, Species, group = 1)) +
geom_line() +
labs(title = "Assignment of new point to group")
请注意如何将新点随机分配给Species
组。