Conditional Assignment in Julia - julia

In R, I can conditionally assign values like this:
A = matrix(c(1,2,3,4), ncol = 2)
A =
1 3
2 4
A[,1][A[,2] == 3] = 1000
A =
1000 3
2 4
In Julia, this same format doesn't work.
A = [1 3; 2 4]
A =
1 3
2 4
A[:,1][A[:,2] .== 3] = 1000
A =
1 3
2 4
I can't seem to figure out what's going on. Can anyone help?
Edit: Thanks. This works for replacing one value with another, like 1 with 1000. But it will not replace multiple. Why is that?
>A = [1 3 5; 2 4 6]
>A
1 3 5
2 4 6
>A1 = sub(A, :, 1)
>A1
1
2
>A2 = sub(A, :, 2)
>A2
3
4
>A1[A2 .> 2] = 1000
1000
>A
1000 3 5
2 4 6
Why does the replacement stop with the first instance and not continue to the second?

As mentioned in the linked post, range indexing produces copies. This can be circumvented using SubArray
julia> A = [1 3 5; 2 4 6]
2x3 Array{Int64,2}:
1 3 5
2 4 6
julia> A1 = sub(A, :, 1)
2-element SubArray{Int64,1,Array{Int64,2},Tuple{Colon,Int64},2}:
1
2
julia> A2 = sub(A, :, 2)
2-element SubArray{Int64,1,Array{Int64,2},Tuple{Colon,Int64},2}:
3
4
julia> A1[A2 .== 3] = 1000
1000
julia> A
2x3 Array{Int64,2}:
1000 3 5
2 4 6
Or using a for loop
julia> for i = 1:size(A,1)
A[i,2] == 3 && (A[i,1]=1000)
end
Edit: It seems the odd behavior you are seeing has been fixed at some point. Here's what I get on the latest git master
julia> versioninfo()
Julia Version 0.4.0-dev+4743
Commit dc088f7 (2015-05-08 13:29 UTC)
Platform Info:
System: Linux (x86_64-redhat-linux)
CPU: Intel(R) Xeon(R) CPU E5-2630 v2 # 2.60GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Sandybridge)
LAPACK: libopenblas
LIBM: libopenlibm
LLVM: libLLVM-3.3
julia> A = [1 3 5; 2 4 6]
2x3 Array{Int64,2}:
1 3 5
2 4 6
julia> A1 = sub(A, :, 1)
2-element SubArray{Int64,1,Array{Int64,2},Tuple{Colon,Int64},2}:
1
2
julia> A2 = sub(A, :, 2)
2-element SubArray{Int64,1,Array{Int64,2},Tuple{Colon,Int64},2}:
3
4
julia> A2 .> 2
2-element BitArray{1}:
true
true
julia> A1[A2 .> 2]
2-element Array{Int64,1}:
1
2
julia> A1[A2 .> 2] = 1000
1000
julia> A1
2-element SubArray{Int64,1,Array{Int64,2},Tuple{Colon,Int64},2}:
1000
1000
julia> A
2x3 Array{Int64,2}:
1000 3 5
1000 4 6
In general, the for loop version will be faster than doing things this way

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

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]

Adding an additional dimension to an array

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.

Best way to subtract vector from matrix in 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 - ).

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