Converting Array of CartesianIndex to 2D-Matrix in Julia - arrays

let's say we have an array of cartesian indices in Julia
julia> typeof(indx)
Array{CartesianIndex{2},1}
Now we want to plot them as a scatter-plot using PyPlot. so we should convert the indx-Array of Cartesian to a 2D-Matrix so we can plot it like this:
PyPlot.scatter(indx[:, 1], indx[:, 2])
How can i convert an Array of type Array{CartesianIndex{2},1} to a 2D-Matrix of type Array{Int,2}
By the way here is a code snippet how to produce a dummy Array of cartesianindex:
A = rand(1:10, 5, 5)
indx = findall(a -> a .> 5, A)
typeof(indx) # this is an Array{CartesianIndex{2},1}
Thanks

An easy and generic way is
julia> as_ints(a::AbstractArray{CartesianIndex{L}}) where L = reshape(reinterpret(Int, a), (L, size(a)...))
as_ints (generic function with 1 method)
julia> as_ints(indx)
2×9 reshape(reinterpret(Int64, ::Array{CartesianIndex{2},1}), 2, 9) with eltype Int64:
1 3 4 1 2 4 1 1 4
2 2 2 3 3 3 4 5 5
This works for any dimensionality, making the first dimension the index into the CartesianIndex.

One possible way is hcat(getindex.(indx, 1), getindex.(indx,2))
julia> #btime hcat(getindex.($indx, 1), getindex.($indx,2))
167.372 ns (6 allocations: 656 bytes)
10×2 Array{Int64,2}:
4 1
3 2
4 2
1 3
4 3
5 3
2 4
5 4
1 5
4 5
However, note that you don't need to - and therefore probably shouldn't - bring your indices to 2D-Matrix form. You could simply do
PyPlot.scatter(getindex.(indx, 1), getindex.(indx, 2))

Related

Julia strange answer from indexing an array

I'm attempting to index an array based on conditions in the array itself and corresponding locations in other arrays. I've produced a MWE but this will be hopefully used in a much larger example, within a loop to automate across scenarios, dare I say... using parallelisation?
MWE:
# create 3d array
a, b, c = [8;8;6;5;5;6], [8;8;7;6;6;6], [8;2;7;7;6;6]
d = transpose(cat(a,b,c, dims = 2))
e, f, g = [3;2;5;1;4;1], [4;3;1;1;1;2], [5;1;2;1;2;3]
h = transpose(cat(e,f,g, dims = 2))
wrkarr = cat(d,h,dims = 3)
# create temp array for indexes
temp = wrkarr[size(wrkarr,1), :, 1]
# calculate indexes
temp[(wrkarr[size(wrkarr,1),:,1] .== 8) .& (wrkarr[size(wrkarr,1),:,2]) .>= 4] .= 22
In my case it doesn't change anything in the temp array, when I would expect the first element to be changed from 8 to 22. Both of the individual conditional tests produce a vector [1,0,0,0,0,0] so why won't the .& test produce the same? Thx. J
First, and as an aside, please note that you can use arr[end,i] to refer to the element arr with the last index in the 1st axis, and index i in the second axis.
Using this notation, your condition can be rewritten as:
julia> (wrkarr[end,:,1] .== 8) .& (wrkarr[end,:,2]) .>=4
6-element BitArray{1}:
0
0
0
0
0
0
It might be a bit easier to see here that there is a parenthesis issue. I think you actually wanted to write:
julia> (wrkarr[end,:,1] .== 8) .& (wrkarr[end,:,2] .>=4)
6-element BitArray{1}:
1
0
0
0
0
0
Making this change does what (I think) you want. (Also note that I added #views below in order to avoid allocations and speed things up a little)
julia> idx = (#view(wrkarr[end,:,1]) .== 8) .& (#view(wrkarr[end,:,2]) .>=4);
julia> temp[idx] .= 22
1-element view(::Array{Int64,1}, [1]) with eltype Int64:
22
julia> temp
6-element Array{Int64,1}:
22
2
7
7
6
6
EDIT: as mentioned in comments, other solutions could be considered:
using findall to generate a vector of indices matching the condition
using a simple for loop
Here is a benchmark of all three solutions, in order to see how they compare in terms of readability and performance.
TLDR: the for loop seems to be much more efficient in this case, and allocates less.
# create 3d array
d = [8 8 6 5 5 6;
8 8 7 6 6 6;
8 2 7 7 6 6]
h = [3 2 5 1 4 1;
4 3 1 1 1 2;
5 1 2 1 2 3]
wrkarr = cat(d,h,dims = 3)
using BenchmarkTools
Option 1 logical indexing
julia> function version1!(temp, wrkarr)
idx = (#view(wrkarr[end,:,1]) .== 8) .& (#view(wrkarr[end,:,2]) .>= 4)
temp[idx] .= 22
end
version1! (generic function with 1 method)
julia> temp = wrkarr[end, :, 1]; #btime version1!($temp, $wrkarr); temp
182.646 ns (3 allocations: 224 bytes)
6-element Array{Int64,1}:
22
2
7
7
6
6
Option 2 vector of indices
julia> function version2!(temp, wrkarr)
idx = findall(i -> (wrkarr[end,i,1] == 8) & (wrkarr[end,i,2] >=4), axes(wrkarr,2))
temp[idx] .= 22
end
version2! (generic function with 1 method)
julia> temp = wrkarr[end, :, 1]; #btime version2!($temp, $wrkarr); temp
134.395 ns (3 allocations: 208 bytes)
6-element Array{Int64,1}:
22
2
7
7
6
6
Option 3 for loop
julia> function version3!(temp, wrkarr)
#inbounds for i in axes(wrkarr, 2)
if wrkarr[end, i, 1] == 8 && wrkarr[end, i, 2] >= 4
temp[i] = 22
end
end
end
version3! (generic function with 1 method)
julia> temp = wrkarr[end, :, 1]; #btime version3!($temp, $wrkarr); temp
21.820 ns (0 allocations: 0 bytes)
6-element Array{Int64,1}:
22
2
7
7
6
6
Based on all the clever stuff given to me above I pushed it a bit further and this solution appears to work and dispenses with the need for an index array, simply does the substitution right back into the original array. Is there anything wrong with that? Looking at #François Févotte's answer the loop function is the fastest, and this could be very important when scaled up to proper size. Now for my next challenge I want to use the same function to loop through sets of numbers to replace the 8, 4, 22, for example for the same wrkarr:
== 8 &>= 4 -> 22
== 7 &>= 2 -> 8
== 6 &>= 3 -> 7
Any takers or suggestions? When I get that to work I want to see if it can be parallelized across these individual sets of numbers, i.e. each substitution can be done independently, not dependent on any other. Thx a bunch!
function version4(wrkarr)
#inbounds for i in axes(wrkarr, 2)
if wrkarr[end, i, 1] == 8 && wrkarr[end, i, 2] >= 4
wrkarr[end,i, 1] = 22
end
end
end
wrkarr[end, :, 1]; #btime version4($wrkarr); wrkarr
2.237 ns (0 allocations: 0 bytes)
3×6×2 Array{Int64,3}:
[:, :, 1] =
8 8 6 5 5 6
8 8 7 6 6 6
22 2 7 7 6 6
[:, :, 2] =
3 2 5 1 4 1
4 3 1 1 1 2
5 1 2 1 2 3

How to convert an array of arrays into a matrix?

I can't find an answer to this simple question.
I have the following:
A(a,j)=[a*j*i*k for i in 1:2, k in 1:2];
B=[A(a,j) for a in 1:2, j in 1:2];
B is a an array of arrays: 2×2 Array{Array{Int64,2},2}. This is useful to easily access the subarrays with indices (e.g., B[2,1]). However, I also need to convert B to a 4 by 4 matrix. I tried hcat(B...) but that yields a 2 by 8 matrix, and other options are worse (e.g., cat(Test2...;dims=(2,1))).
Is there an efficient way of writing B as a matrix while keeping the ability to easily access its subarrays, especially as B gets very large?
Do you want this:
julia> hvcat(size(B,1), B...)
4×4 Array{Int64,2}:
1 2 2 4
2 4 4 8
2 4 4 8
4 8 8 16
or without defining B:
julia> hvcat(2, (A(a,j) for a in 1:2, j in 1:2)...)
4×4 Array{Int64,2}:
1 2 2 4
2 4 4 8
2 4 4 8
4 8 8 16
What about
B = reduce(hcat, reduce(vcat, A(a,j) for a in 1:2) for j in 1:2)
EDIT: Actually this is very slow, I would recommend making a function, e.g.,
function buildB(A, n)
A0 = A(1,1)
nA = size(A0, 1)
B = Array{eltype(A0),2}(undef, n * nA, n * nA)
for a in 1:n, j in 1:n
B[(a-1)*nA .+ (1:nA), (j-1)*nA .+ (1:nA)] .= A(a,j)
end
return B
end
or maybe consider a package like BlockArrays.jl?
EDIT 2 This is an example with BlockArrays.jl:
using BlockArrays
function blockarrays(A, n)
A0 = A(1,1)
nA = size(A0, 1)
B = BlockArray{eltype(A0)}(undef_blocks, fill(nA,n), fill(nA,n))
for a in 1:n, j in 1:n
setblock!(B, A(a,j), a, j)
end
return B
end
which should do what you want:
julia> B = blockarrays(A, 2)
2×2-blocked 4×4 BlockArray{Int64,2}:
1 2 │ 2 4
2 4 │ 4 8
──────┼───────
2 4 │ 4 8
4 8 │ 8 16
julia> getblock(B, 1, 2)
2×2 Array{Int64,2}:
2 4
4 8
julia> B[4,2]
8

Julia's Negative/Complement Indexing like R

Is there a functionality in Julia that's similar to R's negative indexing? In R, the code would be similar to:
x = 1:10
inds = c(1, 5, 7)
x[-inds]
[1] 2 3 4 6 8 9 10
I've found this to be extremely useful in numerous situations, especially for things such as sampling indices to create a testing/training set, but also for subindexing an array to exclude certain rows. So I am hoping there's something simple in Julia that can do the same.
This is similar to #Colin T Bower's answer and also only uses base Julia. Afraid it is not as elegant as your R example.
julia> minus(indx, x) = setdiff(1:length(x), indx)
minus (generic function with 1 method)
julia> x = collect(1:10)
10-element Array{Int64,1}:
1
2
3
4
5
6
7
8
9
10
julia> inds = [1, 5, 7]
3-element Array{Int64,1}:
1
5
7
julia> x[minus(inds, x)]
7-element Array{Int64,1}:
2
3
4
6
8
9
10
Not a feature of the base language, but see for example the package here: https://github.com/mbauman/InvertedIndices.jl

Given an index of choices for each column, construct a 1D array from a 2D array

I have a 2D array such as:
julia> m = [1 2 3 4 5
6 7 8 9 10
11 12 13 14 15]
3×5 Array{Int64,2}:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
I want to pick one value from each column and construct a 1D array.
So for instance, if my choices are
julia> choices = [1, 2, 3, 2, 1]
5-element Array{Int64,1}:
1
2
3
2
1
Then the desired output is [1, 7, 13, 9, 5]. What's the best way to do that? In my particular application, I am randomly generating these values, e.g.
choices = rand(1:size(m)[1], size(m)[2])
Thank you!
This is probably the simplest approach:
[m[c, i] for (i, c) in enumerate(choices)]
EDIT:
If best means fastest for you such a function should be approximately 2x faster than the comprehension for large m:
function selector(m, choices)
v = similar(m, size(m, 2))
for i in eachindex(choices)
#inbounds v[i] = m[choices[i], i]
end
v
end

Replicate Element-wise in matrix [duplicate]

This question already has answers here:
Element-wise array replication in Matlab
(7 answers)
A similar function to R's rep in Matlab [duplicate]
(4 answers)
Closed 8 years ago.
Let's say, I have:
A=[1 2; 3 4];
I want to use repmat that return:
B = [1 1 2 2; 1 1 2 2; 3 3 4 4; 3 3 4 4]
Kindly need your help. Thank you
I do not know a method using repmat but here is a method using kron
kron([1 2 ; 3 4],[1 1;1 1])
ans =
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
An alternative which uses repmat is
A=[1 2; 3 4];
cell2mat(arrayfun(#(x)repmat(x,2,2),A,'UniformOutput',false))
ans =
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
arrayfun is used to evaluate each element in A using the anonymous function #(x)repmat(x,2,2) which replicates that single element into a 2x2 matrix.
The result of arrayfun is a 2x2 cell array where each element is a 2x2 matrix. We then convert this cell array into a matrix via cell2mat.
Let the data be defined as
A = [1 2; 3 4];
R = 2; %// number of repetitions of each row
C = 2; %// number of repetitions of each column. May be different from R
Two possible approaches are as follows:
The simplest method is to use indexing:
B = A(ceil(1/R:1/R:size(A,1)), ceil(1/C:1/C:size(A,2)));
If you really want to do it with repmat, you need to play with dimensions using permute and reshape: move original dimensions 1, 2 to dimensions 2, 4 (permute); do the repetition along new dimensions 1, 3 (repmat); collapse dimensions 1, 2 into one dimension and 3, 4 into another dimension (reshape):
[r c] = size(A);
B = reshape(repmat(permute(A, [3 1 4 2]), [R 1 C 1]), [r*R c*C]);
Example result for R=2, C=3 (obtained with any of the two approaches):
B =
1 1 1 2 2 2
1 1 1 2 2 2
3 3 3 4 4 4
3 3 3 4 4 4

Resources