Adding an additional dimension to an array - julia

Note: This question/answer is copied from the Julia Slack channel.
If I have an arbitrary Julia Array, how can I add another dimension.
julia> a = [1, 2, 3, 4]
4-element Array{Int64,1}:
1
2
3
4
The desired output would be e.g.:
julia> a[some_magic, :]
1×4 Array{Int64,2}:
1 2 3 4
Or:
julia> a[:, some_magic]
4×1 Array{Int64,2}:
1
2
3
4

A less tricky thing I usually do to achieve this is:
julia> reshape(a, 1, :)
1×4 Array{Int64,2}:
1 2 3 4
julia> reshape(a, :, 1)
4×1 Array{Int64,2}:
1
2
3
4
(it also seems to involve less typing)
Finally a common case requiring transforming a vector to a column matrix can be done:
julia> hcat(a)
4×1 Array{Int64,2}:
1
2
3
4
EDIT also if you add trailing dimensions you can simply use ::
julia> a = [1,2,3,4]
4-element Array{Int64,1}:
1
2
3
4
julia> a[:,:]
4×1 Array{Int64,2}:
1
2
3
4
julia> a[:,:,:]
4×1×1 Array{Int64,3}:
[:, :, 1] =
1
2
3
4

The trick is so use [CartesianIndex()] to create the additional axes:
julia> a[[CartesianIndex()], :]
1×4 Array{Int64,2}:
1 2 3 4
And:
julia> a[:, [CartesianIndex()]]
4×1 Array{Int64,2}:
1
2
3
4
If you want to get closer to numpy's syntax, you can define:
const newaxis = [CartesianIndex()]
And just use newaxis.

Related

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.

Operations with CartesianIndex

I'd like to know how can I operate with CartesianIndex. For example I have array
julia> A = rand(1:5, 10, 2)
10×2 Array{Int64,2}:
2 5
1 1
4 5
4 1
2 1
4 1
2 4
1 5
2 5
4 4
and I want to save all numbers which stay near (in pair) with number 1. I can use c=findall(x->x==1, A), but I will have a cartensian indexes of "1".
There is function x=getindex.(c, [1 2]) it makes an array which I can change, but I don't know how to convert it back to CartesianIndex. And I think that must be a better way to do this.
A[view(A.==1,:,[2,1])]
This literally returns "all numbers which stay in pair with number 1".
The order of returned numbers is columnar. If you want to return it by rows:
A'[view(A.==1,:,[2,1])']
Example:
julia> A = rand(1:5, 10, 2)
10×2 Array{Int64,2}:
1 4
3 3
1 3
3 3
5 1
1 5
2 1
3 3
1 3
2 3
julia> A'[view(A.==1,:,[2,1])']
6-element Array{Int64,1}:
4
3
5
5
2
3
If you rather want full rows than use filter!:
julia> filter!((x)->(1 in x), collect(eachrow(A)))
6-element Array{SubArray{Int64,1,Array{Int64,2},Tuple{Int64,Base.Slice{Base.OneTo{Int64}}},true},1}:
[1, 4]
[1, 3]
[5, 1]
[1, 5]
[2, 1]
[1, 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])

Concatenating arrays in Julia

If the two Int arrays are, a = [1;2;3] and b = [4;5;6], how do we concatenate the two arrays in both the dimensions? The expected outputs are,
julia> out1
6-element Array{Int64,1}:
1
2
3
4
5
6
julia> out2
3x2 Array{Int64,2}:
1 4
2 5
3 6
Use the vcat and hcat functions:
julia> a, b = [1;2;3], [4;5;6]
([1,2,3],[4,5,6])
help?> vcat
Base.vcat(A...)
Concatenate along dimension 1
julia> vcat(a, b)
6-element Array{Int64,1}:
1
2
3
4
5
6
help?> hcat
Base.hcat(A...)
Concatenate along dimension 2
julia> hcat(a, b)
3x2 Array{Int64,2}:
1 4
2 5
3 6
Square brackets can be used for concatenation:
julia> a, b = [1;2;3], [4;5;6]
([1,2,3],[4,5,6])
julia> [a; b]
6-element Array{Int64,1}:
1
2
3
4
5
6
julia> [a b]
3×2 Array{Int64,2}:
1 4
2 5
3 6
You can use the cat function to concatenate any number of arrays along any dimension. The first input is the dimension over which to perform the concatenation; the remaining inputs are all of the arrays you wish to concatenate together
a = [1;2;3]
b = [4;5;6]
## Concatenate 2 arrays along the first dimension
cat(1,a,b)
6-element Array{Int64,1}:
1
2
3
4
5
6
## Concatenate 2 arrays along the second dimension
cat(2,a,b)
3x2 Array{Int64,2}:
1 4
2 5
3 6
## Concatenate 2 arrays along the third dimension
cat(3,a,b)
3x1x2 Array{Int64,3}:
[:, :, 1] =
1
2
3
[:, :, 2] =
4
5
6
when encountered Array{Array,1}, the grammer is a little bit different, like this:
julia> a=[[1,2],[3,4]]
2-element Array{Array{Int64,1},1}:
[1, 2]
[3, 4]
julia> vcat(a)
2-element Array{Array{Int64,1},1}:
[1, 2]
[3, 4]
julia> hcat(a)
2×1 Array{Array{Int64,1},2}:
[1, 2]
[3, 4]
julia> vcat(a...)
4-element Array{Int64,1}:
1
2
3
4
julia> hcat(a...)
2×2 Array{Int64,2}:
1 3
2 4
ref:
... combines many arguments into one argument in function definitions
In the context of function definitions, the ... operator is used to combine many different arguments into a single argument. This use of ... for combining many different arguments into a single argument is called slurping
Functional way to concatanate 2 arrays is to use reduce function.
a = rand(10, 1)
b = rand(10, 1)
c = reduce(hcat, [ a, b])

Resources