Julia: find maximum along columns in array - julia

Suppose we have an array defined like this:
a=[1 2; 3 4; 5 5; 7 9; 1 2];
In Matlab, we could find the maximum values by writing:
[x y] = max(a)
x =
7 9
In Julia, we could use:
a=[1 2; 3 4; 5 5; 7 9; 1 2]
findmax(a,1)
returning:
([7 9],
[4 9])
However, I am interested not only in finding [7 9] for the two columns, but also their relative position within each column, like [4, 4]. Of course, I can write a bit more of coding lines, but can I do it directly with findmax?

The second matrix returned by findmax is the linear index of the locations of the maxima over the entire array. You want the position within each column; to get that, you can convert the linear indices into subscripts with ind2sub. Then the first element of the subscript tuple is your row index.
julia> vals, inds = findmax(a, 1)
(
[7 9],
[4 9])
julia> map(x->ind2sub(a, x), inds)
1×2 Array{Tuple{Int64,Int64},2}:
(4,1) (4,2)
julia> map(x->ind2sub(a, x)[1], inds)
1×2 Array{Int64,2}:
4 4

This is mentioned in the comments but I figured I'd do a response that's easy to see. I have version 1.0.3, so I don't know what's the earliest version that allows this. But now you can just do
julia> findmax(a) #Returns 2D index of overall maximum value
(9, CartesianIndex(4, 2))
julia> findmax(a[:,1]) #Returns 1D index of max value in column 1
(7, 4)
julia> findmax(a[:,2]) #Returns 1D index of max value in column 2
(9, 4)
Hope this makes things easier.

I've adopted the following function:
indmaxC(x) = cat(1, [indmax(x[:,c]) for c in 1:size(x,2)]...)
The Good: it's convenient and small
The Bad: it's only valid for 2-D arrays
A safer version would be:
function indmaxC(x::AbstractArray)
assert(ndims(x)==2)
cat(1, [indmax(x[:,c]) for c in 1:size(x,2)]...)
end

Related

How can I slice the high-order multidimeonal array (or tensor) on the specific axis in Julia?

I am using Julia1.6
Here, X is a D-order multidimeonal array.
How can I slice from i to j on the d-th axis of X ?
Here is an exapmle in case of D=6 and d=4.
X = rand(3,5,6,6,5,6)
Y = X[:,:,:,i:j,:,:]
i and j are given values which are smaller than 6 in the above example.
You can use the built-in function selectdim
help?> selectdim
search: selectdim
selectdim(A, d::Integer, i)
Return a view of all the data of A where the index for dimension d equals i.
Equivalent to view(A,:,:,...,i,:,:,...) where i is in position d.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> A = [1 2 3 4; 5 6 7 8]
2×4 Matrix{Int64}:
1 2 3 4
5 6 7 8
julia> selectdim(A, 2, 3)
2-element view(::Matrix{Int64}, :, 3) with eltype Int64:
3
7
Which would be used something like:
julia> a = rand(10,10,10,10);
julia> selectedaxis = 5
5
julia> indices = 1:2
1:2
julia> selectdim(a,selectedaxis,indices)
Notice that in the documentation example, i is an integer, but you can use ranges of the form i:j as well.
If you need to just slice on a single axis, use the built in selectdim(A, dim, index), e.g., selectdim(X, 4, i:j).
If you need to slice more than one axis at a time, you can build the array that indexes the array by first creating an array of all Colons and then filling in the specified dimensions with the specified indices.
function selectdims(A, dims, indices)
indexer = repeat(Any[:], ndims(A))
for (dim, index) in zip(dims, indices)
indexer[dim] = index
end
return A[indexer...]
end
idx = ntuple( l -> l==d ? (i:j) : (:), D)
Y = X[idx...]

How do you access multi-dimension array by N array of index element-wise?

Suppose we have
A = [1 2; 3 4]
In numpy, the following syntax will produce
A[[1,2],[1,2]] = [1,4]
But, in julia, the following produce a permutation which output
A[[1,2],[1,2]] = [1 2; 3 4]
Is there a concise way to achieve the same thing as numpy without using for loops?
To get what you want I would use CartesianIndex like this:
julia> A[CartesianIndex.([(1,1), (2,2)])]
2-element Vector{Int64}:
1
4
or
julia> A[[CartesianIndex(1,1), CartesianIndex(2,2)]]
2-element Vector{Int64}:
1
4
Like Bogumil said, you probably want to use CartesianIndex. But if you want to get your result from supplying the vectors of indices for each dimensions, as in your Python [1,2],[1,2] example, you need to zip these indices first:
julia> A[CartesianIndex.(zip([1,2], [1,2]))]
2-element Vector{Int64}:
1
4
How does this work? zip traverses both vectors of indices at the same time (like a zipper) and returns an iterator over the tuples of indices:
julia> zip([1,2],[1,2]) # is a lazy iterator
zip([1, 2], [1, 2])
julia> collect(zip([1,2],[1,2])) # collect to show all the tuples
2-element Vector{Tuple{Int64, Int64}}:
(1, 1)
(2, 2)
and then CartesianIndex turns them into cartesian indices, which can then be used to get the corresponding values in A:
julia> CartesianIndex.(zip([1,2],[1,2]))
2-element Vector{CartesianIndex{2}}:
CartesianIndex(1, 1)
CartesianIndex(2, 2)

Julia using argmax to return index within a row of a matrix instead of a CartesianIndex

Say I have a matrix
X = [1 2 3 4; 1 4 3 2];
I would like to find the argmax of each row of this matrix, relative to that row and not the index of the entry within the entirety of X. Meaning that I want the output of argmax(X, dims = (2)) to be a vector,
[4, 2];
but the current output is an array of CartesianIndex
[CartesianIndex(1, 4), CartesianIndex(2, 2)];
Is there a way to specify this in the argmax function or to transform the output efficiently to my desired state?
You can use eachrow to iterate over rows of a matrix:
julia> argmax.(eachrow(X))
2-element Vector{Int64}:
4
2

Equivalent of pandas 'clip' in Julia

In pandas, there is the clip function (see https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.clip.html), which constrains values within the lower and upper bound provided by the user. What is the Julia equivalent? I.e., I would like to have:
> clip.([2 3 5 10],3,5)
> [3 3 5 5]
Obviously, I can write it myself, or use a combination of min and max, but I was surprised to find out there is none. StatsBase provides the trim and winsor functions, but these do not allow fixed values as input, but rather counts or percentiles (https://juliastats.github.io/StatsBase.jl/stable/robust.html).
You are probably looking for clamp:
help?> clamp
clamp(x, lo, hi)
Return x if lo <= x <= hi. If x > hi, return hi. If x < lo, return lo. Arguments are promoted to a common type.
This is a function for scalar x, but we can broadcast it over the vector using dot-notation:
julia> clamp.([2, 3, 5, 10], 3, 5)
4-element Array{Int64,1}:
3
3
5
5
If you don't care about the original array you can also use the in-place version clamp!, which modifies the input:
julia> A = [2, 3, 5, 10];
julia> clamp!(A, 3, 5);
julia> A
4-element Array{Int64,1}:
3
3
5
5

Is there outer map function in Julia?

I am trying to construct all possible combinations of four vectors (parameters in a model) that would give me a big nx4 matrix and I could then run simulation on each set (row) of parameters. In R I would achieve this by using expand.grid in Mathematica style, I could use something like outer product with vcat and reduce the output using hcat.
Is there some function analog of expand.grid from R or outer map function?
Toy example:
A = [1 2]
B = [3 4]
some magic
output = [1 3, 1 4, 2 3, 2 4]
Using the Iterators package, it might look like this:
using Iterators
for p in product([1,2], [3,4])
println(p)
end
where you would replace println with your algorithm. You can also use collect if it's important to get the set of all combinations.
Not the exact notation you show, but a comprehension might be useful.
julia> a=[1, 2];
julia> b=[3, 4];
julia> [[i, j] for j in b, i in a]
2x2 Array{Any,2}:
[1,3] [2,3]
[1,4] [2,4]
julia> [[i, j] for j in b, i in a][:]
4-element Array{Any,1}:
[1,3]
[1,4]
[2,3]
[2,4]

Resources