有效地删除包含不同行之间重复元素的行

Efficiently remove rows containing repeating elements between different rows

给定一个二维数组,我可能在索引 i 处有一行可能在另一行中找到一个或多个数字索引 j。我需要从中删除那些行 ij阵列。 同样在任何行中,数字对于该行始终是唯一的。我已经有了没有循环的解决方案,基于 Numpy。 这是我想出的唯一解决方案:

def filter_array(arr):
    # Reshape to 1D without hard copy
    arr_1d = arr.ravel()
    # Make a count of only the existing numbers (faster than histogram)
    u_elem, c = np.unique(arr_1d, return_counts=True)
    # Get which elements are duplicates.
    duplicates = u_elem[c > 1]
    # Get the rows where these duplicates belong
    dup_idx = np.concatenate([np.where(arr_1d == d)[0] for d in duplicates])
    dup_rows = np.unique(dup_idx //9)
    # Remove the rows from the array
    b = np.delete(arr, dup_rows, axis=0)
    return b

这是一个(过度简化的)输入数组示例:

a = np.array([
    [1, 3, 23, 40, 33],
    [2, 8, 5, 35, 7],
    [9, 32, 4, 6, 3],
    [72, 85, 32, 48, 53],
    [3, 98, 101, 589, 208],
    [343, 3223, 4043, 65, 78]
])

过滤后的数组给出了预期的结果,尽管我没有详尽检查这是否适用于所有可能的情况:

[[   2    8    5   35    7]
 [ 343 3223 4043   65   78]]

我的典型数组大小约为 10^5 到 10^6 行,固定数量为 9 列。 %timeit 给了大约 270 毫秒来过滤每个这样的数组。我有一亿个。在考虑其他方式(例如 GPU)

之前,我试图在单个 cpu 上加快速度

这些数据可能已经存在于 Pandas 数据框中。

我们可以通过在找到唯一值及其计数后使用 np.isin 并使用结果对数组进行索引来实现显着的加速:

u, c = np.unique(a, return_counts=True)
a[np.isin(a, u[c == 1]).all(1)]

array([[   2,    8,    5,   35,    7],
       [ 343, 3223, 4043,   65,   78]])

时间安排:

def filter_array(arr):
    arr_1d = arr.ravel()
    u_elem, c = np.unique(arr_1d, return_counts=True)
    duplicates = u_elem[c > 1]
    dup_idx = np.concatenate([np.where(arr_1d == d)[0] for d in duplicates])
    dup_rows = np.unique(dup_idx //9)
    b = np.delete(arr, dup_rows, axis=0)
    return b

def yatu(arr):
    u, c = np.unique(arr, return_counts=True)
    return arr[np.isin(arr, u[c == 1]).all(1)]

a_large = np.random.randint(0, 50_000, (10_000, 5))

%timeit filter_array(a_large)
# 433 ms ± 25.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit yatu(a_large)
# 7.81 ms ± 443 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)