juliamatrix-indexing

Use a BitArray in Julia to filter rows of an array


I'd like to filter each row of my matrix a such that each row contains non-negative values.

First, I tried this:

julia> a = [-1 2 3; 4 5 6; -5 3 4; 3 5 5]
4×3 Matrix{Int64}:
 -1  2  3
  4  5  6
 -5  3  4
  3  5  5

julia> # Desired Operation after filtering should yield 2x3 matrix, [4 5 6; 3 5 5]

julia> mask1 = a .>= 0
4×3 BitMatrix:
 0  1  1
 1  1  1
 0  1  1
 1  1  1

julia> a[mask1]
10-element Vector{Int64}:
 4
 3
 2
 5
 3
 5
 3
 6
 4
 5

This first attempt flattens my matrix. The same thing happens when I do a[mask1, :].

My second attempt I tried this (the equivalent logic works using python's numpy):

julia> mask2 = minimum(a, dims=2) .>= 0
4×1 BitMatrix:
 0
 1
 0
 1

julia> a[mask2, :]
2×1 Matrix{Int64}:
 4
 3

My second attempt only captures the first element of the second and fourth rows, when I want the entire second and fourth rows. Note that if I use the equivalent boolean array for mask2, I do get the desired result:

julia> mask3 = [false; true; false; true]
4-element Vector{Bool}:
 0
 1
 0
 1

julia> a[mask3, :]
2×3 Matrix{Int64}:
 4  5  6
 3  5  5

So, is the idiomatic way to do this row by row filtering to cast BitMatrix to a Vector{Bool}, or is there a cleaner way? Additionally, the crux of the question is why BitMatrix only returns one element of one row while Vector{Bool} returns the entire row.


Solution

  • One possible way:

    julia> a[[all(row.>=0) for row in eachrow(a)], :]
    2×3 Matrix{Int64}:
     4  5  6
     3  5  5
    

    Another one:

    julia> a[findall(x->all(x .>=0), eachrow(a)), :]
    2×3 Matrix{Int64}:
     4  5  6
     3  5  5
    

    The version with minimum you were trying to do would be:

    julia> a[minimum.(eachrow(a)) .>= 0, :]
    2×3 Matrix{Int64}:
     4  5  6
     3  5  5
    

    or following @DNF suggestion which is actually the best:

    julia> a[all.(>=(0), eachrow(a)), :]
    2×3 Matrix{Int64}:
     4  5  6
     3  5  5