使用python的kmeans实现中的空列表

使用python的kmeans实现中的空列表,python,cluster-analysis,k-means,Python,Cluster Analysis,K Means,我正在为一个项目编写一个K-Means集群,该项目使用集群来识别对象,因此机器人几乎可以自由自主。照相机基本上在半秒钟内拍摄一张照片 速率,它存储在像素的“blob”中。这个blob被发送到数据挖掘算法k-means,该算法将对象的“阴影”识别为一个簇,因此可以对机器人进行编程以避免这些区域。我发布了我的k-means代码。它是用python编写的 import sys, math, random class Point: def __init__(self, coords, ref

我正在为一个项目编写一个K-Means集群,该项目使用集群来识别对象,因此机器人几乎可以自由自主。照相机基本上在半秒钟内拍摄一张照片
速率,它存储在像素的“blob”中。这个blob被发送到数据挖掘算法k-means,该算法将对象的“阴影”识别为一个簇,因此可以对机器人进行编程以避免这些区域。我发布了我的k-means代码。它是用python编写的

import sys, math, random

class Point:

    def __init__(self, coords, reference=None):
        self.coords     = coords
        self.n          = len(coords)
        self.reference  = reference

    def __repr__(self):
        return str(self.coords)

class Cluster:

    def __init__(self, points):

        if len(points) == 0: 
            raise Exception("ILLEGAL: empty cluster")

        self.points = points
        self.n      = points[0].n       # make the first element to be the number of clusters

        for p in points:
            if p.n != self.n:
                raise Exception("ILLEGAL: wrong dimension")

        self.centroid = self.calculateCentroid()

    def __repr__(self):
        return str(self.points)

    def update(self, points):
        old_centroid    = self.centroid
        self.points     = points
        self.centroid   = self.calculateCentroid()
        return getDistance(old_centroid, self.centroid)

    def calculateCentroid(self):
        reduce_coord = lambda i:reduce(lambda x,p : x + p.coords[i], self.points, 0.0)
        if len(self.points) == 0:
            print "Dividing by 0"
            self.points = [1]
        centroid_coords = [reduce_coord(i) / len(self.points) for i in range(self.n)]

        return Point(centroid_coords)

def kmeans(points, k, cutoff):

    initial = random.sample(points, k)
    clusters = [Cluster([p]) for p in initial]
    print clusters
    while True:
        lists = [ [] for c in clusters]
        for p in points:
            smallest_distance   = getDistance(p, clusters[0].centroid)
            index = 0

            for i in range(len(clusters[1:])):
                distance = getDistance(p, clusters[i+1].centroid)
                if distance < smallest_distance:

                    smallest_distance = distance
                    index = i+1

                lists[index].append(p)
            biggest_shift = 0.0

            for i in range(len(clusters)):
                shift = clusters[i].update(lists[i])
                biggest_shift = max(biggest_shift, shift)

            if biggest_shift < cutoff:
                break

    return clusters

def getDistance(a, b):

    if a.n != b.n:
        raise Exception("ILLEGAL: non comparable points")

    ret = reduce(lambda x, y: x + pow((a.coords[y] - b.coords[y]), 2), range(a.n), 0.0)
    return math.sqrt(ret)

def makeRandomPoint(n, lower, upper):
    return Point([random.uniform(lower, upper) for i in range(n)])

def main():
    num_points, dim, k, cutoff, lower, upper = 10, 2, 3, 0.5, 0, 200
    points = map(lambda i: makeRandomPoint(dim, lower, upper), range(num_points))

    clusters = kmeans(points, k, cutoff)

    for i, c in enumerate(clusters):
        for p in c.points:
            print "Cluster: ", i, "\t Point: ", p


if __name__ == "__main__":
    main()    
导入系统、数学、随机
课程点:
定义初始化(self,coords,reference=None):
self.coords=coords
self.n=len(coords)
self.reference=reference
定义报告(自我):
返回str(self.coords)
类别群集:
定义初始值(自身,点):
如果len(点)==0:
引发异常(“非法:空群集”)
self.points=点
self.n=points[0].n#将第一个元素设为簇数
对于p in点:
如果p.n!=self.n:
引发异常(“非法:错误维度”)
self.centroid=self.calculateCentroid()
定义报告(自我):
返回str(自身点数)
def更新(自我,积分):
旧形心=自形心
self.points=点
self.centroid=self.calculateCentroid()
返回getDistance(旧形心、自形心)
def计算重心(自身):
reduce_coord=lambda i:reduce(lambda x,p:x+p.coords[i],self.points,0.0)
如果len(自身点)==0:
打印“除以0”
self.points=[1]
质心坐标=[范围(self.n)内i的减少坐标(i)/len(self.points)]
返回点(质心坐标)
def kmeans(点、k、截止点):
初始=随机样本(点,k)
clusters=[Cluster([p])表示初始值中的p]
打印群集
尽管如此:
列表=[[]对于集群中的c]
对于p in点:
最小距离=getDistance(p,簇[0]。质心)
索引=0
对于范围内的i(len(簇[1:]):
距离=getDistance(p,簇[i+1]。质心)
如果距离<最小距离:
最小距离=距离
指数=i+1
列表[索引]。追加(p)
最大位移=0.0
对于范围内的i(len(簇)):
shift=群集[i]。更新(列表[i])
最大移位=最大(最大移位,移位)
如果最大位移<截止值:
打破
返回簇
def getDistance(a、b):
如果a.n!=b、 n:
提出例外(“非法:不可比分数”)
ret=减小(λx,y:x+pow((a.coords[y]-b.coords[y]),2),范围(a.n),0.0)
返回math.sqrt(ret)
def生成点(n、下、上):
返回点([范围(n)内i的随机均匀(下,上)])
def main():
点数、尺寸、k、截止值、下限、上限=10、2、3、0.5、0、200
点=地图(lambda i:makeRandomPoint(暗、下、上)、范围(num_点))
集群=kmeans(点、k、截止点)
对于枚举(集群)中的i、c:
对于c点中的p:
打印“群集:”,i,“\t点:”,p
如果名称=“\uuuuu main\uuuuuuuu”:
main()
果然不行

  Traceback (most recent call last):
  File "C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py", line 100, in ?
    main()    
  File "C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py", line 92, in main
[    clusters = kmeans(points, k, cutoff)
[[89.152748179548524, 81.217634455465131]], [[83.439023369838509, 169.75355953688432]], [[1.8622622156419633, 41.364078271733739]]]
Dividing by 0
  File "C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py", line 69, in kmeans
    shift = clusters[i].update(lists[i])
  File "C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py", line 35, in update
    self.centroid   = self.calculateCentroid()
  File "C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py", line 43, in calculateCentroid
    centroid_coords = [reduce_coord(i) / len(self.points) for i in range(self.n)]
  File "C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py", line 39, in <lambda>
    reduce_coord = lambda i:reduce(lambda x,p : x + p.coords[i], self.points, 0.0)
  File "C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py", line 39, in <lambda>
    reduce_coord = lambda i:reduce(lambda x,p : x + p.coords[i], self.points, 0.0)
AttributeError: 'int' object has no attribute 'coords'
回溯(最近一次呼叫最后一次):
文件“C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py”,第100行,在?
main()
文件“C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py”,第92行,主目录
[集群=kmeans(点、k、截止点)
[[89.152748179548524, 81.217634455465131]], [[83.439023369838509, 169.75355953688432]], [[1.8622622156419633, 41.364078271733739]]]
除以0
文件“C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py”,第69行,在kmeans中
shift=群集[i]。更新(列表[i])
文件“C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py”,第35行,在更新中
self.centroid=self.calculateCentroid()
文件“C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py”,第43行,位于CalculateCenter中
质心坐标=[范围(self.n)内i的减少坐标(i)/len(self.points)]
文件“C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py”,第39行,在
reduce_coord=lambda i:reduce(lambda x,p:x+p.coords[i],self.points,0.0)
文件“C:\Users\philippe\Documents\workspace-sts-2.7.2.RELEASE\scribber\kmeans\kmeans.py”,第39行,在
reduce_coord=lambda i:reduce(lambda x,p:x+p.coords[i],self.points,0.0)
AttributeError:“int”对象没有属性“coords”
当我在
中执行打印时,在函数
kmeans(点,k,截止点)
中列出了

[]、[]、[]]
。我想弄明白,为什么那会给我一张空名单。我发布了整个代码,因此可以运行代码并复制错误。在错误日志中,可以看到“集群”是什么:点列表。
感谢

问题在于,如果距离给定簇最近的点列表为空(所有点都离不同簇较近),那么您将得到一个除以0的错误,此时您将垃圾数据分配给self.points,这将导致您看到的最终错误

如果两个簇具有相同的质心,则这是可能的,在这种情况下,第二个簇将永远不会为其指定点

顺便说一下,还有一个bug。你前面有一个额外的缩进 列表[索引]。追加(p) 无论如何,您应该考虑使用枚举和min重写整个循环,以使其更干净。

下面是我建议重写的方法

while True:
    newPoints = dict([(c,[]) for c in clusters])
    for p in points:
        cluster = min(clusters, key = lambda c:getDistance(p, c.centroid))
        newPoints[cluster].append(p)

    biggest_shift = 0.0

    for c in clusters:
        if newPoints[c]:
            shift = c.update(newPoints[c])
            biggest_shift = max(biggest_shift, shift)

    if biggest_shift < cutoff:
        break
为True时:
newPoints=dict([(c,[])表示集群中的c])
对于p in点:
cluster=min(clusters,key=lambda c:getDistance(p,c.centroid))
新点[簇]