我怎样才能加快这个功能
How could I speed up this function
我正在从 Vizier 下载星表(使用 astroquery)。相关星表不包含星名,因此我通过查询每颗 Vizier 星表 1 弧秒内的所有 SIMBAD 星,从 SIMBAD(也使用 astroquery)获取这些星名。
然后我需要通过 ra/dec 坐标进行匹配。但是,Vizier 和 SIMBAD 坐标可能都有些不准确,因此我无法进行精确匹配。
我目前的解决方案是指定一个公差,并为每个 Vizier 星调用下面的函数来循环遍历 SIMBAD 星,测试坐标是否符合指定的公差。作为复核,因为恒星可以非常靠近,我还检查恒星的星等是否匹配在 0.1 等以内。
除了包含约 2,000 颗恒星的 Vizier 星表和类似大小的 SIMBAD 数据集之外,这一切都可行 运行。我正在寻找加快速度的想法。
def get_simbad_name(self, vizier_star, simbad_stars, tolerance):
"""
Searches simbad_stars to find the SIMBAD name of the star
referenced in vizier_star.
A match is deemed to exist if a star in simbad_stars has both
ra and dec +/- tolerance of the target vizier_star and if their V
magnitudes, rounded to one decimal place, also match.
Parameters
==========
vizier_star : astropy.table.Row
Row of results from Vizier query, corresponding to a star in a
Vizier catalog. Columns of interest to this function are:
'_RAJ2000' : float [Right ascension in decimal degrees]
'_DEJ2000' : float [Declination in decimal degrees]
'Vmag' : float [V magnitude (to 3 decimal places)]
simbad_stars : list of dict
List of star data derived from a Vizier query. Keys of interest
to this function are:
'ra' : float [Right ascension in decimal degrees (ICRS/J2000)]
'dec' : float [Declination in decimal degrees (ICRS/J2000)]
'Vmag' : float [V magnitude (to 3 decimal places)]
'name' : str [SIMBAD primary id of star]
tolerance : float
The tolerance, in degrees, to be used in determining whether
the ra/dec coordinates match.
Returns
=======
name : str
If match then returns the SIMBAD name. If no match returns
an empty string.
Notes
=====
simbad_stars are not all guaranteed to have Vmag. Any that don't are
ignored.
"""
for item in simbad_stars:
try:
approx_Vmag = round(item['Vmag'],1)
except KeyError:
continue
if ((vizier_star['_RAJ2000'] > item['ra'] - tolerance) and
(vizier_star['_RAJ2000'] < item['ra'] + tolerance) and
(vizier_star['_DEJ2000'] > item['dec'] - tolerance) and
(vizier_star['_DEJ2000'] < item['dec'] + tolerance) and
(round(vizier_star['Vmag'],1) == approx_Vmag)):
return item['name']
return ''
评论后的一些想法:
匹配成功率非常高(大约 99%),因此几乎在所有情况下循环都会提前退出。它不必迭代所有 simbad_stars。
如果我按 ra 预排序 simbad_stars 并使用二进制印章获取循环开始位置的索引,我可以进一步改进。
这个问题看起来会因为提问的方式而被关闭,但有两个有用的答案:
(1) 对于位置 cross-matching,参见 https://docs.astropy.org/en/stable/coordinates/matchsep.html
(2) 对于您在这里所做的一般情况,您应该使用矢量化操作,而不是循环遍历源。
通过 pre-sorting simbad_stars 并使用 bisect_left 和 bisect_right 在其中定义开始和停止索引,我已经设法将速度提高了 20 倍。
如果有人感兴趣,我可以 post 代码(它比原来的代码长一点,因为它是使用自定义 class 的更通用的解决方案)。
我正在从 Vizier 下载星表(使用 astroquery)。相关星表不包含星名,因此我通过查询每颗 Vizier 星表 1 弧秒内的所有 SIMBAD 星,从 SIMBAD(也使用 astroquery)获取这些星名。
然后我需要通过 ra/dec 坐标进行匹配。但是,Vizier 和 SIMBAD 坐标可能都有些不准确,因此我无法进行精确匹配。
我目前的解决方案是指定一个公差,并为每个 Vizier 星调用下面的函数来循环遍历 SIMBAD 星,测试坐标是否符合指定的公差。作为复核,因为恒星可以非常靠近,我还检查恒星的星等是否匹配在 0.1 等以内。
除了包含约 2,000 颗恒星的 Vizier 星表和类似大小的 SIMBAD 数据集之外,这一切都可行 运行。我正在寻找加快速度的想法。
def get_simbad_name(self, vizier_star, simbad_stars, tolerance):
"""
Searches simbad_stars to find the SIMBAD name of the star
referenced in vizier_star.
A match is deemed to exist if a star in simbad_stars has both
ra and dec +/- tolerance of the target vizier_star and if their V
magnitudes, rounded to one decimal place, also match.
Parameters
==========
vizier_star : astropy.table.Row
Row of results from Vizier query, corresponding to a star in a
Vizier catalog. Columns of interest to this function are:
'_RAJ2000' : float [Right ascension in decimal degrees]
'_DEJ2000' : float [Declination in decimal degrees]
'Vmag' : float [V magnitude (to 3 decimal places)]
simbad_stars : list of dict
List of star data derived from a Vizier query. Keys of interest
to this function are:
'ra' : float [Right ascension in decimal degrees (ICRS/J2000)]
'dec' : float [Declination in decimal degrees (ICRS/J2000)]
'Vmag' : float [V magnitude (to 3 decimal places)]
'name' : str [SIMBAD primary id of star]
tolerance : float
The tolerance, in degrees, to be used in determining whether
the ra/dec coordinates match.
Returns
=======
name : str
If match then returns the SIMBAD name. If no match returns
an empty string.
Notes
=====
simbad_stars are not all guaranteed to have Vmag. Any that don't are
ignored.
"""
for item in simbad_stars:
try:
approx_Vmag = round(item['Vmag'],1)
except KeyError:
continue
if ((vizier_star['_RAJ2000'] > item['ra'] - tolerance) and
(vizier_star['_RAJ2000'] < item['ra'] + tolerance) and
(vizier_star['_DEJ2000'] > item['dec'] - tolerance) and
(vizier_star['_DEJ2000'] < item['dec'] + tolerance) and
(round(vizier_star['Vmag'],1) == approx_Vmag)):
return item['name']
return ''
评论后的一些想法:
匹配成功率非常高(大约 99%),因此几乎在所有情况下循环都会提前退出。它不必迭代所有 simbad_stars。
如果我按 ra 预排序 simbad_stars 并使用二进制印章获取循环开始位置的索引,我可以进一步改进。
这个问题看起来会因为提问的方式而被关闭,但有两个有用的答案:
(1) 对于位置 cross-matching,参见 https://docs.astropy.org/en/stable/coordinates/matchsep.html
(2) 对于您在这里所做的一般情况,您应该使用矢量化操作,而不是循环遍历源。
通过 pre-sorting simbad_stars 并使用 bisect_left 和 bisect_right 在其中定义开始和停止索引,我已经设法将速度提高了 20 倍。
如果有人感兴趣,我可以 post 代码(它比原来的代码长一点,因为它是使用自定义 class 的更通用的解决方案)。