Due to the size of your matrices, and the requirements of your problem, I think iteration is unavoidable. You can't make use of broadcasting, since it will explode your memory, so you need to operate on the existing array row by row. You can use numba
and njit
to speed this up considerably over a pure-python approach however.
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
This keeps a running tally of whether or not a row is used in another row. This prevents many unnecessary comparisons by short-circuiting, before finally wiping out rows that are contained in others with 0
.
Compared to your initial attempt using iteration, this is a speed improvement, as well as also handles zero-ing out the proper rows.
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)
I will update the timings once your attempt finishes running (currently at ~10 minutes).