I would like to apply function with multiple arguments to a vector.
It seems that both map() and map!() can be helpful.
It works perfect if function has one argument:
f = function(a)
a+a
end
x=[1,2,3,4,5]
map(f, x)
output: [2, 4, 6, 8, 10]
However, it is not clear how to pass arguments to the function, if possible, and the vector to broadcast, if the function has multiple arguments.
f = function(a,b)
a*b
end
However, non of the following working:
b=3
map(f(a,b), x, 3)
map(f, x, 3)
map(f, a=x, b=3)
map(f(a,b), x, 3)
map(f(a,b), a=x,b=3)
Expected output:
[3,6,9,12,15]
Use broadcast - just as you suggested in the question:
julia> f = function(a,b)
a*b
end
#1 (generic function with 1 method)
julia> x=[1,2,3,4,5]
5-element Vector{Int64}:
1
2
3
4
5
julia> b=3
3
julia> f.(x, b)
5-element Vector{Int64}:
3
6
9
12
15
map does not broadcast, so if b is a scalar you would manually need to write:
julia> map(f, x, Iterators.repeated(b, length(x)))
5-element Vector{Int64}:
3
6
9
12
15
You can, however, pass two iterables to map without a problem:
julia> map(f, x, x)
5-element Vector{Int64}:
1
4
9
16
25
One possible solution is to create an anonymous function inside map as follows -->
x = [1, 2, 3, 4, 5]
b = 3
f = function(a, b)
a * b
end
map(x -> f(x, b), x)
which produces below output-->
5-element Vector{Int64}:
3
6
9
12
15
Explanation :- Anonymous function is taking values from vector as its first argument and 2nd argument is fixed with b = 3.
A few other options:
julia> map(Base.splat(func), Iterators.product(3, x))
5-element Vector{Int64}:
3
6
9
12
15
Iterators.product returns a list of tuples (3, 1), (3, 2), etc. Since our function func takes multiple separate arguments and not a tuple, we use Base.splat on it which takes the tuple and splats it into separate arguments to pass on to func.
julia> using SplitApplyCombine: product
julia> product(func, x, 3)
5-element Vector{Int64}:
3
6
9
12
15
SplitApplyCombine.jl's product function can directly map a given function over each combination (Cartesian product) of the given arguments.
julia> map(func, x, Iterators.cycle(3))
5-element Vector{Int64}:
3
6
9
12
15
A difference from the two previous ways is that if the shorter argument was a vector with more than one element in it, the previous methods would apply the function to each combination of elements from the two arguments, whereas this one would behave like Python's zip_longest, repeating the shorter vector until they were the same length (and then applying the function).
julia> y = [10, 1000];
julia> SplitApplyCombine.product(func, x, y) # previous method
5×2 Matrix{Int64}:
10 1000
20 2000
30 3000
40 4000
50 5000
julia> map(func, x, Iterators.cycle(y))
5-element Vector{Int64}:
10
2000
30
4000
50
Related
Trying to find the outer product of two matrices A and B
Here is what I have attempted:
function product(A, B)
n_a, m_a = size(A)
n_b, m_b = size(B)
AB = Array{Float64}(undef, n_a, m_b)
for i in 1:n_a
for j in 1:m_b
AB[i, j] = A[:, j] * B[j, :]'
end
end
return AB
end
product(A, B)
I get an error when attempting to run: Cannot `convert` an object of type Matrix{Float64} to an object of type Float64
I'm not exactly sure what you mean by "outer product of matrices", I'm only familiar with an outer product of vectors (which creates a matrix). Could you clarify what output you're looking for with an example?
In any event to address the immediate issue: The stacktrace is pointing to this line in your function:
AB[i, j] = A[:, j] * B[j, :]'
Let's take two example matrices and see what happens for i=j=1:
julia> x = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> y = [2 3; 4 5]
2×2 Matrix{Int64}:
2 3
4 5
julia> x[:, 1] * y[1, :]'
2×2 Matrix{Int64}:
2 3
6 9
so the way you are slicing and transposing your matrices means you are calculating an outer product (as I know it) of two vectors, which gives you a matrix. Given that AB is defined as a matrix of Float64s, the location AB[i, j] can only hold a Float64 value, but you are trying to assign a Matrix{Float64} to it.
Again I'm not sure what exactly you are trying to achieve here, but if it's just a "normal" matrix multiplication, you should have
AB[i, j] = A[i, :]' * B[:, j]
in your inner loop. Making that change gives me:
julia> product(x, y) == x * y
true
for the x and y defined above.
Based on the image you linked to in the comment, you're calculating an array of matrices. This can be done as follows:
AB = [A[:,j]*B[j,:]' for j=1:size(A,2)]
Though, I don't believe that's the correct definition for matrix outer product. I think it should be like this:
AB = [r*c' for r in eachrow(A), c in eachcol(B)]
This will give you a [n_a*m_b] matrix of [m_a*n_b] matrices.
From the linked image and the text, I think the formula tries to show another representation for the usual matrix product, which is useful, especially when doing rank decomposition of matrices (as sums of rank one matrices).
As a concrete example, first defining a couple of matrices:
julia> using Random
julia> Random.seed!(1234);
julia> A = rand(1:10,(2,3))
2×3 Matrix{Int64}:
4 3 4
6 9 4
julia> B = rand(1:10,(3,4))
3×4 Matrix{Int64}:
10 8 1 7
8 6 2 10
5 8 5 7
Now define a product as a sum of outer products of vectors, and see it gives the same result as a usual matrix product:
julia> product(A, B) = sum( [ A[:,i] * B[i,:]' for i=1:size(A,2) ] )
product (generic function with 1 method)
julia> product(A,B)
2×4 Matrix{Int64}:
84 82 30 86
152 134 44 160
julia> A*B
2×4 Matrix{Int64}:
84 82 30 86
152 134 44 160
In this example, the resulting matrix can be at most rank 3, the number of columns in A (and rows in B). In fact, it is rank 2 because of number of rows, but in general this product is done on tall times flat matrices and then the rank restriction is meaningful.
In R we can create an empty vector where it is possible to insert an element in any position of this vector.
Example:
> x <- c()
> x[1] = 10
> x[4] = 20
The final result is:
> x
[1] 10 NA NA 20
I would like to do something similar using Julia, but couldn't find a way to do this.
The “append” function do not perform something like that.
Could anyone help?
You need to do this in two steps:
First resize the vector or create a vector with an appropriate size.
Next set the elements accordingly.
Since you are coming from R I assume you want the vector to be initially filled with missing values. Here is the way to do this.
In my example I assume you want to store integers in the vector. Before both options load the Missings.jl package:
using Missings
Option 1. Start with an empty vector
julia> x = missings(Int, 0)
Union{Missing, Int64}[]
julia> resize!(x, 4)
4-element Vector{Union{Missing, Int64}}:
missing
missing
missing
missing
julia> x[1] = 10
10
julia> x[4] = 40
40
julia> x
4-element Vector{Union{Missing, Int64}}:
10
missing
missing
40
Option 2. Preallocate a vector
julia> x = missings(Int, 4)
4-element Vector{Union{Missing, Int64}}:
missing
missing
missing
missing
julia> x[1] = 10
10
julia> x[4] = 40
40
The reason why Julia does not resize the vectors automatically is for safety. Sometimes it would be useful, but most of the time if x is an empty vector and you write x[4] = 40 it is a bug in the code and Julia catches such cases.
EDIT
What you can do is:
function setvalue(vec::Vector, idx, val)
#assert idx > 0
if idx > length(vec)
resize!(vec, idx)
end
vec[idx] = val
return vec
end
I have an array x and I would like to repeat each entry of x a number of times specified by the corresponding entries of another array y, of the same length of x.
x = [1, 2, 3, 4, 5] # Array to be repeated
y = [3, 2, 1, 2, 3] # Repetitions for each element of x
# result should be [1, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5]
Is there a way to do this in Julia?
Your x and y vectors constitute what is called a run-length encoding of the vector [1, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5]. So if you take the inverse of the run-length encoding, you will get the vector you are looking for. The StatsBase.jl package contains the rle and inverse_rle functions. We can use inverse_rle like this:
julia> using StatsBase
julia> x = [1, 2, 3, 4, 5];
julia> y = [3, 2, 1, 2, 3];
julia> inverse_rle(x, y)
11-element Vector{Int64}:
1
1
1
2
2
3
4
4
5
5
5
You've given what I would have suggested as the answer already in your comment:
vcat(fill.(x, y)...)
How does this work? Start with fill:
help?> fill
fill(x, dims::Tuple)
fill(x, dims...)
Create an array filled with the value x. For example, fill(1.0, (5,5)) returns a 5×5 array of floats, with each element initialized to 1.0.
This is a bit more complicated than it needs to be for our case (where we only have one dimension to fill into), so let's look at a simple example:
julia> fill(1, 3)
3-element Vector{Int64}:
1
1
1
so fill(1, 3) just means "take the number one, and put this number into a one-dimensional array 3 times."
This of course is exactly what we want to do here: for every element in x, we want an array that holds this element multiple times, with the multiple given by the corresponding element in y. We could therefore loop over x and y and do something like:
julia> for (xᵢ, yᵢ) ∈ zip(x, y)
fill(xᵢ, yᵢ)
end
Now this loop doesn't return anything, so we'd have to preallocate some storage and assign to that within the loop. A more concise way of writing this while automatically returning an object would be a comprehension:
julia> [fill(xᵢ, yᵢ) for (xᵢ, yᵢ) ∈ zip(x, y)]
5-element Vector{Vector{Int64}}:
[1, 1, 1]
[2, 2]
[3]
[4, 4]
[5, 5, 5]
and even more concisely, we can just use broadcasting:
julia> fill.(x, y)
5-element Vector{Vector{Int64}}:
[1, 1, 1]
[2, 2]
[3]
[4, 4]
[5, 5, 5]
so from the comprehension or the broadcast we are getting a vector of vectors, each vector being an element of x repeated y times. Now all that remains is to put these together into a single vector by concatenating them vertically:
julia> vcat(fill.(x, y)...)
11-element Vector{Int64}:
1
1
1
2
2
3
4
4
5
5
5
Here we are using splatting to essentially do:
z = fill.(x, y)
vcat(z[1], z[2], z[3], z[4], z[5])
Note that splatting can have suboptimal performance for arrays of variable length, so a better way is to use reduce which is special cased for this and will give the same result:
reduce(vcat, fill.(x, y))
If performance is a priority, you can also do it the long, manual way:
function runlengthdecode(vals::Vector{T}, reps::Vector{<:Integer}) where T
length(vals) == length(reps) || throw(ArgumentError("Same number of values and counts expected"))
result = Vector{T}(undef, sum(reps))
resind = 1
for (valind, numrep) in enumerate(reps)
for i in 1:numrep
#inbounds result[resind] = vals[valind]
resind += 1
end
end
result
end
This runs about 12 times faster than the vcat/fill based method for the given data, likely because of avoiding creating all the intermediate filled vectors.
You can also instead use fill! on the preallocated result's #views, by replacing the loop in above code with:
for (val, numrep) in zip(vals, reps)
fill!(#view(result[resind:resind + numrep - 1]), val)
resind += numrep
end
which has comparable performance.
Also, for completeness, a comprehension can be quite handy for this. And it's faster than fill and vcat.
julia> [x[i] for i=1:length(x) for j=1:y[i]]
11-element Vector{Int64}:
1
1
1
2
2
3
4
4
5
5
5
I am trying to build credible bands in Julia, however, there is a technical procedure that I am not aware of how to do. The code is the following:
#Significance level 95%
alpha_sign=0.05
#Genrate random values
N_1 = 100
Fs_1 = Array{Float64}(undef, length(x), N_1);
x = 0.0:0.01:1.0
for k in 1:100
f = rand(postΠ)
Fs_1[:,k] = f.(x)
end
# sup|theta_i(t)-average|
dif_b=Array{Float64}(undef, length(x),N);
for k in 1:100
dif_b[:,k] = Fs_1[:,k]-average_across
end
#Defining a function that allows to compute the n smallest values
using Base.Sort
function smallestn(a, n)
sort(a; alg=Sort.PartialQuickSort(n))[1:n]
end
#Compute the maximum of the difference across time
sup_b=Array{Float64}(undef, N_1)
for k in 1:100
sup_b[k]=(maximum(abs.(dif_b[:,k] )))
end
#Build a matrix with the smallest distances
N_min=(1-alpha_sign)*N
using Base.Sort
min_sup_b=smallestn(sup_b,95)
To simplify the problem I am creating this example:
Imagine I have the matrix down there and I want to create a matrix with the values that are closest to the mean. I am able to compute the distances and store into a vector as displayed in the code above and later get the smallest values but I need to get back to the original matrix to extract those values.
X=[1,2,7,4,5]
av_X=mean(X,dims=1)
Question:
I am able to compute the distances and store them into a vector as displayed in the code above and later get the smallest values but I need to get back to the original matrix to extract those values.
How do I do that?
Thanks in advance!
using Statistics
arr = rand(1:20, (4, 4))
colmeans = [mean(col) for col in eachcol(arr)]
deltas = map(cart -> abs(arr[cart] - colmeans[first(Tuple(cart))]) => cart, CartesianIndices(arr))
sorteddeltas = sort(deltas, lt = (x, y) -> first(x) < first(y), dims=1)
sarr = zeros(Int, (4, 4))
for (i, d) in enumerate(sorteddeltas)
sarr[i] = arr[last(d)]
end
println(arr) # [7 1 2 15; 18 7 14 10; 3 11 10 13; 7 14 20 8]
println(colmeans) # [8.75, 8.25, 11.5, 11.5]
println(sarr) # [7 11 10 13; 7 7 14 10; 3 14 2 8; 18 1 20 15]
println(sarr') # [7 7 3 18; 11 7 14 1; 10 14 2 20; 13 10 8 15]
This should give you a sorted list of pairs of the distances from the mean of each column, with the second part of the pair the Cartesian coordinates of the original matrix.
sarr is the original matrix sorted column-major by closeness to the mean for each column.
I think the function you are looking for is findmin(). It gives both the minimum value and its index.
julia> x = randn(5)
5-element Vector{Float64}:
-0.025159738348978562
-0.24720173332739662
-0.32508319212563325
0.9470582053428686
1.1467087893336048
julia> findmin(x)
(-0.32508319212563325, 3)
If you want to do this for every column in a matrix, you can do something like:
julia> X = randn(3, 5)
3×5 Matrix{Float64}:
1.06405 1.03267 -0.826687 -1.68299 0.00319586
-0.129021 0.0615327 0.0756477 1.05258 0.525504
0.569748 -0.0877886 -1.48372 0.823895 0.319364
julia> min_inds = [findmin(X[:, i]) for i = 1:5]
5-element Vector{Tuple{Float64, Int64}}:
(-0.12902069012799203, 2)
(-0.08778864856976668, 3)
(-1.4837211369655696, 3)
(-1.6829919363620507, 1)
(0.003195860366775878, 1)
I have a 3-vector c = [0.7, 0.5, 0.2] and I want to multiply it with everything in an n-vector x = rand((-1,1),n) such that I get a resulting n+2-vector y where y[i] == x[i]*c[3] + x[i-1]*c[2] + x[i-2]*c[1]
How should I do this in julia? I feel like there should be a way to broadcast the smaller 3 vector to all the values in the n vector. And for the edge cases, if i-1 or i-2 is out of bounds I just want zero for those components.
If I understand your question correctly you want a convolution, with a twist that in a standard convolution the vector c would be reversed. You can use e.g. DSP.jl for this.
Is this what you want?
julia> using DSP
julia> c = [0.7, 0.5, 0.2]
3-element Array{Float64,1}:
0.7
0.5
0.2
julia> conv([10, 100, 1000, 10000], reverse(c))
6-element Array{Float64,1}:
1.9999999999996967
25.0
257.0000000000003
2569.9999999999995
5700.0
6999.999999999998
You can also manually implement it using dot from the LinearAlgebra module like this:
julia> using LinearAlgebra
julia> x = [10, 100, 1000, 10000]
4-element Array{Int64,1}:
10
100
1000
10000
julia> y = [0;0;x;0;0]
8-element Array{Int64,1}:
0
0
10
100
1000
10000
0
0
julia> [dot(#view(y[i:i+2]), c) for i in 1:length(x)+2]
6-element Array{Float64,1}:
2.0
25.0
257.0
2570.0
5700.0
7000.0
Here's one approach that uses ShiftedArrays.jl.
using ShiftedArrays
c = [0.7, 0.5, 0.2]
Create lagged versions of x, with initial zeros:
x = 1:5
xminus1 = lag(x, 1, default=0)
xminus2 = lag(x, 2, default=0)
Horizontally concatenate the vectors and use matrix multiplication with c:
X = [xminus2 xminus1 x]
X * c
Here's what X and X * c look like at the REPL:
julia> X = [xminus2 xminus1 x]
5×3 Array{Int64,2}:
0 0 1
0 1 2
1 2 3
2 3 4
3 4 5
julia> X * c
5-element Array{Float64,1}:
0.2
0.9
2.3
3.7
5.1
Note that this produces an output vector of length length(x), not length(x) + 2. I'm not sure how it would make sense for the output to be of length length(x) + 2, as you requested in the question.
I have a package for doing such things. The simplest use is like this:
julia> c = [0.7, 0.5, 0.2]; # from question
julia> x = [10, 100, 1000, 10_000]; # from another answer
julia> using Tullio, OffsetArrays
julia> #tullio y[i] := x[i]*c[3] + x[i-1]*c[2] + x[i-2]*c[1]
2-element OffsetArray(::Vector{Float64}, 3:4) with eltype Float64 with indices 3:4:
257.0
2570.0
julia> #tullio y[i] := x[i+k-3] * c[k] # sum over all k, range of i that's safe
2-element OffsetArray(::Array{Float64,1}, 3:4) with eltype Float64 with indices 3:4:
257.0
2570.0
Since eachindex(c) == 1:3, that's the range of k-values which this sums over, and the range of i is as big as it can be so that i+k-3 stays inside eachindex(x) == 1:4.
To extend the range of i by padding x with two zeros in each direction, write pad(i+k-3, 2). And to compute the shift of i needed to produce an ordinary 1-based Array, write i+_ on the left (and then the -3 makes no difference). Then:
julia> #tullio y[i+_] := x[pad(i+k, 2)] * c[k]
6-element Array{Float64,1}:
2.0
25.0
257.0
2570.0
5700.0
7000.0
On larger arrays, this won't be very fast (at the moment) as it must check at every step whether it is inside x or out in the padding. It's very likely that DSP.conv is a bit smarter about this. (Edit -- DSP.jl seems never to be faster for this c; with a kernel of length 1000 it's faster with 10^6 elements in x.)