【问题标题】:Iterate over two lists, execute function and return values遍历两个列表,执行函数并返回值
【发布时间】:2016-10-04 05:45:52
【问题描述】:

我正在尝试遍历两个相同长度的列表,并且对于每个索引的一对条目,执行一个函数。该功能旨在对条目进行聚类 根据对函数返回值的一些要求X。

问题中的列表是:

e_list = [-0.619489,-0.465505, 0.124281, -0.498212, -0.51]      
p_list = [-1.7836,-1.14238, 1.73884, 1.94904, 1.84]  

并且该函数需要 4 个条目,l1 和 l2 的每个组合。 函数定义为

def deltaR(e1, p1, e2, p2):
    de = e1 - e2                                                                                                                                                                     
    dp = p1 - p2                                                                                                                                                           
    return de*de + dp*dp

到目前为止,我已经能够同时遍历列表:

for index, (eta, phi) in enumerate(zip(e_list, p_list)):                                                                                                                    
    for index2, (eta2, phi2) in enumerate(zip(e_list, p_list)):                                                                                                             
        if index == index2: continue             # to avoid same indices                                                                                                                                   
        if deltaR(eta, phi, eta2, phi2) < X:                                                                                                                                      
             print (index, index2) , deltaR(eta, phi, eta2, phi2)

这个循环对每个组合执行函数,除了那些相同的组合,即索引 0,0 或 1,1 等

代码的输出返回:

(0, 1) 0.659449892453
(1, 0) 0.659449892453
(2, 3) 0.657024790285
(2, 4) 0.642297230697
(3, 2) 0.657024790285
(3, 4) 0.109675332432
(4, 2) 0.642297230697
(4, 3) 0.109675332432

我正在尝试返回符合上述条件的所有索引的数量。换句话说,将输出重新排列为:

output = [No. matched entries]

output = [2, 3]

2 来自索引 0 和 1 匹配的事实

3 来自于索引 2、3 和 4 都匹配的事实

我想到的一种可能的方法是将所有使用的索引附加到一个列表中,以便我返回

output_list = [0, 1, 1, 0, 2, 3, 4, 3, 2, 4, 4, 2, 3]

然后,我使用 defaultdict 来计算出现次数:

for index in output_list:
    hits[index] += 1

从 dict 我可以操纵它返回 [2,3] 但有没有更 Pythonic 的方式来实现这一点?

【问题讨论】:

  • this 示例中,条件对索引列表进行了分区,但我不明白为什么总是这样。基于距离的相似性度量通常不具有传递性(如果 x 接近 y 并且 y 接近 z,则不必是 x 接近 z 的情况)。但是,如果它不是可传递的,那么实际上并不清楚您的输出应该是什么,因为您似乎想要分区中单元格的大小。
  • 在这种情况下,deltaR(0,1)deltaR(1,0) 产生相同的值,因此应该考虑一次。因此,我不是在寻找反向对,而是满足上述要求的索引数量,即 2

标签: python


【解决方案1】:

这是查找图的连接组件,一旦您从该视图重新审视问题,这非常容易且有据可查。

两个列表中的数据会分散注意力。我将认为数据是 zip(e_list, p_list)。将其视为一个图,在这种情况下它有 5 个节点(但在不同的数据集上可能有更多节点)。使用这些节点构建图形,如果它们通过了距离测试,则将它们与边连接。

从那里,您只需要确定无向图的连通分量,该图在很多地方都有介绍。这是该站点上的基本深度优先搜索:Find connected components in a graph

您遍历节点一次,执行 DFS 以查找所有连接的节点。一旦您查看了一个节点,请将其标记为已访问,这样它就不会再次被计算在内。要以您想要的格式获得答案,只需计算从每个未访问的起点找到的未访问节点的数量,并将其附加到列表中。

------------ 图论 --------- -

您有想要分解为相关组的数据点。这是数学和计算机科学中的一个主题,称为图论。见:https://en.wikipedia.org/wiki/Graph_theory

您有数据点。想象在 eta phi 空间中将它们绘制为直角坐标,然后在彼此靠近的点之间画线。您现在有了一个带有顶点和边的“图”。

要确定这些点中的哪些点之间有线,就是寻找连通分量。显然这很容易看出,但如果您有数千个点,并且您希望计算机快速找到连接的组件,则可以使用图论。

假设我用 zip(e_list, p_list) 列出所有 eta phi 点,并且列表中的每个条目都是一个顶点。如果您以“邻接表”格式存储图形,那么每个顶点还将有一个将其连接到另一个顶点的出边列表。

查找连接的组件实际上就像查看每个顶点一样简单,在它旁边打勾,然后沿着每一行到下一个顶点并在那里打勾,直到找不到其他连接的东西。现在找到下一个没有复选标记的顶点,并重复下一个连接的组件。

作为程序员,您知道为常见问题编写自己的数据结构是一个坏主意,因为您可以使用已发布和审查过的代码来处理任务。谷歌“python图形模块”。 cmets 中提到的一个示例是“pip install networkx”。如果您在networkx中构建图形,您可以将连接的组件作为列表的列表,然后将每个组件的len获取您想要的格式:[len(_) for _ in nx.connected_components(G)]

----------------代码-------------------

但是,如果您不了解数学,那么您可能不了解图形模块,也不了解基本的 Python 实现,但如果您只看其中一些链接,就很容易了。基本上是点和线,但在应用这些概念时非常有用,正如您所看到的那样,您的问题只不过是一个非常简单的图论问题。

我的图表是一个基本列表,因此顶点实际上没有名称。它们由它们的列表索引标识。

e_list = [-0.619489,-0.465505, 0.124281, -0.498212, -0.51]      
p_list = [-1.7836,-1.14238, 1.73884, 1.94904, 1.84]  

def deltaR(e1, p1, e2, p2):
    de = e1 - e2                                                                                                                                                                     
    dp = p1 - p2                                                                                                                                                           
    return de*de + dp*dp

X = 1 # you never actually said, but this works

def these_two_particles_are_going_the_same_direction(p1, p2):
    return deltaR(p1.eta, p1.phi, p2.eta, p2.phi) < X

class Vertex(object):
    def __init__(self, eta, phi):
        self.eta = eta
        self.phi = phi
        self.connected = []
        self.visited = False

class Graph(object):
    def __init__(self, e_list, p_list):
        self.vertices = []
        for eta, phi in zip(e_list, p_list):
            self.add_node(eta, phi)

    def add_node(self, eta, phi):
        # add this data point at the next available index
        n = len(self.vertices)
        a = Vertex(eta, phi)

        for i, b in enumerate(self.vertices):
            if these_two_particles_are_going_the_same_direction(a,b):
                b.connected.append(n)
                a.connected.append(i)

        self.vertices.append(a)

    def reset_visited(self):
        for v in self.nodes:
            v.visited = False

    def DFS(self, n):
        #perform depth first search from node n, return count of connected vertices
        count = 0
        v = self.vertices[n]
        if not v.visited:
            v.visited = True
            count += 1
            for i in v.connected:
                count += self.DFS(i)
        return count

    def connected_components(self):
        self.reset_visited()
        components = []
        for i, v in enumerate(self.vertices):
            if not v.visited:
                components.append(self.DFS(i))                
        return components

g = Graph(e_list, p_list)
print g.connected_components()

【讨论】:

  • 或使用networkx,不要重新发明轮子。
  • 我将为这个问题添加 networkx 调用,尽管构建图虽然简单,但仍然是最难的部分,无论您使用的是 networkx 图还是简单的列表/字典实现。跨度>
  • 感谢您的建议,我已听从您的建议。但是,我仍在寻求不依赖于使用非内置模块的解释。
  • 图论不是你下载的模块,它是数学。但是我在没有导入的基本 python 2.7 中添加了您的问题的实现。不过,如果您没有上算法课,下载一个模块可能是明智之举。
  • 你想要更多解释,我添加了。如果那堵文字墙没有帮助,也许你可以评论我没有解释的内容,而不是让我在一个广泛的话题上胡言乱语。
猜你喜欢
  • 2012-05-30
  • 2020-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-12
相关资源
最近更新 更多