What is the best way in Julia to vectorize a function along a specific axis? For example sum up all the rows of a matrix. Is it possible with the dot notation?
sum.(ones(4,4))
Does not yield the desired result.
Try using the dims argument on a lot of functions that deal with sets of values.
sum([1 2; 3 4], dims=2)
2×1 Matrix{Int64}:
3
7
# or
using Statistics
mean([1 2; 3 4], dims=1)
1×2 Matrix{Float64}:
2.0 3.0
There is already a standard function called mapslices, looks like exactly what you need.
julia> mapslices(sum, ones(4, 4), dims = 2)
4-element Vector{Float64}:
4.0
4.0
4.0
4.0
You can find the documentation here or by typing ? followed by mapslices in REPL.
If in your example you want to use the dot notation you should pass an array of rows, not the array itself. Otherwise, sum is applied to each element resulting in the same matrix. It can be done with eachrow and eachcol for rows and columns respectively.
julia> sum.(eachrow(ones(4, 4)))
4-element Vector{Float64}:
4.0
4.0
4.0
4.0
EDIT: I tried to suggest a more general solution, but if you have this option I would recommend using Andre's answer.
Related
I'm trying to analyse some experimental in a matrix and I'm having some issues.
For example I'd like to scale the columns of a matrix so that the first row of each column is 1.
I'd like to do it in the neat/clean julia way that I'm now starting to learn but I'm struggling to find a good solution.
The problem comes from the fact that each column is the result of some experimental test, and they have different lengths. I've "fixed" this by creating the matrix in excel, adding a missing in the empty cells at the bottom of the column and then copy pasting it in julia. I take this is probably not the best way to deal with the issue?
Example: (normal matrices are much bigger though)
A=[1 2 3
4 5 6
missing missing 9]
After that, I'd like to do some analysis, one of which is scaling the matrix so that the first row is = [1 1 1...1]. I tried both map
map((x,y)->x./y,A[2:end,:],A[1,:])
but it seems to apply the top row the the first N elements of the first column only.
Alternatively I tried with mapslices but I'm getting the following error MethodError: Cannot `convert` an object of type Missing to an object of type Float64
I have the feeling I'm missing something and my googlefoo is failing me... any help is much appreciated!
PS: Apologies if I missed some already answered question or if I missed some guideline, I'll try to improve my question if needed. It's the first time I post here!
I'm not sure what your first question is, it seems hard to answer without knowing what the data you're processing it looks like.
Your second question if I understand correctly should be as simple as:
julia> A ./ A[1, :]'
3×3 Matrix{Union{Missing, Float64}}:
1.0 1.0 1.0
4.0 2.5 2.0
missing missing 3.0
Edit to add:
Whether a matrix is or isn't a good idea here depends on the wider context, but if you have some vectors of numbers of different lengths, you can just put them in a vector of vectors rather than a matrix, which means they don't all have to have the same length:
julia> x = rand(3); y = rand(5);
julia> A = [x, y]
2-element Vector{Vector{Float64}}:
[0.2654489138174001, 0.8598585826482341, 0.43527866751212607]
[0.4702376843007643, 0.7890927390349933, 0.6073796489306595, 0.9178238662871376, 0.5917433487576529]
julia> A ./ first.(A)
2-element Vector{Vector{Float64}}:
[1.0, 3.2392620119731323, 1.6397831931290188]
[1.0, 1.6780721013637205, 1.2916439264833126, 1.9518296745015802, 1.2583920185758093]
Coming from R I am used to do something like this to get the first element of vector a:
a <- c(1:3, 5)
a[1]
[1] 1
H can I get the 1 in Julia? The first element of a is now a range.
a = [1:3, 5]
a[1]
1-element Array{UnitRange{Int64},1}:
1:3
The core problem here is that c(1:3, 5) in R and [1:3, 5] in Julia do not do the same thing. The R code concatenates a vector with an integer producing a vector of four integers:
> c(1:3, 5)
[1] 1 2 3 5
The Julia code constructs a two-element vector whose elements are the range 1:3 and the integer 5:
julia> [1:3, 5]
2-element Vector{Any}:
1:3
5
julia> map(typeof, ans)
2-element Vector{DataType}:
UnitRange{Int64}
Int64
This vector has element type Any because there's no smaller useful common supertype of a range and an integer. If you want to concatenate 1:3 and 5 together into a vector you can use ; inside of the brackets instead of ,:
julia> a = [1:3; 5]
4-element Vector{Int64}:
1
2
3
5
Once you've defined a correctly, you can get its first element with a[1] just like in R. In general inside of square brackets in Julia:
Comma (,) is only for constructing vectors of the exact elements given, much like in Python, Ruby, Perl or JavaScript.
If you want block concatenation like in R or Matlab, then you need to use semicolons/newlines (; or \n) for vertical concatenation and spaces for horizontal concatenation.
The given example of [1:3; 5] is a very simple instance of block concatenation, but there are significantly more complex ones possible. Here's a fancy example of constructing a block matrix:
julia> using LinearAlgebra
julia> A = rand(2, 3)
2×3 Matrix{Float64}:
0.895017 0.442896 0.0488714
0.750572 0.797464 0.765322
julia> [A' I
0I A]
5×5 Matrix{Float64}:
0.895017 0.750572 1.0 0.0 0.0
0.442896 0.797464 0.0 1.0 0.0
0.0488714 0.765322 0.0 0.0 1.0
0.0 0.0 0.895017 0.442896 0.0488714
0.0 0.0 0.750572 0.797464 0.765322
Apologies for StackOverflow's lousy syntax highlighting here: it seems to get confused by the postfix ', interpreting it as a neverending character literal. To explain this example a bit:
A is a 2×3 random matrix of Float64 elements
A' is the adjoint (conjugate transpose) of A
I is a variable size unit diagonal operator
0I is similar but the diagonal scalar is zero
These are concatenated together to form a single 5×5 matrix of Float64 elements where the upper left and lower right parts are filled from A' and A, respectively, while the lower left is filled with zeros and the upper left is filled with the 3×3 identity matrix (i.e. zeros with diagonal ones).
In this case, your a[1] is a UnitRange collection. If you want to access an individual element of it, you can use collect
For example for the first element,
collect(a[1])[1]
I want to turn an array like this
[1,2,3,4,5]
into a lagged version
[missing,1,2,3,4] # lag 1
[missing,missing,1,2,3] # lag 2
or a led version
[2,3,4,5,missing] # lead 1
[3,4,5,missing,missing] # lead 2
As Julia is designed for scientific computing, there must be something like this, right?
Add ShiftedArrays. See: https://discourse.julialang.org/t/ann-shiftedarrays-and-support-for-shiftedarrays-in-groupederrors/9162
Quoting from the above:
lag, lead functions, to shift an array and add missing (or a custom default value in the latest not yet released version) where the data is not available, or circshift for shifting circularly in a lazy (non allocating) way:
julia> v = [1.2, 2.3, 3.4]
3-element Array{Float64,1}:
1.2
2.3
3.4
julia> lag(v)
3-element ShiftedArrays.ShiftedArray{Float64,Missings.Missing,1,Array{Float64,1}}:
missing
1.2
2.3
Note the ShiftedArray version of lag keeps the array size the same. You might add a short function to make it behave the way you asked:
biglag(v, n) = lag(vcat(v, v[1:n]), n)
I was delighted to learn that Julia allows a beautifully succinct way to form inner products:
julia> x = [1;0]; y = [0;1];
julia> x'y
1-element Array{Int64,1}:
0
This alternative to dot(x,y) is nice, but it can lead to surprises:
julia> #printf "Inner product = %f\n" x'y
Inner product = ERROR: type: non-boolean (Array{Bool,1}) used in boolean context
julia> #printf "Inner product = %f\n" dot(x,y)
Inner product = 0.000000
So while i'd like to write x'y, it seems best to avoid it, since otherwise I need to be conscious of pitfalls related to scalars versus 1-by-1 matrices.
But I'm new to Julia, and probably I'm not thinking in the right way. Do others use this succinct alternative to dot, and if so, when is it safe to do so?
There is a conceptual problem here. When you do
julia> x = [1;0]; y = [0;1];
julia> x'y
0
That is actually turned into a matrix * vector product with dimensions of 2x1 and 1 respectively, resulting in a 1x1 matrix. Other languages, such as MATLAB, don't distinguish between a 1x1 matrix and a scalar quantity, but Julia does for a variety of reasons. It is thus never safe to use it as alternative to the "true" inner product function dot, which is defined to return a scalar output.
Now, if you aren't a fan of the dots, you can consider sum(x.*y) of sum(x'y). Also keep in mind that column and row vectors are different: in fact, there is no such thing as a row vector in Julia, more that there is a 1xN matrix. So you get things like
julia> x = [ 1 2 3 ]
1x3 Array{Int64,2}:
1 2 3
julia> y = [ 3 2 1]
1x3 Array{Int64,2}:
3 2 1
julia> dot(x,y)
ERROR: `dot` has no method matching dot(::Array{Int64,2}, ::Array{Int64,2})
You might have used a 2d row vector where a 1d column vector was required.
Note the difference between 1d column vector [1,2,3] and 2d row vector [1 2 3].
You can convert to a column vector with the vec() function.
The error message suggestion is dot(vec(x),vec(y), but sum(x.*y) also works in this case and is shorter.
julia> sum(x.*y)
10
julia> dot(vec(x),vec(y))
10
Now, you can write x⋅y instead of dot(x,y).
To write the ⋅ symbol, type \cdot followed by the TAB key.
If the first argument is complex, it is conjugated.
Now, dot() and ⋅ also work for matrices.
Since version 1.0, you need
using LinearAlgebra
before you use the dot product function or operator.
I'm trying to use mean(A,1) to get the mean row of a matrix A, but am getting an error.
For example, try running the command mean(eye(3), 1).
This gives the error no method mean(Array{Float64,2},Int32).
The only documentation I can find for the mean function is here:
http://docs.julialang.org/en/release-0.1/stdlib/base/#statistics
mean(v[, region])
Compute the mean of whole array v, or optionally along the dimensions in region.
What is the region parameter?
EDIT: for Julia 0.7 and higher, write this as mean(v, dims=1).
julia> using Statistics
julia> A = [[1 2 3];[ 4 5 6]]
2×3 Array{Int64,2}:
1 2 3
4 5 6
# Column means
julia> mean(A, dims=1)
1×3 Array{Float64,2}:
2.5 3.5 4.5
# Row means
julia> mean(A, dims=2)
2×1 Array{Float64,2}:
2.0
5.0
It must be something with your installation, mean(eye(3),1) works just fine here.