Python 使用属性实现“类别”系统

Python 使用属性实现“类别”系统,python,igraph,Python,Igraph,我有大约1000个“类别”覆盖了我的边缘。我使用属性指定这些类别: g、 es[0][$cat1]=真 一条边可以属于多个类别 问题是,这会导致我的所有其他边(即使它们与类别1无关)获得属性$cat1=None 因此,基本上,即使我的边缘是单个类别的一部分,它也会有999个其他属性,例如$catN=None 我需要能够获取每个类别,包括它的所有成员节点和边到一个单独的子图。现在我只需遍历所有边,查看其中$catN=True,然后将这些边和节点放入一个新的图形中 这个方法整体上看是可伸缩的吗?这看

我有大约1000个“类别”覆盖了我的边缘。我使用属性指定这些类别:

g、 es[0][$cat1]=真

一条边可以属于多个类别

问题是,这会导致我的所有其他边(即使它们与类别1无关)获得属性$cat1=None

因此,基本上,即使我的边缘是单个类别的一部分,它也会有999个其他属性,例如$catN=None

我需要能够获取每个类别,包括它的所有成员节点和边到一个单独的子图。现在我只需遍历所有边,查看其中$catN=True,然后将这些边和节点放入一个新的图形中

这个方法整体上看是可伸缩的吗?这看起来有点混乱,因为可能有一百万个节点和一万个类别。这意味着每条边将存储2-3个$catN=True,但数千个冗余$catN=None。 如果没有,您对更好地实施这一“分类”系统有何建议? 如果这是最好的方法,那么对于检索特定类别有什么建议吗?穿越所有的边缘似乎是一种浪费。我想我可以维护一个单独的数据结构,边缘编号对应于每个类别。但要维持下去会很痛苦。
是否需要将每条边的类别存储为边属性?如果图形不会发生变化,即不会从图形中删除边,则只需使用外部Python dict将类别ID映射到边ID,然后通过单个字典查找获取每个类别的成员。如果还需要快速判断边属于哪个类别,则还需要反向映射,因此最好创建一个单独的双向映射类,并分别维护映射的两侧:

from collections import defaultdict

class CategoryMapping(object):
    def __init__(self):
        self.category_to_members = defaultdict(set)
        self.member_to_categories = defaultdict(set)

    def add(self, category, member):
        self.category_to_members[category].add(member)
        self.member_to_categories[member].add(category)

    def remove(self, category, member):
        self.category_to_members[category].discard(member)
        self.member_to_categories[member].discard(category)

    def categories_of(self, member):
        return self.member_to_categories[member]

    def members_of(self, category):
        return self.category_to_member[category]

编辑:如果有时从图形中删除边,则可以在其ID edge属性中为每条边指定唯一ID,然后在CategoryMapping中使用这些ID。唯一的问题是,按属性查找边是一个On操作,其中n是边的数目。为了缓解这种情况,还可以创建一个边ID到索引映射类。这个类可以有一个edges\u removed方法,每当您从图形中删除边时,必须使用删除边的旧ID调用该方法,并且它应该相应地更新内部ID以索引映射。遗憾的是,igraph没有一个特殊的类似于id的边属性,尽管它以这种方式处理顶点对象的name属性,因此可以通过名称实现顶点的O1查找。你可以利用这样一个事实,即当有k条被删除的边的索引小于原始图中的i时,删除后的边i的索引将变为i-k。

你能将你的帖子限制为一个问题吗;试着避免像这种方法整体上看是可伸缩的吗?你是说我应该为这个问题创建3个独立的问题?它们都与我描述的问题完全相关。我同意这个开放式问题,但我不认为这里有更多经验的人,他们处理过1000个属性的百万节点图,可以根据他们的经验给我一些启示是错误的。我不知道IGRAPHE,所以也许这不是一个选项,但你能将一组类别附加到边上吗?类似于g.es[0]['categories']=set['$cat1']和不属于任何类别的边的空集。你能详细说明一下吗?我理解将所有类别存储在一个集合中。但这难道不能解决任何问题吗?因为我不需要通过g.es[0]字典键,而需要通过g.es[0]['categories']集来找出g.es[0]属于哪个类别。。。另外,为什么我需要一个不属于任何类别的边的空集?如果你不在不属于任何类别的边上存储空集,你需要额外的代码来检查。与字典中每个边缘的n个总类别的n个键相比,其优势在于集合只包含egde的实际类别。检查一个类别是否在该集合中,或者即使一组类别是子集,也是有效的。我不认为如果你不能建立一个映射类别,你可以避免通过所有的边来提取一个给定类别的子图→像@Tamás的回答中建议的边缘。这是一个好主意,但正如你所说,当边缘被移除时,它不起作用。特别是因为IGRAPHE在删除边缘后会对边缘ID重新编号……我用一种可能但并非真正直接的边缘删除解决方案更新了我的答案。