J'ai du mal à bien comprendre le algorithme K-Means ++ . Je suis intéressé exactement comment les premiers centroïdes k
sont choisis, à savoir l'initialisation car le reste est comme dans l'original algorithme K-Means .
J'apprécierai une explication étape par étape et un exemple. Celui de Wikipedia n'est pas assez clair. Un code source très bien commenté serait également utile. Si vous utilisez 6 tableaux, veuillez nous indiquer lequel est pour quoi.
Question interessante. Merci d'avoir porté ce document à mon attention - K-Means ++: The Advantages of Careful Seeding
En termes simples, les centres de grappes sont initialement choisis au hasard dans l'ensemble des vecteurs d'observation d'entrée, où la probabilité de choisir le vecteur x
est élevée si x
n'est proche d'aucun centre précédemment choisi.
Voici un exemple unidimensionnel. Nos observations sont [0, 1, 2, 3, 4]. Soit le premier centre, c1
, soit 0. La probabilité que le prochain centre de cluster, c2
, est x est proportionnel à ||c1-x||^2
. Donc, P (c2 = 1) = 1a, P (c2 = 2) = 4a, P (c2 = 3) = 9a, P (c2 = 4) = 16a, où a = 1/(1 + 4 + 9 + 16).
Supposons que c2 = 4. Alors, P (c3 = 1) = 1a, P (c3 = 2) = 4a, P (c3 = 3) = 1a, où a = 1/(1 + 4 + 1).
J'ai codé la procédure d'initialisation en Python; Je ne sais pas si cela vous aide.
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
EDIT avec clarification: La sortie de cumsum
nous donne des limites pour partitionner l'intervalle [0,1]. Ces partitions ont une longueur égale à la probabilité que le point correspondant soit choisi comme centre. Alors, puisque r
est uniformément choisi entre [0,1], il tombera exactement dans l'un de ces intervalles (à cause de break
). La boucle for
vérifie quelle partition r
se trouve.
Exemple:
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
Bon mot.
Supposons que nous devons sélectionner 2 centres de cluster, au lieu de les sélectionner tous de façon aléatoire {comme nous le faisons en termes k simples}, nous sélectionnerons le premier au hasard, puis trouverons les points les plus éloignés du premier centre {Ces points le font probablement n'appartiennent pas au premier centre de cluster car ils en sont éloignés} et affectez le deuxième centre de cluster à proximité de ces points éloignés.
J'ai préparé une implémentation source complète de k-means ++ basée sur le livre "Collective Intelligence" de Toby Segaran et l'initialisation de k-menas ++ fournie ici.
En effet, il existe ici deux fonctions de distance. Pour les centroïdes initiaux, un standard est utilisé basé sur numpy.inner, puis pour la fixation des centroïdes, le Pearson est utilisé. Peut-être que celui de Pearson peut également être utilisé pour les centroïdes initiaux. Ils disent que c'est mieux.
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