Подтвердить что ты не робот

Как можно реализовать алгоритм K-Means ++?

У меня проблемы с полным пониманием алгоритма K-Means ++. Меня интересует, как именно выбираются первые центроиды k, а именно инициализация, как и остальные, как в оригинальном алгоритме K-средних.

  1. Используется ли функция вероятности на основе расстояния или гауссова?
  2. В то же время самая длинная дальняя точка (от других центроидов) выбрана для нового центроида.

Буду признателен пошаговое объяснение и пример. То, что в Википедии, недостаточно ясно. Также очень хорошо прокомментированный исходный код также поможет. Если вы используете 6 массивов, пожалуйста, сообщите нам, какой из них предназначен для чего.

4b9b3361

Ответ 1

Интересный вопрос Спасибо за то, что вы обратили мое внимание на этот документ - K-Means ++: Преимущества тщательного посева

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

Вот одномерный пример. Наши наблюдения [0, 1, 2, 3, 4]. Пусть первый центр, c1, равен 0. Вероятность того, что следующий центр кластера, c2, равен x, пропорциональна ||c1-x||^2. Итак, P (c2 = 1) = 1a, P (c2 = 2) = 4a, P (c2 = 3) = 9a, P (c2 = 4) = 16a, где a = 1/(1 + 4 + 9 + 16).

Предположим, с2 = 4. Тогда P (c3 = 1) = 1a, P (c3 = 2) = 4a, P (c3 = 3) = 1a, где a = 1/(1 + 4 + 1).

Я кодировал процедуру инициализации в Python; Я не знаю, поможет ли это вам.

def initialize(X, K):
    C = [X[0]]
    for k in range(1, K):
        D2 = scipy.array([min([scipy.inner(c-x,c-x) for c in C]) for x in X])
        probs = D2/D2.sum()
        cumprobs = probs.cumsum()
        r = scipy.rand()
        for j,p in enumerate(cumprobs):
            if r < p:
                i = j
                break
        C.append(X[i])
    return C

ОБНОВЛЕНИЕ с уточнением: Вывод cumsum дает нам границы для разбиения интервала [0,1]. Эти перегородки имеют длину, равную вероятности выбора соответствующей точки в качестве центра. Итак, поскольку r выбирается равномерно между [0,1], он попадает точно в один из этих интервалов (из-за break). Цикл for проверяет, в каком разделе r находится.

Пример:

probs = [0.1, 0.2, 0.3, 0.4]
cumprobs = [0.1, 0.3, 0.6, 1.0]
if r < cumprobs[0]:
    # this event has probability 0.1
    i = 0
elif r < cumprobs[1]:
    # this event has probability 0.2
    i = 1
elif r < cumprobs[2]:
    # this event has probability 0.3
    i = 2
elif r < cumprobs[3]:
    # this event has probability 0.4
    i = 3

Ответ 2

Один лайнер.

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

Ответ 3

Я подготовил полную реализацию k-средств ++ на основе книги "Коллективный разум" Тоби Сегарана и инициализации k-menas ++, представленной здесь.

Действительно, здесь есть две функции расстояния. Для начальных центроидов стандартный используется на основе numpy.inner, а затем для фиксации центроидов используется Pearson. Возможно, Pearson можно также использовать для начальных центроидов. Говорят, это лучше.

from __future__ import division

def readfile(filename):
  lines=[line for line in file(filename)]
  rownames=[]
  data=[]
  for line in lines:
    p=line.strip().split(' ') #single space as separator
    #print p
    # First column in each row is the rowname
    rownames.append(p[0])
    # The data for this row is the remainder of the row
    data.append([float(x) for x in p[1:]])
    #print [float(x) for x in p[1:]]
  return rownames,data

from math import sqrt

def pearson(v1,v2):
  # Simple sums
  sum1=sum(v1)
  sum2=sum(v2)

  # Sums of the squares
  sum1Sq=sum([pow(v,2) for v in v1])
  sum2Sq=sum([pow(v,2) for v in v2])    

  # Sum of the products
  pSum=sum([v1[i]*v2[i] for i in range(len(v1))])

  # Calculate r (Pearson score)
  num=pSum-(sum1*sum2/len(v1))
  den=sqrt((sum1Sq-pow(sum1,2)/len(v1))*(sum2Sq-pow(sum2,2)/len(v1)))
  if den==0: return 0

  return 1.0-num/den

import numpy
from numpy.random import *

def initialize(X, K):
    C = [X[0]]
    for _ in range(1, K):
        #D2 = numpy.array([min([numpy.inner(c-x,c-x) for c in C]) for x in X])
        D2 = numpy.array([min([numpy.inner(numpy.array(c)-numpy.array(x),numpy.array(c)-numpy.array(x)) for c in C]) for x in X])
        probs = D2/D2.sum()
        cumprobs = probs.cumsum()
        #print "cumprobs=",cumprobs
        r = rand()
        #print "r=",r
        i=-1
        for j,p in enumerate(cumprobs):
            if r 0:
        for rowid in bestmatches[i]:
          for m in range(len(rows[rowid])):
            avgs[m]+=rows[rowid][m]
        for j in range(len(avgs)):
          avgs[j]/=len(bestmatches[i])
        clusters[i]=avgs

  return bestmatches

rows,data=readfile('/home/toncho/Desktop/data.txt')

kclust = kcluster(data,k=4)

print "Result:"
for c in kclust:
    out = ""
    for r in c:
        out+=rows[r] +' '
    print "["+out[:-1]+"]"

print 'done'

data.txt:


p1 1 5 6
p2 9 4 3
p3 2 3 1
p4 4 5 6
p5 7 8 9
p6 4 5 4
p7 2 5 6
p8 3 4 5
p9 6 7 8