使用numpy或tabular通过比较两个列表的所有项进行过滤
我有两个元组列表,每个列表里的元组都是独一无二的。列表的格式如下:
[('col1', 'col2', 'col3', 'col4'), ...]
我正在使用嵌套循环来找出两个列表中在特定列(col2和col3)上有相同值的成员。
temp1 = set([])
temp2 = set([])
for item1 in list1:
for item2 in list2:
if item1['col2'] == item2['col2'] and \
item1['col3'] == item2['col3']:
temp1.add(item1)
temp2.add(item2)
这样做是有效的,但当列表中有成千上万的项目时,完成这个过程需要很多分钟。
使用tabular,我可以根据列表2中的一个项目的col2和col3来过滤列表1,如下所示:
list1 = tb.tabular(records=[...], names=['col1','col2','col3','col4'])
...
for (col1, col2, col3, col4) in list2:
list1[(list1['col2'] == col2) & (list1['col3'] == col3)]
显然,这种方法是“错误的”,而且比第一种方法慢得多。
我该如何有效地使用numpy或tabular来检查一个元组列表中的项目与另一个列表中的所有项目?
谢谢!
3 个回答
0
我会创建一个元组的子类,这个子类有特别的 __eq__
和 __hash__
方法:
>>> class SpecialTuple(tuple):
... def __eq__(self, t):
... return self[1] == t[1] and self[2] == t[2]
... def __hash__(self):
... return hash((self[1], self[2]))
...
这个方法会比较 col1
和 col2
,只有当这两列完全相同的时候,元组才会被认为是相等的。
然后,过滤操作就可以通过对这些特殊的元组使用 set
的交集来完成:
>>> list1 = [ (0, 1, 2, 0), (0, 3, 4, 0), (1, 2, 3, 12) ]
>>> list2 = [ (0, 1, 1, 0), (0, 3, 9, 9), (42, 2, 3, 12) ]
>>> set(map(SpecialTuple, list1)) & set(map(SpecialTuple, list2))
set([(42, 2, 3, 12)])
我不知道这个方法的速度如何。告诉我吧。:)
1
“我该如何有效地用numpy或tabular检查一个元组列表中的项目与另一个列表中的所有项目?”
嗯,我对tabular没有经验,对numpy也只是了解一点,所以我不能给你一个现成的解决方案。不过,我可以给你一些方向。如果第一个列表的长度是X,第二个列表的长度是Y,那么你需要进行X * Y次检查……而实际上你只需要进行X + Y次检查。
你可以尝试做以下事情(我会假装这些是普通的Python元组列表,而不是tabular记录——我相信你可以做出必要的调整):
common = {}
for item in list1:
key = (item[1], item[2])
if key in common:
common[key].append(item)
else:
common[key] = [item]
first_group = []
second_group = []
for item in list2:
key = (item[1], item[2])
if key in common:
first_group.extend(common[key])
second_group.append(item)
temp1 = set(first_group)
temp2 = set(second_group)
1
试试这个:
temp1 = set([])
temp2 = set([])
dict1 = dict()
dict2 = dict()
for key, value in zip([tuple(l[1:3]) for l in list1], list1):
dict1.setdefault(key, list()).append(value)
for key, value in zip([tuple(l[1:3]) for l in list2], list2):
dict2.setdefault(key, list()).append(value)
for key in dict1:
if key in dict2:
temp1.update(dict1[key])
temp2.update(dict2[key])
虽然有点不太干净,但应该能用。