49 votes

Algorithme k-means de Python

Je recherche une implémentation Python de l'algorithme k-means avec des exemples pour regrouper et mettre en cache ma base de données de coordonnées.

1 votes

J'ai fait une implémentation similaire pour les images. Vous pouvez utiliser des tableaux 2d au lieu des valeurs RGB. C'est très naïf mais ça marche pour moi. github.com/keremgocen/pattern-recog-notes .

57voto

tom10 Points 19886

Mise à jour : (Onze ans après cette réponse originale, il est probablement temps de faire une mise à jour).

Tout d'abord, tu es sûr de vouloir les k-means ? Cette page donne un excellent résumé graphique de différents algorithmes de clustering. Je suggère qu'au-delà du graphique, vous regardiez surtout les paramètres que chaque méthode requiert et que vous décidiez si vous pouvez fournir le paramètre requis (par exemple, k-means requiert le nombre de clusters, mais peut-être ne le savez-vous pas avant de commencer le clustering).

Voici quelques ressources :

Vieille réponse :

Le clustering de Scipy fonctionnent bien, et elles comprennent une k-means mise en œuvre.

Il y a aussi scipy-cluster qui fait du clustering agglomératif ; cela a l'avantage que vous n'avez pas besoin de décider du nombre de clusters à l'avance.

0 votes

Pourquoi scipy est-il préféré à sklean pour les k-means ? Ayant utilisé les deux récemment, j'ai trouvé que je préférais l'implémentation de sklearn.

29voto

Vebjorn Ljosa Points 6215

SciPy kmeans2() a quelques problèmes numériques : d'autres ont signalé des messages d'erreur tels que "Matrix is not positive definite - Cholesky decomposition cannot be computed" dans la version 0.6.0, et je viens de rencontrer le même problème dans la version 0.7.1.

Pour l'instant, je recommande d'utiliser PyCluster à la place. Exemple d'utilisation :

>>> import numpy
>>> import Pycluster
>>> points = numpy.vstack([numpy.random.multivariate_normal(mean, 
                                                            0.03 * numpy.diag([1,1]),
                                                            20) 
                           for mean in [(1, 1), (2, 4), (3, 2)]])
>>> labels, error, nfound = Pycluster.kcluster(points, 3)
>>> labels  # Cluster number for each point
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], dtype=int32)
>>> error   # The within-cluster sum of distances for the solution
1.7721661785401261
>>> nfound  # Number of times this solution was found
1

2 votes

Il semble également que la fonction scipy cluster kmeans n'accepte pas de méthode de distance et utilise toujours l'euclidienne. Une autre raison d'utiliser PyCluster ?

0 votes

Je viens de rencontrer l'erreur mentionnée... Je vois dans votre exemple les regroupements de clusters, mais pouvez-vous obtenir le "centre" du cluster ?

0 votes

@monkup, numpy.vstack([points[labels == i].mean(0) for i in range(labels.max() + 1)]) pour obtenir les centres des clusters.

21voto

Nathan Points 2414

Pour les données continues, la méthode k-means est très simple.

Vous avez besoin d'une liste de vos moyennes, et pour chaque point de données, trouvez la moyenne dont il est le plus proche et faites la moyenne du nouveau point de données par rapport à celle-ci. Vos moyennes représenteront les groupes de points saillants récents dans les données d'entrée.

Je fais la moyenne en continu, il n'est donc pas nécessaire d'avoir les anciennes données pour obtenir la nouvelle moyenne. Étant donné l'ancienne moyenne k ,le point de données suivant x et une constante n qui est le nombre de points de données passés dont il faut conserver la moyenne, la nouvelle moyenne est de

k*(1-(1/n)) + n*(1/n)

Voici le code complet en Python

from __future__ import division
from random import random

# init means and data to random values
# use real data in your code
means = [random() for i in range(10)]
data = [random() for i in range(1000)]

param = 0.01 # bigger numbers make the means change faster
# must be between 0 and 1

for x in data:
    closest_k = 0;
    smallest_error = 9999; # this should really be positive infinity
    for k in enumerate(means):
        error = abs(x-k[1])
        if error < smallest_error:
            smallest_error = error
            closest_k = k[0]
        means[closest_k] = means[closest_k]*(1-param) + x*(param)

Vous pourriez simplement imprimer les moyennes lorsque toutes les données sont passées, mais c'est beaucoup plus amusant de les voir changer en temps réel. Je l'ai utilisé sur des enveloppes de fréquences de sons de 20 ms et, après lui avoir parlé pendant une minute ou deux, il a trouvé des catégories cohérentes pour la voyelle "a" courte, la voyelle "o" longue et la consonne "s".

0 votes

Il s'agit d'un excellent algorithme d'apprentissage en ligne des kmeans ! Mais il y a un bug à la dernière ligne du code. Il faut supprimer un onglet sur cette ligne : means[closest_k] = means[closest_k]*(1-param) + x*(param)

6voto

denis Points 7316

(Des années plus tard) ce kmeans.py sous est-il possible de spécifier sa propre fonction de distance à l'aide de la méthode d'apprentissage des sciences est simple et raisonnablement rapide ; il utilise l'une des 20 métriques de scipy.spatial.distance.

5voto

Jacob Points 22306

De wikipedia vous pouvez utiliser scipy, Regroupement K-means et quantification vectorielle

Ou bien, vous pouvez utiliser un wrapper Python pour OpenCV, ctypes-opencv .

Ou vous pourriez La nouvelle interface Python d'OpenCV et leurs kmeans mise en œuvre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X