我试图迭代两个相同长度的列表,并且对于每个索引的一对条目,执行一个函数。该功能旨在对条目进行聚类 根据函数返回值的某些要求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方法来实现这个目标吗?
答案 0 :(得分:2)
这是查找图表的连接组件,一旦您从该视图中重新查看问题,就会非常容易并且有详细记录。
两个列表中的数据分散注意力。我将把数据视为zip(e_list,p_list)。将此视为图形,在这种情况下有5个节点(但在不同的数据集上可能有更多节点)。使用这些节点构建图形,如果它们通过了距离测试,则将它们与边缘连接起来。
从那里,您只需要确定无向图的连通分量,这在许多地方都有所涉及。以下是此网站上的基本深度优先搜索:Find connected components in a graph
循环遍历节点一次,执行DFS以查找所有连接的节点。查看节点后,将其标记为已访问,因此不会再次计算。要以您想要的格式获得答案,只需计算从每个未访问的起始点找到的未访问节点的数量,并将其附加到列表中。
------------------------ graph theory --------------------- -
您有要分解为相关组的数据点。这是数学和计算机科学中的一个主题,称为图论。见:https://en.wikipedia.org/wiki/Graph_theory
您有数据点。想象一下,将它们作为直角坐标绘制在eta phi空间中,然后在彼此接近的点之间绘制线条。你现在有一个&#34;图表&#34;有顶点和边缘。
要确定这些点中哪一个点之间有线条,请找到连接的组件。显然它很容易看到,但是如果你有数千个点,并且你想让计算机快速找到连接的组件,你可以使用图论。
假设我用zip(e_list,p_list)列出了所有eta phi点,列表中的每个条目都是一个顶点。如果您将图表存储在&#34;邻接列表&#34;格式,然后每个顶点也将有一个传出边的列表,将它连接到另一个顶点。
查找连接的组件实际上就像查看每个顶点一样简单,通过它添加一个复选标记,然后跟随每一行到下一个顶点并在其中放置一个复选标记,直到找不到任何其他连接的顶点。现在找到没有复选标记的下一个顶点,并重复下一个连接的组件。
作为一名程序员,您知道当您可以使用已发布和已审核的代码来处理任务时,为常见问题编写自己的数据结构是一个坏主意。 Google&#34; python图形模块&#34;。评论中提到的一个例子是&#34; pip install networkx&#34;。如果你在networkx中构建图形,你可以将连接的组件作为列表列表,然后取每个列表的len来获得你想要的格式:[len(_)for _ in nx.connected_components(G)]
---------------- code -------------------
但是如果你不理解数学,那么你可能不了解图形模块,也不理解基础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()