Julia matrix row becomes a column during indexing - matrix

Issue: When building a matrix out of single rows, Julia interprets them as columns instead.
a = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
b = [a[1:2,:]; a[1:2,:]] # Rows duplicated correctly
4×3 Array{Int64,2}:
1 2 3
4 5 6
1 2 3
4 5 6
c = [a[1,:]; a[1,:]] # Rows converted to columns
6-element Array{Int64,1}:
1
2
3
1
2
3
How to fix this?

In addition to the range index, you can transpose vectors
julia> [a[1, :]'; a[1, :]']
2×3 Array{Int64,2}:
1 2 3
1 2 3
It looks likes this approach is somewhat more performant, than the range index, but it should be tested on larger matrices, also it is not consistent, if you have ranges and single columns
using BenchmarkTools
f1(a) = [a[1:1,:]; a[1:1,:]]
f2(a) = [a[1, :]'; a[1, :]']
julia> #btime f1($a)
122.440 ns (3 allocations: 352 bytes)
2×3 Array{Int64,2}:
1 2 3
1 2 3
julia> #btime f2($a)
107.480 ns (3 allocations: 352 bytes)
2×3 Array{Int64,2}:
1 2 3
1 2 3

Solution: Although it may feel a bit perplexing, its because the type has changed from a matrix into a vector. To keep the type the same you'll need to select from your desired row, to your desired row in a similar manner to the second line of code in your example.
c = [a[1:1,:]; a[1:1,:]]
2×3 Array{Int64,2}:
1 2 3
1 2 3

Related

Intersection of two matrices in Julia?

Is there any function or method in Julia that would allow one to compute the intersection of two matrices A and B?
There are many possible definitions for intersection.
Suppose that you have:
julia> a=[1 2 3;4 5 6;3 2 1]
3×3 Matrix{Int64}:
1 2 3
4 5 6
3 2 1
julia> b = a'
3×3 adjoint(::Matrix{Int64}) with eltype Int64:
1 4 3
2 5 2
3 6 1
and if you mean by intersection you mean matrix with elements who have the same values in both matrices and zero otherwise you could do:
julia> (a .== b) .* a
3×3 Matrix{Int64}:
1 0 3
0 5 0
3 0 1

Language Julia: convert vector in matrix

Who can help.
To transform a vector into a one-dimensional matrix just run in Julia:
a = copy(permutedims([1,2,3]))
To transform the matrix "a" into a vector just use:
b = copy(vec(a))
If you have a matrix "[1 2 3; 4 5 6]" to transform it into a vector, just:
c = vec([1 2 3; 4 5 6])
Now how to make the vector have the form of the 2x3 matrix like:
2×3 Matrix{Int64}:
1 2 3
4 5 6
You can use reshape
julia> c = vec([1 2 3; 4 5 6])
6-element Vector{Int64}:
1
4
2
5
3
6
julia> M=reshape(c,2,3)
2×3 Matrix{Int64}:
1 2 3
4 5 6
Note that this operation does not reallocate memory, c and M share the same memory. By example:
julia> c[1]=10
10
julia> M
2×3 Matrix{Int64}:
10 2 3
4 5 6

Ranking over each matrix column's sort in julia

I have a matrix (m) of scores for 4 students on 3 different exams.
4 3 1
3 2 5
8 4 6
1 5 2
I want to know, for each student, the exams they did best to worse on. Desired output:
1 2 3
2 3 1
1 3 2
3 1 2
Now, I'm new to the language (and coding in general), so I read GeeksforGeeks' page on sorting in Julia and tried
mapslices(sortperm, -m; dims = 2)
However, this gives something subtly different: a matrix of each row being the index of the sorting.
1 2 3
3 1 2
1 3 2
2 3 1
Perhaps it was obvious, but I now realize this is not actually what I want, but I cannot find a built-in function/fast way to complete this operation. Any ideas? Preferably something which doesn't iterate through items in the matrix/row, as in reality my matrix is very, very large. Thanks!
Such functionality is provided by StatsBase.jl. Here is an example:
julia> using StatsBase
julia> m = [4 3 1
3 2 5
8 4 6
1 5 2]
4×3 Array{Int64,2}:
4 3 1
3 2 5
8 4 6
1 5 2
julia> mapslices(x -> ordinalrank(x, rev=true), m, dims = 2)
4×3 Array{Int64,2}:
1 2 3
2 3 1
1 3 2
3 1 2
You might want to use other rank, depending on how you want to split ties, see here for details.
Figured out something which works!
Run m_index_rank = mapslices(sortperm, -m; dims = 2) on the matrix and get a ranking for each row through index. Then, realizing this is, in each row, an inverse permutation away from the desired output, run mapslices(invperm, m_index_rank; dims = 2) for the desired result.
In one line, this is mapslices(r -> invperm(sortperm(r, rev=true)), m; dims=2) over the desired matrix m. dims = 2 is to carry out the operation row-wise.
I'm marking this resolved for now, but please let me know if there are cleaner/faster ways to do this.
Edit: Replaced my syntactically clunky mapslices(invperm, mapslices(sortperm, -m; dims = 2); dims = 2) with a more natural one, thanks to #phipsgabler

Julialang: In-place sort for columns of a matrix

I have a huge matrix and want to sort the columns in place for speed/memory efficency. Is it possible to use in-place sort for the columns of a matrix in Julia?
As an example, take the following matrix:
julia> M=Matrix{Int}(3,3);
julia> for i = 1:size(M)[1]
for j = 1:size(M)[2]
M[i,j]=3*(j-1)+i
end
end
julia> M
3×3 Array{Int64,2}:
1 4 7
2 5 8
3 6 9
I want to use in-place sort for the columns to obtain the matrix
3×3 Array{Int64,2}:
3 6 9
2 5 8
1 4 7
This can be obtained without in-place sort as follows:
julia> M_sorted=Matrix{Int}(3,3);
julia> for j = 1:size(M)[2]
M_sorted[:,j]=sort(M[:,j],rev=true)
end
julia> M_sorted
3×3 Array{Int64,2}:
3 6 9
2 5 8
1 4 7
But something like that fails (here only for one column):
julia> sort!(M[:,1],rev=true)
3-element Array{Int64,1}:
3
2
1
julia> M
3×3 Array{Int64,2}:
1 4 7
2 5 8
3 6 9
Is there any way to use in-place sort in this case? Note that there is no problem with the indexing since the matrix is saved column-wise in memory:
julia> M[1:end]
9-element Array{Int64,1}:
1
2
3
4
5
6
7
8
9
So I think it should be possible.
Slicing creates a copy of the column and sorts on that. If you instead want to directly sort in the memory of the existing array, use a view. Example:
M=Matrix{Int}(undef,3,3)
for i = 1:size(M)[1]
for j = 1:size(M)[2]
M[i,j]=3*(j-1)+i
end
end
M
3×3 Array{Int64,2}:
1 4 7
2 5 8
3 6 9
sort!(#view(M[:,1]),rev=true)
M
3×3 Array{Int64,2}:
3 4 7
2 5 8
1 6 9

Adding zeros between every 2 elements of a matrix in matlab/octave

I am interested in how can I add rows and columns of zeros in a matrix so that it looks like this:
1 0 2 0 3
1 2 3 0 0 0 0 0
2 3 4 => 2 0 3 0 4
5 4 3 0 0 0 0 0
5 0 4 0 3
Actually I am interested in how can I do this efficiently, because walking the matrix and adding zeros takes a lot of time if you work with a big matrix.
Update:
Thank you very much.
Now I'm trying to replace the zeroes with the sum of their neighbors:
1 0 2 0 3 1 3 2 5 3
1 2 3 0 0 0 0 0 3 8 5 12... and so on
2 3 4 => 2 0 3 0 4 =>
5 4 3 0 0 0 0 0
5 0 4 0 3
as you can see i'm considering all the 8 neighbors of an element, but again using for and walking the matrix slows me down quite a bit, is there a faster way ?
Let your little matrix be called m1. Then:
m2 = zeros(5)
m2(1:2:end,1:2:end) = m1(:,:)
Obviously this is hard-wired to your example, I'll leave it to you to generalise.
Here are two ways to do part 2 of the question. The first does the shifts explicitly, and the second uses conv2. The second way should be faster.
M=[1 2 3; 2 3 4 ; 5 4 3];
% this matrix (M expanded) has zeros inserted, but also an extra row and column of zeros
Mex = kron(M,[1 0 ; 0 0 ]);
% The sum matrix is built from shifts of the original matrix
Msum = Mex + circshift(Mex,[1 0]) + ...
circshift(Mex,[-1 0]) +...
circshift(Mex,[0 -1]) + ...
circshift(Mex,[0 1]) + ...
circshift(Mex,[1 1]) + ...
circshift(Mex,[-1 1]) + ...
circshift(Mex,[1 -1]) + ...
circshift(Mex,[-1 -1]);
% trim the extra line
Msum = Msum(1:end-1,1:end-1)
% another version, a bit more fancy:
MexTrimmed = Mex(1:end-1,1:end-1);
MsumV2 = conv2(MexTrimmed,ones(3),'same')
Output:
Msum =
1 3 2 5 3
3 8 5 12 7
2 5 3 7 4
7 14 7 14 7
5 9 4 7 3
MsumV2 =
1 3 2 5 3
3 8 5 12 7
2 5 3 7 4
7 14 7 14 7
5 9 4 7 3

Resources