我正在尝试编写一种方法,允许我计算3维中的对象数量,这些对象属于具有3维坐标的另一个对象。你可以说这个有值的物体也有一个半径,所以我试图计算一个球体内物体的数量。
我不会发布我当前的剧本,但我会尝试一个例子:我有一个3D坐标为gal_pos
且半径为gal_rad
的星系。
import numpy as np
gal_pos = np.array(
[[ 528.1373291 , 432.18615723, 443.8348999 ],
[ 540.12231445, 450.08154297, 442.07891846],
[ 590.73675537, 234.6769104 , 296.02798462],
[ 529.98809814, 161.75544739, 567.58203125],
[ 552.45446777, 312.1973877 , 375.42492676],
[ 700.94335938, 65.46828461, 172.71842957],
[ 463.43258667, 73.57706451, 285.4147644 ],
[ 547.74414062, 330.9855957 , 401.49771118],
[ 591.89801025, 196.19670105, 274.60073853],
[ 581.28320312, 376.70013428, 359.81851196],
[ 520.09820557, 302.17849731, 371.68771362],
[ 812.84539795, 97.41672516, 150.87428284],
[ 541.6552124 , 17.40070724, 373.07562256],
[ 523.34509277, 302.18151855, 503.6333313 ]])
gal_rad = np.array(
[ 1.14752779, 1.02471195, 0.79648002, 0.6085083 , 0.78725676,
1.07809084, 0.57744866, 0.93733404, 0.76053329, 0.68979678,
0.61188519, 1.07989271, 0.83872035, 0.59899661])
然后我还有3D位置star_pos
的星星。
star_pos = np.array(
[[ 517.0300293 , 264.54165649, 547.87835693],
[ 530.37280273, 358.40835571, 455.68734741],
[ 530.42211914, 358.20803833, 455.80908203],
[ 530.86737061, 324.91717529, 407.96405029],
[ 547.05175781, 333.9262085 , 403.82403564],
[ 530.61053467, 325.91259766, 407.04153442],
[ 533.9979248 , 331.18804932, 451.3795166 ],
[ 531.20678711, 326.75308228, 406.44711304],
[ 550.81237793, 340.88101196, 408.75830078],
[ 519.52880859, 299.91259766, 516.25140381],
[ 525.82739258, 301.46209717, 501.66738892],
[ 524.87988281, 268.88357544, 510.0123291 ],
[ 524.43371582, 299.99725342, 512.36077881],
[ 524.40429688, 299.8979187 , 512.57452393],
[ 524.40765381, 299.89120483, 512.5032959 ],
[ 545.57440186, 331.59066772, 401.20291138],
[ 532.29016113, 306.27557373, 491.26434326],
[ 530.77410889, 326.18057251, 407.06216431],
[ 524.14819336, 306.60586548, 509.55993652]])
以上只是我所拥有的价值的一个样本。
xmax_rad = gal_pos[:,0]+gal_rad
xmin_rad = gal_pos[:,0]-gal_rad
ymax_rad = gal_pos[:,1]+gal_rad
ymin_rad = gal_pos[:,1]-gal_rad
zmax_rad = gal_pos[:,2]+gal_rad
zmin_rad = gal_pos[:,2]-gal_rad
tot_pop = [] # Total population found each galaxy
Nind = [(x,y,z) for x,y,z in enumerate(star_pos)
if any(xmin_rad <=x<= xmax_rad) and
any(ymin_rad<=y<=ymax_rad)
and any(zmin_rad<=x<=zmax_rad)]
tot_pop.append(Nind)
print tot_pop
我尝试的这种方法通过分解所有内容对我来说最有意义,但这用于大小为〜300的数组,但是ValueError: need more than 2 values to unpack
返回Nind
。可能由于我的迭代无法解压缩3个对象的事实?
我已经尝试了其他方法,其中我取每个位置的大小,但它返回不正确的结果,以及通过直方图计数值,但同样,返回不正确的结果(我检查通过在2d直方图中投影所有内容) 。我为每个星系编制索引的方法为每个星系返回空数组:
tot_pop = []
for k in np.arange(len(gal_pos)):
Nind = [(x,y) for x,y in enumerate(star_pos)
if xmin_rad[k] <=x<= xmax_rad[k]) and
ymin_rad[k]<=y<=ymax_rad[k]]
tot_pop.append(Nind)
答案 0 :(得分:3)
您可以使用zip
迭代星系+半径,然后使用广播和布尔索引来查找匹配项:
result = []
for galaxy, galaxy_radius in zip(gal_pos, gal_rad):
# With broadcasting you can simply subtract the positions from the galaxy center
# and using abs avoids checking lower and upper bound.
rel_star_pos = abs(star_pos - galaxy)
# Check which distances are below the radius and keep these which are
# within the radius for x, y and z
matches = (rel_star_pos <= galaxy_radius).all(axis=1)
# use boolean indexing to append the stars which satisfy the above condition
result.append(star_pos[matches])
print(result)
如果您想要附加索引(而不是实际的星座坐标),可以将append
行更改为:
result.append(np.where(matches)[0])
或者如果您只想要匹配数量:
result.append(np.sum(matches))
但是我无法找到与给定数据匹配的任何内容:
[array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64),
array([], shape=(0, 3), dtype=float64)]
答案 1 :(得分:3)
这里有一个几乎矢量化的方法,利用高效的NumPy broadcasting
和slicing
来帮助 -
# Define low and high limits
l = gal_pos - gal_rad[:,None]
h = gal_pos + gal_rad[:,None]
# Get mask of valid ones for each row of star_pos
mask = np.ones(star_pos.shape[0], dtype=bool)
for i in range(star_pos.shape[1]):
mask &= ((l[:,i,None] <= star_pos[:,i]) & (h[:,i,None] >= star_pos[:,i])).any(0)
# Finally use the mask to select valid rows off star_pos
out = star_pos[mask]
将其称为几乎矢量化,因为我们仍在迭代star_pos
中的列数。但是,由于我们正在处理X,Y,Z
数据,因此3
。因此,出于这个原因,将其称为几乎是矢量化是安全的。
对于给定的样本,这是我得到的 -
In [302]: out
Out[302]: array([], shape=(0, 3), dtype=float64)
因此,来自star_pos
的点数不会满足限制。