【问题标题】:python transitivity between dictionaries字典之间的python传递性
【发布时间】:2014-08-27 18:06:04
【问题描述】:

我在python中有一个类似下面的列表(真正的列表很大,我不能仅仅通过查看它来做到这一点):

original1=[['email', 'tel', 'fecha', 'descripcion', 'categ'],
          ['a@gmail.com', '1', '2014-08-06 00:00:06', 'MySpace a', 'animales'],
          ['b@gmail.com', '1', '2014-08-01 00:00:06', 'My Space a', 'ropa'],
          ['a@gmail.com', '2', '2014-08-06 00:00:06', 'My Space b', 'electronica'],
          ['b@gmail.com', '3', '2014-08-10 00:00:06', 'Myace c', 'animales'],
          ['c@gmail.com', '4', '2014-08-10 00:00:06', 'Myace c', 'animales']]

我将其拆分为数据和名称以处理数据:

datos=original1[-(len(original1)-1):len(original1)]

考虑到电子邮件和电话,我需要制作一个将所有重复项放在一起的字典,但我需要应用传递性:因为如果我们考虑电子邮件,第 0 行 = 第 2 行,但如果我们考虑电话,则第 1 行,而第 1 行1= 第 3 行 如果我们再次考虑电子邮件,我需要知道在这种情况下所有候选人都是 0、1、2 和 3,而 4 是单独的。

我创建了以下代码:

from collections import defaultdict
email_to_indices = defaultdict(list) 
phone_to_indices = defaultdict(list)

for idx, row in enumerate(datos): 
    email = row[0].lower() 
    phone = row[1]
    email_to_indices[email].append(idx) 
    phone_to_indices[phone].append(idx)

所以现在我需要应用传递性规则,将 0 到 3 和单独的 4 聚集在一起。

如果你打印

print 'email', email_to_indices
print 'phone', phone_to_indices

你得到:

email defaultdict(, {'a@gmail.com': [0, 2],'b@gmail.com': [1, 3], 'c@gmail.com': [4]})

phone defaultdict(, {'1': [0, 1], '3': [3], '2': [2], '4': [4]})

不知道如何获得考虑传递属性的人的联合。 我需要得到类似的东西:

first_group: [0, 1, 2, 3]
second_group:[4]

谢谢!

【问题讨论】:

  • 输出dict的key应该是什么?它应该为每个唯一的电子邮件和电话都有一个密钥,每个都引用相同的数据列表,还是应该有某种由所有重叠的电子邮件和数字构成的合并密钥?您的预期输出是什么?
  • 在我看来,自然的做法是像[ [line0, line1, line2, line3], [line4] ]这样的数据结构
  • 亚当,问题是这是一个例子,真正的桌子很大。这就是我写代码的原因。
  • GabyP 我只是提出一个数据结构来保存它,以回应@SilasRay 的评论,上面:)

标签: python dictionary transitivity


【解决方案1】:

这里有一个图表,或者更准确地说是Bipartite graph。节点有两种类型:电子邮件和电话。如果该电子邮件和电话存在记录,则连接两个节点。或者我们甚至可以说记录本身就是连接两个节点的边。

任务是找到这张图的Connected components。通过以下链接,您可以找到可以在线性时间内完成的算法。

当然,也可以发明一些快速而肮脏的解决方案,如果您的数据集足够小,甚至可能被认为是合适的。

您可以在这里找到一些 Python 实现:Python connected components

更新:以下是如何构建图表的示例:

graph = {};
EMAIL = "email";
PHONE = "phone";

for rec in datos:
    graph.setdefault((EMAIL, rec[0]), set()).add((PHONE, rec[1]));
    graph.setdefault((PHONE, rec[1]), set()).add((EMAIL, rec[0]));

print "\n".join("%s: %s" % (str(node), str(linkedNodes)) for (node, linkedNodes) in graph.iteritems());

所以每个节点都有一个类型(EMAILPHONE,它们实际上可以只是整数,例如 0 和 1,我将它们设为字符串只是为了方便打印)和一个值。 Graph 是一个字典,其中节点作为键,连接的节点集作为值。

【讨论】:

  • 嗨 Anton,这是个好主意,但是 python 中有一个模块可以这样做吗?那会怎么样?
  • @GabyP 我认为没有,但quick search 提供了很多信息,包括关于 SO 的相关问题。
【解决方案2】:

这是另一种方法:

在构建email_to_indices 字典时,可以将该行的电话号码存储为值,然后让phone_to_indices 具有该行的索引。这样我们就创建了一个email_to_indicesphone_to_indices 来索引行映射。

通过修改和基本的设置操作,我可以得到你想要的:

from collections import defaultdict

email_to_indices = defaultdict(list)
phone_to_indices = defaultdict(list)
combined = defaultdict(set)

original=[['email', 'tel', 'fecha', 'descripcion', 'categ'],
          ['a@gmail.com', '1', '2014-08-06 00:00:06', 'MySpace a', 'animales'],
          ['b@gmail.com', '1', '2014-08-01 00:00:06', 'My Space a', 'ropa'],
          ['a@gmail.com', '2', '2014-08-06 00:00:06', 'My Space b', 'electronica'],
          ['b@gmail.com', '3', '2014-08-10 00:00:06', 'Myace c', 'animales'],
          ['c@gmail.com', '4', '2014-08-10 00:00:06', 'Myace c', 'animales']]


for idx, row in enumerate(original[1:], start=1):
    email = row[0].lower()
    phone = row[1]
    email_to_indices[email].append(phone) # Here is what I changed
    phone_to_indices[phone].append(idx)

random_key = 0
for idx, row in enumerate(original[1:], start=1):
    grouped_rows = []
    if row[0].lower() in email_to_indices:
        for phone_no in email_to_indices[row[0].lower()]:
            grouped_rows.extend(phone_to_indices[phone_no])

    if len(combined[random_key]) > 0 and len(set(grouped_rows).intersection(combined[random_key])) > 0:
        combined[random_key].update(set(grouped_rows))
    elif len(combined[random_key]) > 0:
        random_key += 1
        combined[random_key].update(set(grouped_rows))
    else:
        combined[random_key].update(set(grouped_rows))

print combined

这给出了:

defaultdict(<type 'set'>, {0: set([1, 2, 3, 4]), 1: set([5])})

【讨论】:

    猜你喜欢
    • 2012-04-20
    • 2020-12-07
    • 2019-02-11
    • 1970-01-01
    • 2013-12-14
    • 1970-01-01
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    相关资源
    最近更新 更多