【问题标题】:Faster way to do a correspondence replace operation in python?在python中进行对应替换操作的更快方法?
【发布时间】:2013-05-05 06:11:32
【问题描述】:

我不确定我是否使用了正确的术语——我可能称之为合并操作?简单匹配?

我有两本字典。其中之一包含标签 ID 列表。另一种是标签 ID 和标签 ID 名称之间的对应关系。我想匹配 ID 并在第一个字典中包含标签名称。

所以,第一个字典看起来像这样:

>>> myjson
[
{"tags" : ["1","3"],"otherdata" : "blah"},
{"tags" : ["2","4"],"otherdata" : "blah blah"}
]

第二个字典如下所示:

>>> tagnames
[
{"id": "1", "name":"bassoon"},
{"id": "2", "name":"banjo"},
{"id": "3", "name":"paw paw"},
{"id": "4", "name":"foxes"}
]

要将 myjson 中的标签 ID 替换为标签 ID 名称,我目前正在这样做:

data = []
for j in myjson:
    d = j
    d['tagnames'] = [i['name'] for i in tagnames for y in d['tags'] if y==i['id']]
    data.append(d)

我想要的输出是这样的:

>>> data
[
{"tags" : ["1","3"],"otherdata" : "blah", "tagname" : ["bassoon","paw paw"]},
{"tags" : ["2","4"],"otherdata" : "blah blah", "tagname": ["banjo","foxes"]}
]

我得到了正确的输出,但它似乎真的很慢。我知道它每次都在对 myjson 中的每个元素进行完整迭代 x 对标记名中的每个元素进行完整迭代(那是 mxn 吗?nxn?),这会很慢,但也许有更智能的语法或技巧来加速它?只遍历数组一次而不是 n 次?

哦,如果有人可以建议一种使用光滑映射或函数方法而不是外部 forloop 来完成此任务的方法,那将是很酷的。

【问题讨论】:

  • d['tagnames'] 已经更改了myjson 结构就地。也无需创建新列表datad = j 只是分配一个引用,字典是复制的。
  • 哇,真的吗?哎呀。好的,好吧,这应该开始加速,但我担心会弄乱我的旧数据。

标签: python performance algorithm dictionary merge


【解决方案1】:

您想将标记名列表转换为字典:

tagnames_map = {t['id']: t['name'] for t in tagnames}

现在您可以更快地找到匹配的标记名;您的代码已经进行了就地更改,因此我将其简化为:

for d in myjson:
    d['tagnames'] = [tagnames_map[t] for t in tagnames_map.viewkeys() & d['tags']]

dict.viewkeys() method 返回一个dictionary view object,其作用类似于一个集合。我们将该集合与您的标签列表相交,从而产生一系列标签,这些标签都列在tagnames_map 中。通过这样做,我们不必担心地图中缺少任何标签。

如果您使用的是 Python 3,那么您只需直接使用tagnames_map.keys();在 Python 3 中,.keys().values()items() 方法已更改为始终返回字典视图对象。

如果您想制作副本,请使用d.copy()

data = []
for d in myjson:
    d = d.copy()
    d['tagnames'] = [tagnames_map[t] for t in tagnames_map.viewkeys() & d['tags']]
    data.append(d)

dict.copy() 创建一个浅拷贝;不复制可变值,新的字典只会引用相同的值。因为你没有在这里改变值,这很好。

针对您的示例输入运行此命令:

>>> pprint(data)
[{'otherdata': 'blah', 'tagnames': ['bassoon', 'paw paw'], 'tags': ['1', '3']},
 {'otherdata': 'blah blah',
  'tagnames': ['banjo', 'foxes'],
  'tags': ['2', '4']}]

【讨论】:

  • 这非常有用且非常清晰。我开始运行它,对于我的实际样本,它仍然很慢——但我肯定比我的原始样本快得多,它甚至没有在我的真实样本上完成。这里的缓慢只是野兽的本性?
  • @Mittenchops:如果您的输入数据集是 huge 那么是的,慢度是您输入的数据量的函数。但是 tagnames 生成是本地的快速 (O(N)) 而不是 O(MN),N 是每个条目中 tags 列表的长度,Mtagnames 列表的长度。
  • @Mittenchops:如果您可以避免复制所有条目,那就更好了。
  • 是的,一旦你指出这是多余的,我就开始回去修改......所有......我的脚本。 =) 谢谢。我认为只是数据集非常庞大。它在 myjson 中有 50 万,在标签中有 40k,到目前为止已经运行了大约 20 分钟。
  • @Mittenchops:您现在正在创建 500.000 个字典副本。对于每个副本,您将进行 N 次字典查找以将标签映射到标签名称,其中 N 是 tags 列表的长度。这仍然比为 500.000 个条目中的每一个循环遍历 N * 40.000 个标记名称要好得多。你基本上把这个过程加快了 4 万倍。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-26
  • 2019-01-29
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
相关资源
最近更新 更多