使用numpy或tabular通过比较两个列表的所有项进行过滤

0 投票
3 回答
518 浏览
提问于 2025-04-16 18:25

我有两个元组列表,每个列表里的元组都是独一无二的。列表的格式如下:

[('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]))
... 

这个方法会比较 col1col2,只有当这两列完全相同的时候,元组才会被认为是相等的。

然后,过滤操作就可以通过对这些特殊的元组使用 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])

虽然有点不太干净,但应该能用。

撰写回答