Best way to subtract vector from matrix in Julia - julia

What is the best way to subtract a vector of length N from a matrix of size (N, K) in Julia?
Of course, for loop or repmat should work but they do not seem to be the most efficient.
Can I use broadcast somehow?

julia> [1 2 3; 4 5 6; 7 8 9] .- [1; 2; 3]
3×3 Array{Int64,2}:
0 1 2
2 3 4
4 5 6
(obviously, subtracting horizontal vectors is also broadcasted)
julia> [1 2 3; 4 5 6; 7 8 9] .- [1 2 3]
3×3 Array{Int64,2}:
0 0 0
3 3 3
6 6 6
Also, note that the broadcasted call .- in the top example is essentially equivalent to
julia> (-).([1 2 3; 4 5 6; 7 8 9], [1; 2; 3])
3×3 Array{Int64,2}:
0 1 2
2 3 4
4 5 6
as of julia 0.6, unifying the f.(args) syntax / under-the-hood implementation for broadcasting functions with that for broadcasting operators.
(i.e. .- is no longer a separately defined operator, which happens to be a 'broadcasted' version of - ).

Related

Broadcasting vector to matrix to calculate sum (MATLAB style)

In MATLAB, I can do the following operation:
[1 2 3; 4 5 6] + [-1 -2 -3]
This will return [0 0 0; 3 3 3], as it understands that I want to perform the addition of the vector with each row of the matrix.
How can I do this in Julia? If I try, it gives me this error:
ERROR: DimensionMismatch("dimensions must match: a has dims (Base.OneTo(2), Base.OneTo(3)), b has dims (Base.OneTo(1), Base.OneTo(3)), mismatch at 1")
Add a dot in front of + like this:
julia> [1 2 3; 4 5 6] .+ [-1 -2 -3]
2×3 Matrix{Int64}:
0 0 0
3 3 3
However, note that [-1 -2 -3] is not a vector in Julia. It is a matrix having one row:
julia> [-1 -2 -3]
1×3 Matrix{Int64}:
-1 -2 -3
In Julia a vector would be [1, 2, 3] and vectors are always treated as columnar:
julia> [1, 2, 3]
3-element Vector{Int64}:
1
2
3
The reason why:
[1 2 3; 4 5 6] + [-1 -2 -3]
fails is that it is an incorrect expression from a mathematical perspective. These two matrices: [1 2 3; 4 5 6] and [-1 -2 -3] are representing linear operators having different spaces they operate on and adding such linear operators is typically considered as not allowed in mathematics.
However, if matrices had the same shape you could add them as linear operators then have the same dimension of the from and to spaces so they can be added:
julia> [1 2; 3 4] + [5 6; 7 8]
2×2 Matrix{Int64}:
6 8
10 12
(such an operation is mathematically well defined)
You can read more about broadcasting here.

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.
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

Broadcast over Array Dimension

Let's say I have a two-dimensional array
a = [1 2 3; 1 2 3]
2×3 Array{Int64,2}:
1 2 3
1 2 3
and I would like sum along a dimension, e.g. along dimension 1 yielding
[2, 4, 6]
or along dimension 2 yielding
[6, 6]
How is this done properly in Julia?
julia> sum(a; dims=1)
1×3 Array{Int64,2}:
2 4 6
julia> sum(a; dims=2)
2×1 Array{Int64,2}:
6
6
You can drop the dimension with vec.
What Jun Tian suggests is the standard way to do it. However, it is also worth to know a more general pattern:
julia> sum.(eachrow(a))
2-element Array{Int64,1}:
6
6
julia> sum.(eachcol(a))
3-element Array{Int64,1}:
2
4
6
In this case sum can be replaced by any collection aggregation function.

Get 2d index from flattened array

Given the array:
arr = [1 2; 3 4; 5 6]
3×2 Array{Int64,2}:
1 2
3 4
5 6
which is flattened flat_arr = collect(Iterators.flatten(arr))
6-element Array{Int64,1}:
1
3
5
2
4
6
I sometimes need to go between both index formats. For example, if I got the sorted indices of flat_arr, I may want to iterate over arr using these sorted indices. In Python, this is typically done with np.unravel_index. How is this done in Julia? Do I just need to write my own function?
vec() creates a 1-d view of the array. Hence you can have both pointers to the array in the memory and use whichever one you need in any minute (they point to the same array):
julia> arr = [1 2; 3 4; 5 6]
3×2 Array{Int64,2}:
1 2
3 4
5 6
julia> arr1d = vec(arr)
6-element Array{Int64,1}:
1
3
5
2
4
6
julia> arr1d[4] = 99
99
julia> arr
3×2 Array{Int64,2}:
1 99
3 4
5 6
Note that in Julia arrays are stored in column major order and hence the fourth value is the first value in the second column
This can be accomplished using CartesianIndices.
c_i = CartesianIndices(arr)
flat_arr[2] == arr[c_i[2]]) == 3

I want to create 2D array with 5 rows by 1 column

If I want to create 2D array with 1 row by 5 columns.
I could do this
julia> a = [1 2 3 4 5]
1×5 Array{Int64,2}:
1 2 3 4 5
But to create 2D array with 5 rows by 1 column. I have tried
julia> b = [1; 2; 3; 4; 5]
5-element Array{Int64,1}:
1
2
3
4
5
But I got back a 1D array which is NOT what I wanted
The only way to get it to work is
julia> b=reshape([1 2 3 4 5],5,1)
5×1 Array{Int64,2}:
1
2
3
4
5
Perhaps I am missing some crucial information here.
You could also do a = [1 2 3 4 5]'.
On a side note, for Julia versions > 0.6 the type of a wouldn't be Array{Int64, 2} but a LinearAlgebra.Adjoint{Int64,Array{Int64,2}} as conjugate transpose is lazy in this case. One can get <= 0.6 behavior by a = copy([1 2 3 4 5]').
AFAIK there is no syntactic sugar for it.
I usually write:
hcat([1, 2, 3, 4, 5])
which is short and I find it easy to remember.
If you use reshape you can replace one dimension with : which means you do not have to count (it is useful e.g. when you get an input vector as a variable):
reshape([1 2 3 4 5], :, 1)
Finally you could use:
permutedims([1 2 3 4 5])

Resources