Согласованный порядок кластеров с Kmeans в R

#r #k-means

#r #k-означает

Вопрос:

Это может быть невозможно, но Google пока меня подвел, поэтому я надеюсь, что у кого-то еще может быть некоторое представление. Извините, если об этом спрашивали раньше.

Предыстория в том, что у меня есть база данных с информацией о разных городах, например, о названии, населении, загрязнении, преступности и т. Д. По годам. Я запрашиваю его для агрегирования данных по каждому городу и вывода результата в таблицу. Это работает нормально.

Следующим шагом я запускаю функцию kmeans() в R в наборе данных для поиска кластеров, в ходе тестирования я обнаружил, что 5 кластеров почти всегда являются хорошим выбором с помощью «метода локтя».

Проблема, с которой я сталкиваюсь, заключается в том, что эти кластеры имеют разные значения / интерпретации, поэтому я хочу пометить каждую строку в исходном наборе данных интерпретацией кластера для этой строки, а не номером кластера. Поэтому я не хочу отождествлять строку 2 с «кластером 5», я хочу сказать «низкая численность населения, высокая преступность, низкий доход».

Если R будет выводить кластеры в том же порядке, скажем, если кластер 5 всегда приравнивается к кластеру городов с «низким населением, высокой преступностью, низким доходом», это будет работать нормально, но это не так. Например, если вы выполняете код, подобный этому:

 > 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, затем упорядочить таблицу по различным метрикам, каждый раз, когда тот, у которого самый высокий / самый низкий, помечается как таковой, а затем объединить результаты для обозначения уровня. Это может работать, но не очень элегантно.

Ответ №1:

Я знаю, что это очень старый пост, но я наткнулся на него только сейчас. Сегодня у меня была такая же проблема, и я адаптировал предложение Баркера, чтобы найти решение:

 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
  

Ответ №2:

Обычно k-средние инициализируются случайным образом несколько раз, чтобы избежать локальных минимумов. Если вы хотите упорядочить результирующие кластеры, вы должны упорядочить их вручную после того, как алгоритм k-means перестанет работать.

Комментарии:

1. Спасибо! Итак, меня интересует порядок вручную, это будет частью конвейера данных, поэтому я не могу просматривать кластеры при каждом запуске. Я бы предпочел сделать что-то на R или найти какой-нибудь не SQL-способ сохранения последовательности кластерных порядков, если это возможно.

2. Извините, я не могу помочь с R.

Ответ №3:

Я сам этого не делал, поэтому я не уверен, что это сработает, но kmeans имеет параметр:

  • centers — либо количество кластеров, скажем, k, либо набор начальных (отдельных) центров кластера. Если число, случайный набор (отдельных) строк в x выбирается в качестве начальных центров.

Если вы знаете, в основном знаете, где должны быть кластеры (возможно, путем получения центров кластеров из набора данных, с которым вы сопоставляете), вы можете использовать это для инициализации модели. Это сделало бы начальные местоположения неслучайными, поэтому кластеры должны оставаться в том же порядке. Кроме того, в качестве дополнительного преимущества инициализация центров кластеров вблизи того места, где они окажутся, должна ускорить кластеризацию.

Редактировать

Я только что проверил, используя данные из kmeans примера, но инициализируя с первой точкой данных at (1,1) и второй at (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 помощью кластеров приводила к переключению назад и вперед. Если у вас есть некоторые приблизительные начальные значения для ваших кластеров (т. Е. Количественная оценка для «низкой численности населения, высокой преступности, низкого дохода»), это может быть вашей инициализацией и дать вам желаемые результаты.

Ответ №4:

Эта функция запускает 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
  

Ответ №5:

Вот пример, в котором вы приписываете группы буквенных коэффициентов кластерам k-means, упорядоченным от 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]))