python:计算质心
python: calculate center of mass
我有一个包含 4 列的数据集:x、y、z 和值,比方说:
x y z value
0 0 0 0
0 1 0 0
0 2 0 0
1 0 0 0
1 1 0 1
1 2 0 1
2 0 0 0
2 1 0 0
2 2 0 0
我想计算所有值的质心 CM = (x_m,y_m,z_m)
。在本示例中,我希望看到 (1,1.5,0)
作为输出。
我以为这一定是个小问题,但我在网上找不到解决办法。 scipy.ndimage.measurements.center_of_mass
似乎是正确的,但不幸的是,函数总是 returns 两个值(而不是 3)。此外,我找不到任何关于如何从数组设置 ndimage
的文档:Would I use a numpy array N of shape (9,4)
?那么 N[:,0] 会是 x 坐标吗?
非常感谢任何帮助。
怎么样:
# x y z value
table = np.array([[ 5. , 1.3, 8.3, 9. ],
[ 6. , 6.7, 1.6, 5.9],
[ 9.1, 0.2, 6.2, 3.7],
[ 2.2, 2. , 6.7, 4.6],
[ 3.4, 5.6, 8.4, 7.3],
[ 4.8, 5.9, 5.7, 5.8],
[ 3.7, 1.1, 8.2, 2.2],
[ 0.3, 0.7, 7.3, 4.6],
[ 8.1, 1.9, 7. , 5.3],
[ 9.1, 8.2, 3.3, 5.3]])
def com(xyz, mass):
mass = mass.reshape((-1, 1))
return (xyz * mass).mean(0)
print(com(table[:, :3], table[:, 3]))
我能想到的最简单的方法是:找到质量分量坐标的平均值,这些分量由每个分量的贡献加权。
import numpy
masses = numpy.array([[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 2, 0, 0],
[1, 0, 0, 0],
[1, 1, 0, 1],
[1, 2, 0, 1],
[2, 0, 0, 0],
[2, 1, 0, 0],
[2, 2, 0, 0]])
nonZeroMasses = masses[numpy.nonzero(masses[:,3])] # Not really necessary, can just use masses because 0 mass used as weight will work just fine.
CM = numpy.average(nonZeroMasses[:,:3], axis=0, weights=nonZeroMasses[:,3])
另一种选择是使用 scipy 质心:
from scipy import ndimage
import numpy
masses = numpy.array([[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 2, 0, 0],
[1, 0, 0, 0],
[1, 1, 0, 1],
[1, 2, 0, 1],
[2, 0, 0, 0],
[2, 1, 0, 0],
[2, 2, 0, 0]])
ndimage.measurements.center_of_mass(masses)
为什么ndimage.measurements.center_of_mass
没有给出预期的结果?
关键在于输入数据 masses
如何由 4 元组 (x, y, z, value) 的数组表示
# x y z value
[[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 2, 0, 0],
[1, 0, 0, 0],
[1, 1, 0, 1],
[1, 2, 0, 1],
[2, 0, 0, 0],
[2, 1, 0, 0],
[2, 2, 0, 0]]
这里的数组masses
表示每个质量块的三维位置和权重。
但是请注意,此 python 数组结构只是一个二维数组。它的形状是 (9, 4).
您需要传递给 ndimage 以获得预期结果的输入是一个 3-D 数组,其中到处都包含零,并且每个质量的权重位于数组内的适当坐标处,如下所示:
from scipy import ndimage
import numpy
masses = numpy.zeros((3, 3, 1))
# x y z value
masses[1, 1, 0] = 1
masses[1, 2, 0] = 1
CM = ndimage.measurements.center_of_mass(masses)
# x y z
# (1.0, 1.5, 0.0)
这正是预期的输出。
请注意此解决方案(和 ndimage 库)的局限性是它需要非负整数坐标。对于大型 and/or 稀疏体积也不会有效,因为 ndimage 的每个“像素”都需要在内存中实例化。
我有一个包含 4 列的数据集:x、y、z 和值,比方说:
x y z value
0 0 0 0
0 1 0 0
0 2 0 0
1 0 0 0
1 1 0 1
1 2 0 1
2 0 0 0
2 1 0 0
2 2 0 0
我想计算所有值的质心 CM = (x_m,y_m,z_m)
。在本示例中,我希望看到 (1,1.5,0)
作为输出。
我以为这一定是个小问题,但我在网上找不到解决办法。 scipy.ndimage.measurements.center_of_mass
似乎是正确的,但不幸的是,函数总是 returns 两个值(而不是 3)。此外,我找不到任何关于如何从数组设置 ndimage
的文档:Would I use a numpy array N of shape (9,4)
?那么 N[:,0] 会是 x 坐标吗?
非常感谢任何帮助。
怎么样:
# x y z value
table = np.array([[ 5. , 1.3, 8.3, 9. ],
[ 6. , 6.7, 1.6, 5.9],
[ 9.1, 0.2, 6.2, 3.7],
[ 2.2, 2. , 6.7, 4.6],
[ 3.4, 5.6, 8.4, 7.3],
[ 4.8, 5.9, 5.7, 5.8],
[ 3.7, 1.1, 8.2, 2.2],
[ 0.3, 0.7, 7.3, 4.6],
[ 8.1, 1.9, 7. , 5.3],
[ 9.1, 8.2, 3.3, 5.3]])
def com(xyz, mass):
mass = mass.reshape((-1, 1))
return (xyz * mass).mean(0)
print(com(table[:, :3], table[:, 3]))
我能想到的最简单的方法是:找到质量分量坐标的平均值,这些分量由每个分量的贡献加权。
import numpy
masses = numpy.array([[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 2, 0, 0],
[1, 0, 0, 0],
[1, 1, 0, 1],
[1, 2, 0, 1],
[2, 0, 0, 0],
[2, 1, 0, 0],
[2, 2, 0, 0]])
nonZeroMasses = masses[numpy.nonzero(masses[:,3])] # Not really necessary, can just use masses because 0 mass used as weight will work just fine.
CM = numpy.average(nonZeroMasses[:,:3], axis=0, weights=nonZeroMasses[:,3])
另一种选择是使用 scipy 质心:
from scipy import ndimage
import numpy
masses = numpy.array([[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 2, 0, 0],
[1, 0, 0, 0],
[1, 1, 0, 1],
[1, 2, 0, 1],
[2, 0, 0, 0],
[2, 1, 0, 0],
[2, 2, 0, 0]])
ndimage.measurements.center_of_mass(masses)
为什么ndimage.measurements.center_of_mass
没有给出预期的结果?
关键在于输入数据 masses
如何由 4 元组 (x, y, z, value) 的数组表示
# x y z value
[[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 2, 0, 0],
[1, 0, 0, 0],
[1, 1, 0, 1],
[1, 2, 0, 1],
[2, 0, 0, 0],
[2, 1, 0, 0],
[2, 2, 0, 0]]
这里的数组masses
表示每个质量块的三维位置和权重。
但是请注意,此 python 数组结构只是一个二维数组。它的形状是 (9, 4).
您需要传递给 ndimage 以获得预期结果的输入是一个 3-D 数组,其中到处都包含零,并且每个质量的权重位于数组内的适当坐标处,如下所示:
from scipy import ndimage
import numpy
masses = numpy.zeros((3, 3, 1))
# x y z value
masses[1, 1, 0] = 1
masses[1, 2, 0] = 1
CM = ndimage.measurements.center_of_mass(masses)
# x y z
# (1.0, 1.5, 0.0)
这正是预期的输出。
请注意此解决方案(和 ndimage 库)的局限性是它需要非负整数坐标。对于大型 and/or 稀疏体积也不会有效,因为 ndimage 的每个“像素”都需要在内存中实例化。