在列表迭代中防止多个匹配

时间:2016-07-29 15:59:49

标签: python numpy

我是python的新手,所以我会尽力解释我想要做的事情。我试图遍历两个星形列表(两个都包含记录数组),试图通过它们的坐标匹配恒星与公差(在这种情况下Ra和Dec,它们都是记录数组中的索引)。但是,一个列表中似乎有多个星星与另一个星星中的相同星星相匹配。 *这是因为atol中的两个星都匹配。有办法防止这种情况吗?这是我到目前为止所做的:

from __future__ import print_function
import numpy as np    

###importing data###
Astars = list()
for s in ApStars:###this is imported but not shown
    Astars.append(s)

wStars = list()
data1 = np.genfromtxt('6819.txt', dtype=None, delimiter=',', names=True)
for star in data1:
    wStars.append(star)

###beginning matching stars between the Astars and wStars###
list1 = list()
list2 = list()
for star,s in [(star,s) for star in wStars for s in Astars]:
    if np.logical_and(np.isclose(s["RA"],star["RA"], atol=0.000277778)==True , 
                      np.isclose(s["DEC"],star["DEC"],atol=0.000277778)==True): 
        if star not in list1:   
            list1.append(star) #matched wStars
        if s not in list2:
            list2.append(s) #matched Astars

我不能减少atol,因为它超出了乐器错误。会发生什么:有多个Wstars匹配一个Astar。如果有可能的话,我只想要一颗恒星作为明星。

有什么建议吗?

4 个答案:

答案 0 :(得分:1)

我会完全改变你的方法以适应这些是你所谈论的天文物体的事实。我将忽略加载功能,并假设您已经有输入列表AstarwStar

我们会使用笛卡尔点积找到wStarAstar中每颗恒星的最近星。那个应该帮助解决关于最佳匹配的任何含糊之处。

# Pre-process the data a little
def getCV(ra, de):
    return np.array([np.cos(aStar['DE']) * np.cos(aStar['RA']),
                     np.cos(aStar['DE']) * np.sin(aStar['RA']),
                     np.sin(aStar['DE'])])

for aStar in Astars:
    aStar['CV'] = getCV(aStar['RA'], aStar['DE'])
for wStar in wStars:
    wStar['CV'] = getCV(wStar['RA'], wStar['DE'])

# Construct lists of matching stars
aList = []
wList = []

# This an extra list of lists of stars that are within tolerance but are
# not best matches. This list will contain empty sublists, but never None
wCandidates []

for aStar in AStars:
    for wStar in wStars:
        # Use native short-circuiting, and don't explicitly test for `True`
        if np.isclose(aStar["RA"], wStar["RA"], atol=0.000277778) and \
           np.isclose(aStar["DEC"], wStar["DEC"], atol=0.000277778):
            newDot = np.dot(aStar['CV'], wStar['CV'])
            if aStar == aList[-1]:
                # This star already has a match, possibly update it
                if newDot > bestDot:
                    bestDot = newDot
                    # Move the previous best match to list of candidates
                    wCandidates[-1].append(wList[-1])
                    wList[-1] = wStar
                else:
                    wCandidates[-1].append(wStar)
             else:
                 # This star does not yet have a match
                 bestDot = newDot
                 aList.append(aStar)
                 wList.append(wStar)
                 wCandidates.append([])

结果是wList中每个索引处的星号代表aList中相应星号的最佳匹配。并非所有的星星都有匹配,因此并非所有星星都出现在任何一个列表中。请注意,可能会有一些(非常不可能)的情况,aList中的星号与wList中的星号不匹配。

我们通过计算基于these formulas的笛卡尔单位向量并取点积来找到两颗恒星之间最接近的绝对距离。点越接近一个,星星越接近。这应该有助于解决模棱两可的问题。

我为主循环外的星星预先计算了笛卡尔向量,以避免为wStars反复进行。键名'CV'代表笛卡尔矢量。根据需要更改它。

最后请注意,此方法不会检查wStars中的星号是否与多个AStar匹配。它只是确保为每个wStar选择最佳AStar

<强>更新

我在输出中添加了第三个列表,其中列出了对应wStars元素容差范围内的所有AStars个候选列表,但没有被选为最佳匹配。

答案 1 :(得分:0)

这里第一次回答问题(如果我犯了错误请注明)。但是大卫评论的内容似乎是正确的,因为“星星总是在列表1中(并且s总是在列表2中”)。 所以我建议比较并附加一个追踪星和星的新列表1 / newlist1。

newlist1 = list()
newlist2 = list()

#new list will keep the unique star and s
for star in list1:
    for s in list2:
        #assuming the comparison works haven't test it yet
        if np.logical_and(np.isclose(s["RA"],star["RA"], atol=0.000277778)==True , np.isclose(s["DEC"],star["DEC"],atol=0.000277778)==True):
                if star not in newlist1:
                    newlist1.append(s)
                if s not in newlist2:
                    newlist2.append(s)
                break
                #once a match is found leave the second loop

答案 2 :(得分:0)

我还没有完全解决你的问题,但我会首先尝试简化你的计算。

看起来Apstarsdata1是结构化数组,都是1d,具有相同的dtype

此列表迭代可以替换为:

Astars = list()
for s in ApStars:###this is imported but not shown
    Astars.append(s)

Astarrs = list(ApStars)

或者只是省略。如果你可以在这里迭代ApStars,你可以在列表理解中迭代它们。与wStars相同。

我将比较重写为:

set1, set2 = set(), set()   
# for star,s in [(star,s) for star in data1 for s in ApStars]:
# iteration on this list comprehension works, 
# but I think this nest iteration is clearer
for star in data1:
    for s in ApStars:
         x1 = np.isclose(s["RA"],star["RA"], atol=0.000277778)
         x2 = np.isclose(s["DEC"],star["DEC"],atol=0.000277778)
         # isclose returns boolean, don't need the ==True
         if x1 & x2:
             set1.add(star)
             set2.add(s)

set很容易添加而无需替换,但订单未定义(与dict相同)。

我想探讨在迭代之前“提取”相关字段是否会有所帮助。

Apstars['RA'], data1['RA'], Apstars['DEC'], data1['DEC']

x1 = np.isclose(Apstars['RA'][:,None], data1['RA'], atol=...)
x2 = np.isclose(Apstars['DEC']....)

x12 = x1 & x2

x12是一个2d布尔数组;当x12[i,j]“接近”Apstars[i]时,data1[j]为True。

答案 3 :(得分:0)

我感谢您提供的所有内容!我做了一些询问,并找到了一个聪明的方法来完成我正在寻找的东西。以下是我们提出的建议:

Route::get('something', ['uses' => 'Controller@page', 'page' => 'something']);

public function page(Request $request)
{
    $page = $request->route()->getAction()['page'];
    ...
}

使用列表理解,计算从Astar到所有wStars的距离,并将所有这些都落在1/3弧秒内。如果一个Astar星有多个wStars匹配,它会附加给出最短距离的Wstar索引及其Astar。