【问题标题】:How to calculate centroid of x,y coordinates in python如何在python中计算x,y坐标的质心
【发布时间】:2013-11-10 04:31:22
【问题描述】:

我有很多 x,y 坐标,我根据它们之间的距离对它们进行了聚类。 现在我想为每个 x,y 坐标簇计算质心测量值。 有没有办法做到这一点?

我的坐标格式为:

    coordinates_cluster = [[x1,x2,x3,...],[y1,y2,y3,...]]

每个簇的最小长度为三个点,所有点的 x 和 y 值都可以为负值和正值。 我希望有人可以帮助我。

最好, 马丁

(我在 Windows 7 系统上使用带有 canopy 1.1.1(32 位)的 python 2.7。)

【问题讨论】:

标签: python points coordinate-systems centroid


【解决方案1】:

我意识到这并不难,但这里是计算 x,y 坐标质心的代码:

    >>> c = [[1,4,-5],[3,-2,9]] # of the form [[x1,x2,x3],[y1,y2,y3]]
    >>> centroide = (sum(c[0])/len(c[0]),sum(c[1])/len(c[1]))

    >>> centroide
    (0, 3)

【讨论】:

  • 您对整数结果是否满意,而不是更精确的小数或浮点数?您的 y 质心是 10/3 或 3.33333,而不是 3。
【解决方案2】:

恕我直言,这里给出的公认答案不适用于您想要计算由一组 (x,y) 顶点(又名多边形)定义的形状的质心的典型现实生活用例。所以请原谅我回答了一个差不多 8 年前提出的问题,但它仍然在我的 SO 搜索中名列前茅,所以它也可能会出现在其他人身上。我并不是说在问题的具体情况下接受的答案是错误的,但我认为,大多数找到这个线程的人实际上是根据不同的定义寻找质心。

质心未定义为顶点的算术平均值

...这与普遍看法相反。 我们必须承认,通常通过质心,我们想到的是“图中所有点的算术平均位置”。非正式地,它是形状的切口可以在针尖上完美平衡的点”(引用维基百科,这里引用了实际的文献)。请注意,它是图中的所有点,而不仅仅是顶点坐标的平均值。 这正是,如果您接受大多数 SO 答案,您将出错的地方,这意味着质心是顶点的 x 和 y 坐标的算术平均值,并将其应用于您可能通过执行实验收集的现实生活数据.
描述您的形状的点的密度可能会沿着您的形状线变化。这只是所述方法的许多可能的限制之一。那么坐标的简单平均值肯定不是你想要的。我会用一个例子来说明这一点。

示例


在这里,我们看到一个由 8 个顶点组成的多边形。我们的直觉正确地告诉我们,我们可以在 (x,y)=(0,0) 的针尖上平衡这个形状,使质心 (0,0)。但是在 (-1,1) 周围的区域中,我们用来描述该多边形的点/顶点的密度高于沿线的其他区域。现在如果我们通过取顶点的平均值来计算质心,结果将被拉向高密度区域。
点“centroid poly”对应于真实的质心。该点是通过执行此处描述的算法计算得出的:https://en.wikipedia.org/wiki/Centroid#Of_a_polygon(唯一区别:它返回区域的绝对值)
它适用于由 N 个顶点的 x 和 y 坐标描述的图形,例如 X = x_0, x_1, ..., x_(N-1),对于 Y 也是如此。这个图形可以是任何多边形,只要它是非自相交的并且顶点按出现的顺序给出。
这可以用来计算例如matplotlib 等高线的“真实”质心。

代码

这是上面例子的代码和算法的实现:

import matplotlib.pyplot as plt

def centroid_poly(X, Y):
    """https://en.wikipedia.org/wiki/Centroid#Of_a_polygon"""
    N = len(X)
    # minimal sanity check
    if not (N == len(Y)): raise ValueError('X and Y must be same length.')
    elif N < 3: raise ValueError('At least 3 vertices must be passed.')
    sum_A, sum_Cx, sum_Cy = 0, 0, 0
    last_iteration = N-1
    # from 0 to N-1
    for i in range(N):
        if i != last_iteration:
            shoelace = X[i]*Y[i+1] - X[i+1]*Y[i]
            sum_A  += shoelace
            sum_Cx += (X[i] + X[i+1]) * shoelace
            sum_Cy += (Y[i] + Y[i+1]) * shoelace
        else:
            # N-1 case (last iteration): substitute i+1 -> 0
            shoelace = X[i]*Y[0] - X[0]*Y[i]
            sum_A  += shoelace
            sum_Cx += (X[i] + X[0]) * shoelace
            sum_Cy += (Y[i] + Y[0]) * shoelace
    A  = 0.5 * sum_A
    factor = 1 / (6*A)
    Cx = factor * sum_Cx
    Cy = factor * sum_Cy
    # returning abs of A is the only difference to
    # the algo from above link
    return Cx, Cy, abs(A)

# ********** example ***********
X = [-1, -0.8,  -0.6,  1,   2,  1, -1,   -2]
Y = [ 1,    1,     1,  1, 0.5, -1, -1, -0.5]

Cx, Cy, A = centroid_poly(X, Y)

# calculating centroid as shown by the accepted answer
Cx_accepted = sum(X)/len(X)
Cy_accepted = sum(Y)/len(Y)

fig, ax = plt.subplots()
ax.scatter(X, Y, label='vertices')
ax.scatter(Cx_accepted, Cy_accepted, label="mean of vertices")
ax.scatter(Cx, Cy, label='centroid poly')

# just so the line plot connects xy_(N-1) and xy_0
X.append(X[0]), Y.append(Y[0])
ax.plot(X, Y, label='polygon')

ax.legend(bbox_to_anchor=(1, 1))
ax.grid(), ax.set_aspect('equal')

【讨论】:

    【解决方案3】:

    如果您有兴趣计算几何或信号处理中定义的质心 [12]

    import numpy as np
    # a line from 0,0 to 1,1
    x = np.linspace(0, 1, 100)
    y = np.linspace(0, 1, 100)
    cx = np.dot(x, y) / np.sum(y)
    

    0.67003367003367

    【讨论】:

      猜你喜欢
      • 2018-10-06
      • 1970-01-01
      • 1970-01-01
      • 2011-01-23
      • 1970-01-01
      • 2020-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多