在R中使用Kmeans的一致群集顺序

时间:2016-10-06 17:47:32

标签: r k-means

这可能是不可能的,但到目前为止谷歌已经让我失望,所以我希望其他人可能有一些见解。对不起,如果之前有人询问过。

背景是,我有一个关于不同城市的信息数据库,所以像年份一样,名称,人口,污染,犯罪等。我查询它以按城市汇总数据并将结果输出到表格。这很好。

下一步是我在数据集上运行R中的kmeans()函数来查找集群,在测试中我发现5个集群几乎总是一个很好的选择,通过&#34肘法"。

我遇到的问题是这些群集具有不同的含义/解释,因此我想用原始数据集中的每一行标记该行的解释,而不是群集号。因此,我不想用第3组"第3组来识别第2行,我想说"低人口,高犯罪率,低收入"。

如果R会以相同的顺序输出集群,那么假设集群5总是等同于人口较少,犯罪率高,收入较低的城市集群,这样可以正常工作,但它不会#39;吨。例如,如果您运行如下代码:

> a =  kmeans(city_date,centers=5)
> b =  kmeans(city_date,centers=5)
> c =  kmeans(city_date,centers=5)

运行此代码:

a$centers
b$centers
c$centers

群集将包含相同的数据集,但群集编号将不同。因此,如果我在SQL中有一个具有簇号和解释的映射表,它就不会起作用,因为当我运行它有一天它可能会有低人口,高犯罪率,低收入"群集为5,下一个可能是2,接下来的4,等等。

我想弄清楚的是,是否有办法保持输出的一致性。数据集会得到更新,因此每次都不会相同,而且即使使用相同的数据集,R也不会保持集群顺序一致,我想知道它是否可行。

感谢任何人提供的任何帮助。在我的最后,我目前的想法是将$ centers数据输出到SQL表,然后按各种指标对表进行排序,每次最高/最低的数据被标记为这样,然后连接结果以标记级别。这可能有用,但并不优雅。

5 个答案:

答案 0 :(得分:2)

我知道这是一个很老的帖子,但我现在才遇到它。我今天遇到了同样的问题,并根据Barker提出的建议来提出解决方案:

library(dplyr)

# create a random data frame
df <- data.frame(id = 1:10, obs = sample(0:500, 10))

# use kmeans a first time to get the centers
centers <- kmeans(df$obs, centers = 3)$centers

# order the centers
centers <- sort(centers)

# call kmeans again but this time passing the centers calculated in the previous step
clusteridx <- kmeans(df$obs, centers = centers)$cluster

不是很优雅,但它有效。 clusteridx向量将始终根据中心按升序返回簇编号。

如果您愿意,也可以将其折叠为一行:

clusteridx <- kmeans(df$obs, centers = sort(kmeans(df$obs, centers = 3)$centers))$cluster

答案 1 :(得分:1)

通常k-means随机初始化几次以避免局部最小值。如果要生成有序的聚类,则必须在k-means算法停止工作后手动对它们进行排序。

答案 2 :(得分:1)

我自己没有这样做,所以我不确定它是否会奏效,但kmeans有参数:

  • centers - 群集数量,例如k,或一组初始(不同)群集中心。如果是数字,则选择x中随机的(不同)行作为初始中心。

如果您基本知道群集应该在哪里(可能是通过从您匹配的数据集中获取群集中心),则可以使用它来初始化模型。这将使起始位置非随机,因此群集应保持相同的顺序。此外,作为额外的好处,将群集中心初始化到接近最终的位置可以加快群集速度。

修改

我刚刚使用kmeans示例中的数据进行了检查,但是使用(1,1)处的第一个数据点和(0,0)处的第二个数据点进行初始化(用于生成群集的分布方式)如下。

x <- rbind(matrix(rnorm(100, sd = 0.3), ncol = 2),
           matrix(rnorm(100, mean = 1, sd = 0.3), ncol = 2))
colnames(x) <- c("x", "y")
(cl <- kmeans(x, matrix(c(1,0,1,0),ncol=2)))
plot(x, col = cl$cluster)
points(cl$centers, col = 1:2, pch = 8, cex = 2)

重复运行后,我发现第一个集群始终位于右上角,第二个集群始终位于左下角,而2集群初始化则导致来回切换。如果您的群集具有一些近似的起始值(即,#34;低人口,高犯罪率,低收入&#34;的量化),这可能是您的初始化并为您提供所需的结果。

答案 3 :(得分:0)

在此示例中,将字母因子组归因于k均值聚类,从A到C的顺序从高到低。可以更改参数以适合您的数据。

df <- data.frame(id = 1:10, obs = sample(0:500, 10))
km <- kmeans(df$obs, centers = 3)
km.order <- as.numeric(names(sort(km$centers[,1])))
names(km.order) <- toupper(letters)[1:3]
km.order <- sort(km.order)
clus.order <- factor(names(km.order[km$cluster]))

答案 4 :(得分:0)

此函数使用一维输入运行kmeans,并返回具有合理编号簇的普通“ kmeans”对象,而无需两次运行kmeans。

ordered_kmeans = function(x, centers, iter.max = 10, nstart = 1,
                          algorithm = c("Hartigan-Wong", "Lloyd", "Forgy",
                                        "MacQueen"), 
                          trace = FALSE,
                          desc = TRUE) {

  if (NCOL(x) > 1) {
    stop("only one-dimensional inputs are allowed")
  }
  
  k = kmeans(x = x, centers = centers, iter.max = iter.max, nstart = nstart,
             algorithm = algorithm, trace = trace)
  
  centers_ind = order(k$centers, decreasing = desc)
  
  centers_ord = setNames(seq_along(k$centers), nm = centers_ind)
  
  k$cluster  = unname(centers_ord[as.character(k$cluster)])
  k$centers  = matrix(k$centers[centers_ind], ncol = 1)
  k$withinss = k$withinss[centers_ind]
  k$size     = k$size[centers_ind]
 
  k
}

用法示例:

vec = c(20.28, 9.49, 7.14, 2.48, 2.36, 1.82, 1.3, 1.26, 1.11, 0.98, 
        0.81, 0.73, 0.66, 0.63, 0.57, 0.53, 0.44, 0.42, 0.38, 0.37, 0.33, 
        0.29, 0.28, 0.27, 0.26, 0.23, 0.23, 0.2, 0.18, 0.16, 0.15, 0.14, 
        0.14, 0.12, 0.11, 0.1, 0.1, 0.08)

# For comparispon
set.seed(1)
k = kmeans(vec, centers = 3); k

set.seed(1)
k = ordered_kmeans(vec, centers = 3); k

set.seed(1)
k = ordered_kmeans(vec, centers = 3, desc = FALSE); k