如何有效地比较二维矩阵中的每一对行?
How to efficiently compare each pair of rows in a 2D matrix?
我正在处理一个子例程,我需要处理矩阵的每一行并找出当前行中 包含 的其他行。为了说明一行 何时包含另一行 ,请考虑如下所示的 3x3 矩阵:
[[1, 0, 1],
[0, 1, 0],
[1, 0, 0]]
此处第 1 行包含第 3 行,因为 第 1 行中的每个元素都大于或等于第 3 行但第 1 行不包含第 2 行。
我提出了以下解决方案,但由于 for 循环(矩阵大小约为 6000x6000),它非常慢。
for i in range(no_of_rows):
# Here Adj is the 2D matrix
contains = np.argwhere(np.all(Adj[i] >= Adj, axis = 1))
能否让我知道是否可以更有效地做到这一点?
由于你矩阵的大小,以及你问题的要求,我认为迭代是不可避免的。你不能使用广播,因为它会爆炸你的内存,所以你需要逐行操作现有的数组。但是,您可以使用 numba
和 njit
来大大加快速度,而不是纯 python 方法。
import numpy as np
from numba import njit
@njit
def zero_out_contained_rows(a):
"""
Finds rows where all of the elements are
equal or smaller than all corresponding
elements of anothe row, and sets all
values in the row to zero
Parameters
----------
a: ndarray
The array to modify
Returns
-------
The modified array
Examples
--------
>>> zero_out_contained_rows(np.array([[1, 0, 1], [0, 1, 0], [1, 0, 0]]))
array([[1, 0, 1],
[0, 1, 0],
[0, 0, 0]])
"""
x, y = a.shape
contained = np.zeros(x, dtype=np.bool_)
for i in range(x):
for j in range(x):
if i != j and not contained[j]:
equal = True
for k in range(y):
if a[i, k] < a[j, k]:
equal = False
break
contained[j] = equal
a[contained] = 0
return a
这会记录一个 运行 行是否在另一行中使用的记录。这通过短路防止了许多不必要的比较,最后用 0
.
清除其他行中包含的行。
与您最初使用迭代的尝试相比,这是一个速度提升,并且还处理了将正确的行归零的问题。
a = np.random.randint(0, 2, (6000, 6000))
%timeit zero_out_contained_rows(a)
1.19 s ± 1.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
我会在您的尝试完成后更新时间 运行(目前大约 10 分钟)。
如果矩阵 6000x6000 超出您的需要 (6000*6000 - 6000)/2 = 17997000 次计算。
您可以尝试为矩阵的顶部三角形使用生成器,而不是使用 np.triu_indices - 它应该可以减少内存消耗。试试这个,也许会有帮助..
def indxs(lst):
for i1, el1 in enumerate(lst):
for el2 in lst[i1:][1:]:
yield (el1, el2)
我正在处理一个子例程,我需要处理矩阵的每一行并找出当前行中 包含 的其他行。为了说明一行 何时包含另一行 ,请考虑如下所示的 3x3 矩阵:
[[1, 0, 1],
[0, 1, 0],
[1, 0, 0]]
此处第 1 行包含第 3 行,因为 第 1 行中的每个元素都大于或等于第 3 行但第 1 行不包含第 2 行。
我提出了以下解决方案,但由于 for 循环(矩阵大小约为 6000x6000),它非常慢。
for i in range(no_of_rows):
# Here Adj is the 2D matrix
contains = np.argwhere(np.all(Adj[i] >= Adj, axis = 1))
能否让我知道是否可以更有效地做到这一点?
由于你矩阵的大小,以及你问题的要求,我认为迭代是不可避免的。你不能使用广播,因为它会爆炸你的内存,所以你需要逐行操作现有的数组。但是,您可以使用 numba
和 njit
来大大加快速度,而不是纯 python 方法。
import numpy as np
from numba import njit
@njit
def zero_out_contained_rows(a):
"""
Finds rows where all of the elements are
equal or smaller than all corresponding
elements of anothe row, and sets all
values in the row to zero
Parameters
----------
a: ndarray
The array to modify
Returns
-------
The modified array
Examples
--------
>>> zero_out_contained_rows(np.array([[1, 0, 1], [0, 1, 0], [1, 0, 0]]))
array([[1, 0, 1],
[0, 1, 0],
[0, 0, 0]])
"""
x, y = a.shape
contained = np.zeros(x, dtype=np.bool_)
for i in range(x):
for j in range(x):
if i != j and not contained[j]:
equal = True
for k in range(y):
if a[i, k] < a[j, k]:
equal = False
break
contained[j] = equal
a[contained] = 0
return a
这会记录一个 运行 行是否在另一行中使用的记录。这通过短路防止了许多不必要的比较,最后用 0
.
与您最初使用迭代的尝试相比,这是一个速度提升,并且还处理了将正确的行归零的问题。
a = np.random.randint(0, 2, (6000, 6000))
%timeit zero_out_contained_rows(a)
1.19 s ± 1.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
我会在您的尝试完成后更新时间 运行(目前大约 10 分钟)。
如果矩阵 6000x6000 超出您的需要 (6000*6000 - 6000)/2 = 17997000 次计算。
您可以尝试为矩阵的顶部三角形使用生成器,而不是使用 np.triu_indices - 它应该可以减少内存消耗。试试这个,也许会有帮助..
def indxs(lst):
for i1, el1 in enumerate(lst):
for el2 in lst[i1:][1:]:
yield (el1, el2)