【问题标题】:Getting direct edge connections in a network graph在网络图中获取直接边连接
【发布时间】:2018-08-10 20:41:43
【问题描述】:

我有下面的网络图:

import networkx as nx
net = nx.Graph()
node_list = ["Gur","Qing","Samantha","Jorge","Lakshmi","Jack","John","Jill"]
edge_list = [("Gur","Qing",{"relation":"work"}),
         ("Gur","Jorge", {"relation":"family"}),
        ("Samantha","Qing", {"relation":"family"}),
        ("Jack","Qing", {"relation":"work"}),
        ("Jorge","Lakshmi", {"relation":"work"}),
        ("Jorge","Samantha",{"relation":"family"}),
        ("Samantha","John", {"relation":"family"}),
        ("Lakshmi","Jack", {"relation":"family"}),
        ("Jack","Jill", {"relation":"charity"}),
        ("Jill","John",{"relation":"family"})]

net.add_nodes_from(node_list)
net.add_edges_from(edge_list)

我想构建一个函数,给定网络、节点名称和关系类型,返回给定人员直接连接的人员列表。

这是我目前得到的功能:

def get_relations(graph,node,relationship):
        if relationship == 'charity':
            charity = [ (v) for (u,v,d) in net.edges( data = True) if d["relation"]=="charity"]
            return list(set(charity))
        else:

            if relationship == 'work':
                work = [ (v) for (u,v,d) in net.edges( data = True) if d["relation"]=="work"]
                return list(set(work))
            else:

                if relationship == 'family':
                    family = [(v) for (u,v,d) in net.edges( data = True) if d["relation"]=="family"]
                    return list(set(family))
                else:
                    return None

这样调用函数:

get_connections(net, 'John', 'family')

产生这个输出:

['Gur', 'Samantha', 'John', 'Lakshmi']

但这不是我需要的,我希望它只返回那些直接连接到 John 的人,或者无论节点是什么,使用直接路径,而不是间接路径。

以相同的方式调用函数应该会产生正确的输出:

['John', 'Jill', 'Samantha', 'Qing', 'Jorge', 'Gur']

代码尝试:

def get_relations(graph,node,relationship):
    if relationship not in {'charity', 'work', 'family'}: 
        return None
    relation_net = nx.Graph([(u,v,d) for (u, v, d) in net.edges( data = True)
                             if d["relation"] == relationship])

    relation_subnet = nx.Graph([(node,v,d) for (u, v, d) in relation_net.edges( data = True)
                             if d["relation"] == relationship])

    return list(set(relation_subnet.nodes))

但是,这仍然返回错误的结果。

【问题讨论】:

  • 不是问题的原因,但您听说过elif 吗?如果没有,你应该检查一下。
  • 请发帖minimal reproducible example。您的问题目前带有许多警告信号,表明显示的代码 sn-ps 并非全部来自您的代码的同一版本;看起来你可能试图从记忆中重新输入内容。
  • @xdze2 我需要获取所有与给定关系类型有连接的邻居,但只有那些与该关系类型连接的邻居,中间没有任何其他不同的关系类型。因此,例如,如果我有 John 和 Jill 与家庭关系直接相关,而 Jill 与任何其他有家庭关系的人有联系,我需要得到那个人的名字。但是,例如,如果 Jill 与一个人有工作关系,而那个人与另一个人有家庭关系,那我就不需要了。
  • @Miguel2488:是的。我将您的代码粘贴到一个文本文件中,连续运行五次,得到四个不同的集合作为输出。
  • @Miguel2488,我现在明白了。我认为混淆是因为“直接连接”对我来说意味着第一个邻居,即只有一个边缘可以遍历,这与边缘类型无关。图表很有趣也很让人头疼,尽情享受吧!也许这个很棒的课程会有所帮助youtube.com/watch?v=s-CYnVz-uh4

标签: python python-3.x graph networkx network-analysis


【解决方案1】:

首先,重构你的函数定义,以便更容易理解:

def get_relations(graph,node,relationship):
    if relationship not in {'charity', 'work', 'family'}:
        return None
    connections = [v for (u, v, d) in G.edges(data = True) if d["relation"] == relationship]
    return list(set(connections))

然后使用较小的网络对其进行测试(也使事情更容易理解):

node_list = ["Gur","Qing","Samantha","Jorge","Lakshmi","Jack","John","Jill"]
edge_list = [
    ("Jack","Qing", {"relation":"work"}),
    ("Gur","Jorge", {"relation":"family"}),
    ("Samantha","Qing", {"relation":"family"}),
    ("Jorge","Samantha",{"relation":"family"}),
    ("Lakshmi","Jack", {"relation":"family"}),
    ("Jill","John",{"relation":"family"})
]
net = nx.Graph()
net.add_nodes_from(node_list)
net.add_edges_from(edge_list)

我们可以立即看到您的函数没有执行您要查找的操作:

get_relations(G, 'John', 'family') 的调用会产生以下输出:

['Jack', 'Jorge', 'Jill', 'Samantha']

您没有在代码中的任何位置使用所需节点的逻辑。

你真正应该做的是:

  1. 找到net 的子图,该子图由具有正确'relation' 属性的边以及这些边连接到的所有节点组成(称为relation_net
  2. 寻找包含所需节点的relation_net(可能是整个事物)的全连接组件子图(称为relation_sub_net)。
  3. 输出relation_sub_net的节点列表。这是您想要的输出。

如果您想尝试一下,我相信如果您遇到困难,任何人(包括我自己)都会很乐意为您提供帮助。

【讨论】:

  • 感谢您的回答,我是这个网络的新手,所以我对此有点困惑。我将尝试您的示例,如果我有更多疑问,我会回复您。非常感谢:)
  • 这是我到目前为止所得到的:def get_relations(graph,node,relationship): if relationship not in {'charity', 'work', 'family'}: return None relation_net = nx.Graph([(u,v,d) for (u, v, d) in net.edges( data = True) if d["relation"] == relationship]) relation_subnet = nx.Graph([(node,v,d) for (u, v, d) in relation_net.edges( data = True) if d["relation"] == relationship]) return list(set(relation_subnet.nodes)) 我不确定这是否是你建议我做的,但这是我最接近所需输出的结果跨度>
  • 现在像这样get_relations(net, 'John', 'family') 调用函数会产生这样的结果:['Jill', 'Jack', 'Jorge', 'Samantha', 'John'] 我做错了,因为'Jack' 不应该在那里,相反,'Gur' 应该在'Jack's place .我觉得我非常接近我想要的结果,但我不知道我在哪里迷路了。我会很感激这里的一些启发。再次感谢:)
【解决方案2】:

您根据PMende 的指导进行的编码尝试非常接近。问题出在您的第二次提取中,当您尝试仅获取连接到 John 的那些边时:

relation_subnet = nx.Graph([(node,v,d) for (u, v, d) in relation_net.edges( data = True)
                             if d["relation"] == relationship])

(u,v,d)的选择(node,v,d)错误,条件错误。在第一个子句中

(node,v,d) for (u, v, d) in ...

对于relation_net 中的每个节点,您获取 src、dst 和 arc 值...但随后丢弃 src 并强制 John 进入该位置。这仅在John 恰好是源时才有效;否则,您刚刚创建了一个新的子网边缘,例如

("John","Jack", {"relation":"family"})  # Lakshmi removed

相反,您需要将包含 John 的边缘保留在 either 位置。

其次,您的“关系”过滤器第二次不执行任何操作;你已经第一次包括了每一个家庭关系。相反,您需要收集所有与 John 处于家庭边缘的人。

relation_subnet = nx.Graph([(u,v,d) for (u, v, d) in relation_net.edges( data = True)
                             if u == node or v == node])

这正确产生

['Samantha', 'Jill', 'John']

Samantha 和 Jill 是 John 唯一的直系亲属。如果您想要此列表上的串联闭包,则需要迭代该过程,将 family 的每个新成员添加到 Jill 和/或 Samantha,重复此操作直到没有添加新节点。

你能从那里拿走吗?

【讨论】:

  • 嘿,我真的很感谢你的帮助,我今天试试,如果我知道了,我会告诉你的。你的解释很好,帮助我看到了我的错误:)
  • 您好 :) 非常感谢您的帮助。我终于成功了,我得到了正确的解决方案,我现在把它贴在这里,因为也许它最终可以帮助某人:D
  • 当你得到解决方案时,请记得给有用的东西投票并接受你最喜欢的答案(即使你必须自己写),这样 Stack Overflow 才能正确存档问题。跨度>
  • 好了,哥们,我把你的答案标记为正确的,这是当之无愧的,因为你的答案让我走上了正确的道路;)
【解决方案3】:

再次向大家致意 :) 我要感谢你们所有人的时间和帮助,你们确实帮助我提高了我对所面临问题的认识和理解,现在我对网络有了更多的了解。我终于得到了我正在寻找的解决方案。事情是这样的:

def get_relations(graph,node,relationship):
    if relationship not in {'charity', 'work', 'family'}:
        return None

    relation_net = nx.Graph([(u,v,d) for (u,v,d) in net.edges(nbunch = net.nodes(), data = True) if u == node or v == node])
    relation_subnet = nx.Graph([(u,v,d) for (u,v,d) in net.edges(nbunch = relation_net.nodes(), data = True) if d['relation']== relationship])
    relation1 = nx.Graph([(u,v,d) for (u,v,d) in net.edges(nbunch = relation_subnet.nodes(), data = True) if d['relation'] == relationship])
    relation2 = nx.Graph([(u,v,d) for (u,v,d) in net.edges(nbunch = relation1.nodes(), data = True) if d['relation'] == relationship])


    return list(set(relation2))

我发布这个是因为也许我认为它可以在某个时候帮助某人。没有你们的帮助,我是做不到的。再次感谢:D

【讨论】:

  • 对不起,我没有早点回复!很高兴您能够解决它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-01
  • 2015-04-09
  • 2017-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多