Use for loop to get i:i+1 columns - arrays

I want to use for loop so I can get the result for i:i+1 columns at each iteration. E.g: when i= 1, I get 1st & 2nd cols, i= 2 , 3rd and 4th cols.
m= [2 -3;4 6]
al= [1 3;-2 -4]
l=[1 0; 2 4]
Random.seed!(1234)
d= [rand(2:20, 10) rand(-1:10, 10)]
Random.seed!(1234)
c= [rand(0:30, 10) rand(-1:20, 10)]
n,g=size(w)
mx=zeros(n,2*g)
for i =1:g
mx[ : ,i:i+1] = m[:,i]' .+ (d[:,i]' .* al[:,i])' .+ (l[:,i]' .* c[:,i])
end
return mx
I got the following which is wrong when I compared it with doing the process manually
julia> mx
10×4 Array{Float64,2}:
8.0 -6.0 10.0 0.0
22.0 3.0 18.0 0.0
40.0 18.0 38.0 0.0
9.0 9.0 22.0 0.0
51.0 3.0 18.0 0.0
10.0 18.0 34.0 0.0
52.0 12.0 30.0 0.0
36.0 21.0 42.0 0.0
44.0 24.0 42.0 0.0
33.0 24.0 42.0 0.0
The first 2 cols and last 2 cols in mx should be matched the results here with same order
mx1_2=m[:,1]' .+ (d[:,1]' .* al[:,1])' .+ (l[:,1]' .* c[:,1])
mx2_4=m[:,2]' .+ (d[:,2]' .* al[:,2])' .+ (l[:,2]' .* c[:,2])

Related

Place a small array into a big array

I have 2 arrays; one is small array and second is big array as follows,
import pandas as pd
import numpy as np
dat1 = np.array([2, 3 ,4 ,4 ,3 ,2, 2, 4 ,3 ,4 ,4, 3])
dat2 = np.array([1, 4 ,4, 4, 2 ,1, 3 ,3 ,2, 3, 3, 1])
small_array = pd.crosstab(dat1, dat2)
big_array = pd.DataFrame(np.zeros(6*6).reshape(6,6), columns=[1,3,4,2,6,5], index=[3,4,1,2,5,6])
Now I want to place small_array into big_array matching the rownames and colnames between both arrays.
Is there any easy way to perform this?
Any pointer will be very helpful
You can update big_array in-place:
big_array.update(small_array)
print(big_array)
If you want to create a new DataFrame, you can use combine_first:
out = small_array.combine_first(big_array)
Output:
1 3 4 2 6 5
3 1.0 0.0 1.0 2.0 0.0 0.0
4 0.0 3.0 2.0 0.0 0.0 0.0
1 0.0 0.0 0.0 0.0 0.0 0.0
2 2.0 1.0 0.0 0.0 0.0 0.0
5 0.0 0.0 0.0 0.0 0.0 0.0
6 0.0 0.0 0.0 0.0 0.0 0.0
Let us try reindex_like
out = small_array.reindex_like(big_array).fillna(0)
Out[494]:
1 3 4 2 6 5
3 1.0 0.0 1.0 2.0 0.0 0.0
4 0.0 3.0 2.0 0.0 0.0 0.0
1 0.0 0.0 0.0 0.0 0.0 0.0
2 2.0 1.0 0.0 0.0 0.0 0.0
5 0.0 0.0 0.0 0.0 0.0 0.0
6 0.0 0.0 0.0 0.0 0.0 0.0

Broadcasting over different sized arrays

Say I have the following function
function foo(p :: Int, x :: Real)
return p*x
end
And I want to call it for the following arrays:
P = [1, 2, 3]
X = [5.0, 6.0, 7.0, 8.0]
If I want to call foo and store the value in a single array of size (length(P), length(X)) I could just double loop X and P as:
R = zeros(length(P), length(X))
for i in 1:length(P), j in 1:length(X)
R[i, j] = foo(P[i], X[j])
end
However, is there another way to do this while explicitly avoiding the double loop?
Maybe something like?
R = foo.(collect(zip(P, X)))
Of course, the above does not work as foo cannot handle ::Tuple{Int64, Float64}, but I have not found a way to broadcast over different sized arrays for the moment. Any tips would be appreciated, thanks!
If you want to use broadcasting you can do it like this:
julia> foo.(P, permutedims(X))
3×4 Matrix{Float64}:
5.0 6.0 7.0 8.0
10.0 12.0 14.0 16.0
15.0 18.0 21.0 24.0
or
julia> foo.(P, reshape(X, 1, :))
3×4 Matrix{Float64}:
5.0 6.0 7.0 8.0
10.0 12.0 14.0 16.0
15.0 18.0 21.0 24.0
or
julia> (((x, y),) -> foo(x, y)).(Iterators.product(P, X))
3×4 Matrix{Float64}:
5.0 6.0 7.0 8.0
10.0 12.0 14.0 16.0
15.0 18.0 21.0 24.0
or
julia> Base.splat(foo).(Iterators.product(P, X))
3×4 Matrix{Float64}:
5.0 6.0 7.0 8.0
10.0 12.0 14.0 16.0
15.0 18.0 21.0 24.0
Note that adjoint (') will not work here in general, as it is recursive:
julia> x = ["a", "b"]
2-element Vector{String}:
"a"
"b"
julia> permutedims(x)
1×2 Matrix{String}:
"a" "b"
julia> x'
1×2 adjoint(::Vector{String}) with eltype Union{}:
Error showing value of type LinearAlgebra.Adjoint{Union{}, Vector{String}}:
ERROR: MethodError: no method matching adjoint(::String)

julia arrays select the first x rows by group

Using julia, I want to select the first x rows of an array per group.
In the following example, I want the first two rows where the second column is equal to 1.0, then the first two rows where the second column is equal to 2.0, etc.
XX = [repeat([1.0], 6) vcat(repeat([1.0], 3), repeat([2.0], 3))]
XX2 = [repeat([2.0], 6) vcat(repeat([3.0], 3), repeat([4.0], 3))]
beg = [XX;XX2]
> 12×2 Matrix{Float64}:
> 1.0 1.0
> 1.0 1.0
> 1.0 1.0
> 1.0 2.0
> 1.0 2.0
> 1.0 2.0
> 2.0 3.0
> 2.0 3.0
> 2.0 3.0
> 2.0 4.0
> 2.0 4.0
> 2.0 4.0
The final array would look like this:
8×2 Matrix{Float64}:
1.0 1.0
1.0 1.0
1.0 2.0
1.0 2.0
2.0 3.0
2.0 3.0
2.0 4.0
2.0 4.0
I use the following code, but I am not sure whether there is a simpler way (one function) that does already that in a more efficient way?
x = []
for val in unique(beg[:,2])
x = append!(x, findfirst(beg[:,2].==val))
end
idx = sort([x; x.+1])
final = beg[idx, :]
Assuming your data:
is sorted (i.e. groups are forming continuous blocks)
each group is guaranteed to have at least two elements
(your code assumes both)
then you can generate idx filter that you want in the following way:
idx == [i for i in axes(beg, 1) if i < 3 || beg[i, 2] != beg[i-1, 2] || beg[i, 2] != beg[i-2, 2]]
If you cannot assume either of the above please comment and I can show a more general solution.
EDIT
Here is an example without using any external packages:
julia> using Random
julia> XX = [repeat([1.0], 6) vcat(repeat([1.0], 3), repeat([2.0], 3))]
6×2 Matrix{Float64}:
1.0 1.0
1.0 1.0
1.0 1.0
1.0 2.0
1.0 2.0
1.0 2.0
julia> XX2 = [repeat([2.0], 7) vcat(repeat([3.0], 3), repeat([4.0], 3), 5.0)] # last group has length 1
7×2 Matrix{Float64}:
2.0 3.0
2.0 3.0
2.0 3.0
2.0 4.0
2.0 4.0
2.0 4.0
2.0 5.0
julia> beg = [XX;XX2][randperm(13), :] # shuffle groups so they are not in order
13×2 Matrix{Float64}:
2.0 3.0
1.0 2.0
2.0 4.0
2.0 3.0
2.0 4.0
2.0 5.0
2.0 3.0
1.0 2.0
1.0 2.0
1.0 1.0
1.0 1.0
2.0 4.0
1.0 1.0
julia> x = Dict{Float64, Vector{Int}}() # this will store indices per group
Dict{Float64, Vector{Int64}}()
julia> for (i, v) in enumerate(beg[:, 2]) # collect the indices
push!(get!(x, v, Int[]), i)
end
julia> x
Dict{Float64, Vector{Int64}} with 5 entries:
5.0 => [6]
4.0 => [3, 5, 12]
2.0 => [2, 8, 9]
3.0 => [1, 4, 7]
1.0 => [10, 11, 13]
julia> idx = sort!(mapreduce(x -> first(x, 2), vcat, values(x))) # get first two indices per group in ascending order
9-element Vector{Int64}:
1
2
3
4
5
6
8
10
11

convert Array to indicator matrix

Given the y Array, is there a cleaner or more idiomatic way to create a 2D Array such as Y?
y = [1.0 2.0 3.0 4.0 1.0 2.0]'
Y = ifelse(y .== 1, 1.0, 0.0)
for j in 2:length(unique(y))
Y = hcat(Y, ifelse(y .== j, 1.0, 0.0) )
end
julia> Y
6x4 Array{Float64,2}:
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
One alternative approach is to use broadcast:
julia> broadcast(.==, y, (1:4)')
6x4 Array{Float64,2}:
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
(.== broadcasts automatically, so if you just wanted a BitArray you could write y .== (1:4)'.)
This avoids the explicit for loop and also the use of hcat to build the array. However, depending on the size of the array you're looking to create, it might be most efficient to allocate an array of zeros of the appropriate shape and then use indexing to add the ones to the appropriate column on each row.
Array comprehension is an idiomatic and fast way to create matrices in Julia. For the example in the question:
y = convert(Vector{Int64},vec(y)) # make sure indices are integer
Y = [j==y[i] ? 1.0 : 0.0 for i=1:length(y),j=1:length(unique(y))]
What was probably intended was:
Y = [j==y[i] ? 1.0 : 0.0 for i=1:length(y),j=1:maximum(y)]
In both cases Y is:
6x4 Array{Float64,2}:
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
In numerical analysis, a sparse matrix is a matrix in which most of
the elements are zero.
And from Julia Doc:
sparse(I,J,V,[m,n,combine])
Create a sparse matrix S of dimensions m x n such that S[I[k], J[k]] =
V[k]. The combine function is used to combine duplicates. If m and n
are not specified, they are set to max(I) and max(J) respectively. If
the combine function is not supplied, duplicates are added by default.
y = [1, 2, 3, 4, 1, 2]
rows=length(y);
clms=4 # must be >= maximum(y);
s=sparse(1:rows,y,ones(rows),rows,clms);
full(s) # =>
6x4 Array{Float64,2}:
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0

Multiple assignment in multidimensional array

I have a 4x4 array of zeros.
julia> X = zeros(4,4)
4x4 Array{Float64,2}:
0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0
I have an 2xN array containing indices of elements in X that I want to assign a new value.
julia> ind = [1 1; 2 2; 3 3]
3x2 Array{Int64,2}:
1 1
2 2
3 3
What is the simplest way to assign a value to all elements in X whose indices are rows in ind? (something like X[ind] = 2.0).
julia> X
2.0 0.0 0.0 0.0
0.0 2.0 0.0 0.0
0.0 0.0 2.0 0.0
0.0 0.0 0.0 0.0
I'm not sure there is a non-looping way to do this. What's wrong with this?
for i=[1:size(ind)[1]]
a, b = ind[i, :]
X[a, b] = 2.0
end
user3467349's answer is correct, but inefficient, because it allocates an Array for the indices. Also, the notation [a:b] is deprecated as of Julia 0.4. Instead, you can use:
for i = 1:size(ind, 1)
a, b = ind[i, :]
X[a, b] = 2.0
end

Resources