我怎样才能加快这个迭代?

How can I speed up this iteration?

我有一个包含 2 列 'left_index''right_index' 的超过一千万行的数据框。 'left_index' 是值的索引,'right_index' 包含可能匹配的行的索引。 问题是这包含重复的匹配项(例如:0,1 和 1,0)。 我想过滤这个数据框,只保留每个匹配项的一个组合。

我在这里使用列表作为示例。

在:[(0,1), (1,0), (3,567)]

输出:[(0,1), (3, 567)]

下面的代码生成了我想要的结果,但是速度很慢。有没有更快的方法来解决这个问题?

lst2 = []
for i in lst1:
  if(i in lst2):
    lst1.remove(i)
  else:
    lst2.append((i[1],i[0]))

我相信 Pandas 可以避免使用循环。

import pandas as pd

df = pd.DataFrame([
    [(0, 0), (0, 0), 123],
    [(0, 0), (0, 1), 234],
    [(1, 0), (0, 1), 345],
    [(1, 1), (0, 1), 456],
], columns=['left_index', 'right_index', 'value'])

print(df)
  left_index right_index  value
0     (0, 0)      (0, 0)    123
1     (0, 0)      (0, 1)    234
2     (1, 0)      (0, 1)    345
3     (1, 1)      (0, 1)    456

df['left_index_set'] = df['left_index'].apply(set)
df['right_index_set'] = df['right_index'].apply(set)

我不确定您在此之后需要什么。如果要过滤重复项,请执行以下操作。

df = df[df['left_index_set'] != df['right_index_set']]

df_final1= df[['left_index', 'right_index', 'value']]

print(df_final1)
  left_index right_index  value
1     (0, 0)      (0, 1)    234
3     (1, 1)      (0, 1)    456

但是,如果您不想过滤数据框而是想修改它:

df.loc[df['left_index_set'] != df['right_index_set'], 'right_index'] = None     # None, '' or what you want. It's up to you 
df_final2 = df[['left_index', 'right_index', 'value']]

print(df_final2)
  left_index right_index  value
0     (0, 0)      (0, 0)    123
1     (0, 0)        None    234
2     (1, 0)      (0, 1)    345
3     (1, 1)        None    456

您提到数据位于数据帧中并标记为 pandas,因此我们可以使用 numpy 使用矢量化为我们完成这项工作。

首先,由于您没有提供创建数据的方法,我根据您的描述生成了一个数据框:

import numpy as np
import pandas


def build_dataframe():
    def rand_series():
        """Create series of 1 million random integers in range [0, 9999]."""
        return (np.random.rand(1000000) * 10000).astype('int')

    data = pandas.DataFrame({
        'left_index': rand_series(),
        'right_index': rand_series()
    })
    return data.set_index('left_index')

data = build_dataframe()

由于 (0,1)(1,0) 相同,根据您的要求,让我们创建一个为我们排序的值的索引。先新建两列,左右索引的最小值和最大值:

data['min_index'] = np.minimum(data.index, data.right_index)
data['max_index'] = np.maximum(data.index, data.right_index)
print(data)
           right_index  min_index  max_index
left_index                                   
4270                438        438       4270
1277               9378       1277       9378
20                 7080         20       7080
4646               6623       4646       6623
3280               4481       3280       4481
...                 ...        ...        ...
3656               2492       2492       3656
2345                210        210       2345
9241               1934       1934       9241
369                8362        369       8362
5251               6047       5251       6047

[1000000 rows x 2 columns]

然后我们可以将索引重置为这两个新列(实际上我们只想要一个多索引,这是我们获得它的一种方法)。

data = data.reset_index().set_index(keys=['min_index', 'max_index'])
print(data)
                     left_index  right_index
min_index max_index                         
438       4270             4270          438
1277      9378             1277         9378
20        7080               20         7080
4646      6623             4646         6623
3280      4481             3280         4481
...                         ...          ...
2492      3656             3656         2492
210       2345             2345          210
1934      9241             9241         1934
369       8362              369         8362
5251      6047             5251         6047

[1000000 rows x 2 columns]

然后我们只需要索引的唯一值。这是最耗时的操作,但仍然比使用列表的简单实现快得多。

unique = data.index.unique()
print (unique)
MultiIndex([( 438, 4270),
            (1277, 9378),
            (  20, 7080),
            (4646, 6623),
            (3280, 4481),
            (4410, 9367),
            (1864, 7881),
            ( 516, 3287),
            (1678, 6946),
            (1253, 7890),
            ...
            (6669, 9527),
            (1095, 8866),
            ( 455, 7800),
            (2862, 8587),
            (8221, 9808),
            (2492, 3656),
            ( 210, 2345),
            (1934, 9241),
            ( 369, 8362),
            (5251, 6047)],
           names=['min_index', 'max_index'], length=990197)

使用 numpy 保留非唯一数组的第一次出现:

import numpy as np

lst1 = [(1,0), (0,1), (2, 5), (3,567), (5,2)]
arr = np.array(lst1)

result = arr[np.unique(np.sort(arr), 1, axis=0)[1]]

>>> result
array([[  1,   0],
       [  2,   5],
       [  3, 567]])