我有很多 x,y 坐标,我根据它们之间的距离进行了聚类。现在我想为每个 x,y 坐标簇计算质心测量值。有没有办法做到这一点?
我的坐标格式为:
coordinates_cluster = [[x1,x2,x3,...],[y1,y2,y3,...]]
每个簇的最小长度为三个点,并且所有点都可以有负和正的 x 和 y 值。我希望有人能帮助我。
最好的,马丁
(我在 Windows 7 系统上使用带有 canopy 1.1.1(32 位)的 python 2.7。)
我有很多 x,y 坐标,我根据它们之间的距离进行了聚类。现在我想为每个 x,y 坐标簇计算质心测量值。有没有办法做到这一点?
我的坐标格式为:
coordinates_cluster = [[x1,x2,x3,...],[y1,y2,y3,...]]
每个簇的最小长度为三个点,并且所有点都可以有负和正的 x 和 y 值。我希望有人能帮助我。
最好的,马丁
(我在 Windows 7 系统上使用带有 canopy 1.1.1(32 位)的 python 2.7。)
我意识到这并不难,但这里是计算 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)
恕我直言,此处给出的公认答案不适用于您想要计算由一组(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')