Slice matrix every 2 columns - arrays

I am trying to figure out how to slice a matrix every 2 columns. For example, if we have
A=[[1 2 3 4 5 6];[7 8 9 10 11 12]]
2×6 Matrix{Int64}:
1 2 3 4 5 6
7 8 9 10 11 12
then I would like to return 3 matrices sliced every 2 columns, i.e. a 3 dimensional array with 3 matrices,
2×2×3 Array{Int64, 3}:
[:, :, 1] =
1 2
7 8
[:, :, 2] =
3 4
9 10
[:, :, 3] =
5 6
11 12
One thing I have tried is the eachslice function,
collect(eachslice(A,dims=2))
6-element Vector{SubArray{Int64, 1, Matrix{Int64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true}}:
[1, 7]
[2, 8]
[3, 9]
[4, 10]
[5, 11]
[6, 12]
but this slices along every column, but I want to slice along every two columns!
Thanks in advance.

That's just a reshape. Reshapes share memory (like views), so you should copy it if you want it to be independent of the original A:
julia> reshape(A, 2, 2, 3)
2×2×3 Array{Int64, 3}:
[:, :, 1] =
1 2
7 8
[:, :, 2] =
3 4
9 10
[:, :, 3] =
5 6
11 12
But if you really want, you can express it as indexing, too:
julia> A[:, [1:2 3:4 5:6]]
2×2×3 Array{Int64, 3}:
[:, :, 1] =
1 2
7 8
[:, :, 2] =
3 4
9 10
[:, :, 3] =
5 6
11 12

Related

Julia - Reshaping a 4D array into a matrix of matrices

I want to start from an array like
A = zeros( nK , nK , m , m )
and reshape it into an matrix of size (nK,nK) where each element is an mxm matrix.
I have tried the basis reshape function, reshape(A , nK , nK ), but it gives me
DimensionMismatch("new dimensions (nK, nK) must be consistent with array size mxmxnKxnK")
On Julia 1.9, you want eachslice:
julia> x = rand(Int8,3,3,2,2)
3×3×2×2 Array{Int8, 4}:
[:, :, 1, 1] =
127 107 27
31 -90 95
-50 -92 117
...
julia> eachslice(x; dims=(3,4))
2×2 Slices{Array{Int8, 4}, Tuple{Colon, Colon, Int64, Int64}, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}, SubArray{Int8, 2, Array{Int8, 4}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64, Int64}, true}, 2}:
[127 107 27; 31 -90 95; -50 -92 117] [-58 7 -16; -77 -110 32; -82 25 -48]
[-40 13 -43; -63 121 47; 28 -64 57] [62 -61 19; 117 42 101; 70 -82 -62]
julia> eachslice(x; dims=(1,2))
3×3 Slices{Array{Int8, 4}, Tuple{Int64, Int64, Colon, Colon}, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}, SubArray{Int8, 2, Array{Int8, 4}, Tuple{Int64, Int64, Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}}, true}, 2}:
[127 -58; -40 62] [107 7; 13 -61] [27 -16; -43 19]
[31 -77; -63 117] [-90 -110; 121 42] [95 32; 47 101]
[-50 -82; 28 70] [-92 25; -64 -82] [117 -48; 57 -62]
As noted above, usually it's best to use slices containing the leading dimensions, like x[:,:,i,j] produced by eachslice(x; dims=(3,4)).
On Julia 1.8 & lower, ideally Compat.jl#663 will make this work.
If I understand your problem correctly, I think you can do it this:
julia> x = rand(1:10, 2, 4, 3, 3)
2×4×3×3 Array{Int64, 4}:
[:, :, 1, 1] =
9 5 4 1
2 2 2 10
[:, :, 2, 1] =
8 1 4 9
9 5 5 8
...
julia> # With copy:
julia> [x[i, j, :, :] for i in axes(x, 1), j in axes(x, 2)]
2×4 Matrix{Matrix{Int64}}:
[9 5 4; 8 2 6; 5 7 5] [5 8 5; 1 6 1; 1 5 5] [4 10 4; 4 3 10; 4 7 10] [1 10 5; 9 2 5; 7 1 10]
[2 7 1; 9 5 3; 7 1 7] [2 3 9; 5 7 10; 4 1 4] [2 1 2; 5 1 1; 1 2 4] [10 1 3; 8 3 8; 9 10 2]
julia> # With views:
julia> [view(x, i, j, :, :) for i in axes(x, 1), j in axes(x, 2)]
2×4 Matrix{SubArray{Int64, 2, Array{Int64, 4}, Tuple{Int64, Int64, Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}}, true}}:
[9 5 4; 8 2 6; 5 7 5] [5 8 5; 1 6 1; 1 5 5] [4 10 4; 4 3 10; 4 7 10] [1 10 5; 9 2 5; 7 1 10]
[2 7 1; 9 5 3; 7 1 7] [2 3 9; 5 7 10; 4 1 4] [2 1 2; 5 1 1; 1 2 4] [10 1 3; 8 3 8; 9 10 2]
I hope it helps you.

How can I add 1 in the beginning of a numpy array?

I have a numpy array X = [[3 4 5 6] [6 5 3 3] [9 8 5 2]]
I would like to add 1 in each array like so:
X = [[1 3 4 5 6] [1 6 5 3 3] [1 9 8 5 2]]
I wanted to do it using np.ones() and np.hstack()
This is what I tried to do
X = [[3 4 5 6] [6 5 3 3] [9 8 5 2]]
ones = np.ones(len(X))
X = np.hstack((ones, X))

Julia, #view to prevent production of a new array

My old friend the 3d array called Pop, I want to remove columns (d2), across all of d3 when the value in the end of d1 == 1, so I have this code:
Pop[end, :, 1] .!=1
I thought adding #view in front of this would write the changes back to Pop, outwith producing an additional copy in memory. This code works fine
#view(Pop[ :, Pop[end, :, 1] .!=1, :])
but it does not alter the original 3d array called Pop. I could do
Pop = #view(Pop[ :, Pop[end, :, 1] .!=1, :])
but I believe this will create another copy in memory which I'm trying to avoid. What simple syntax have I missed? Thx. J
#view does not modify the size of the original array, it provides a "view" into it, (e.g., omitting some columns in your case). I don't think there is anything wrong with
Pop = view(Pop, :, Pop[end, :, 1] .≠ 1, :)
since now Pop is a view into your old, full Pop, but it behaves like an array, so you can modify its entries, e.g., you could then do things like
julia> using Random # using a fixed seed for reproducibility
julia> Random.seed!(0) ;
julia> Pop = rand(1:5, (2,4,2)) # original Pop
2×4×2 Array{Int64,3}:
[:, :, 1] =
4 3 5 5
1 1 3 5
[:, :, 2] =
2 2 3 1
2 5 1 1
julia> Pop[end,:,1] .≠ 1 # columns to keep
4-element BitArray{1}:
0
0
1
1
julia> Pop = view(Pop, :, Pop[end, :, 1] .≠ 1, :) # make it a view
2×2×2 view(::Array{Int64,3}, :, [3, 4], :) with eltype Int64:
[:, :, 1] =
5 5
3 5
[:, :, 2] =
3 1
1 1
julia> Pop[end,:,1] .= 1 ; # use your new view to manipulate data
julia> Pop # view of the modified Pop
2×2×2 view(::Array{Int64,3}, :, [3, 4], :) with eltype Int64:
[:, :, 1] =
5 5
1 1
[:, :, 2] =
3 1
1 1
julia> Pop.parent # original full Pop (now Pop.parent) has been modified
2×4×2 Array{Int64,3}:
[:, :, 1] =
4 3 5 5
1 1 1 1
[:, :, 2] =
2 2 3 1
2 5 1 1

how to convert from Array{Array{Int64,2},1} to Array{Int64,2}

In Julia, I want to convert data defined as Vector of 2D array to a 2D array of Matrix.
As described in the following example, I want to convert data s into data t, but I have not been successful so far.
How should I deal with the case?
julia> s = [[1 2 3], [4 5 6], [7 8 9]]
3-element Array{Array{Int64,2},1}:
[1 2 3]
[4 5 6]
[7 8 9]
julia> t = [[1 2 3]; [4 5 6]; [7 8 9]]
3××3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> s |> typeof
Array{Array{Int64,2},1}
julia> t |> typeof
Array{Int64,2}
julia> convert(Array{Int64, 2}, s)
ERROR: MethodError: Cannot `convert` an object of type Array{Array{Int64,2},1} to an object of type Array{Int64,2}
This may have arisen from a call to the constructor Array{Int64,2}(...),
since type constructors fall back to convert methods.
julia> reshape(s, 3, 3)
ERROR: DimensionMismatch("new dimensions (3,3) must be consistent with array size 3")
in reshape(::Array{Array{Int64,2},1}, ::Tuple{Int64,Int64}) at .\array.jl:113
in reshape(::Array{Array{Int64,2},1}, ::Int64, ::Int64, ::Vararg{Int64,N}) at .\reshapedarray.jl:39
As in the following example, if you define 2D array or 1D array as source data, I can then reshape them successfully into a 2D array of Matrix.
julia> u = [1 2 3 4 5 6 7 8 9]
1××9 Array{Int64,2}:
1 2 3 4 5 6 7 8 9
julia> u |> typeof
Array{Int64,2}
julia> reshape(u, 3, 3)
3××3 Array{Int64,2}:
1 4 7
2 5 8
3 6 9
julia> v = [1, 2, 3, 4, 5, 6, 7, 8, 9]
9-element Array{Int64,1}:
1
2
3
4
5
6
7
8
9
julia> v |> typeof
Array{Int64,1}
julia> reshape(v, 3, 3)
3××3 Array{Int64,2}:
1 4 7
2 5 8
3 6 9
You can use vcat and splatting
julia> t = vcat(s...)
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9

numpy array representation and formatting

I am working with some documentation and wish to portray an array of this form
>>> a_3d
array([[[4, 6, 4],
[1, 1, 8],
[0, 7, 5],
[5, 3, 3],
[8, 9, 5]],
[[8, 8, 4],
[3, 4, 4],
[0, 0, 9],
[3, 7, 3],
[3, 4, 7]],
[[9, 5, 4],
[7, 7, 3],
[9, 5, 9],
[8, 7, 8],
[5, 8, 8]]], dtype=int32)
as text in a similar fashion as I can do it using MatPlotLib as a graph/map.
I have managed to simply decompress the original array and provide some additional information into this form.
array...
shape (3, 5, 3) ndim 3 size 45
a[0]...
[[[4 6 4]
[1 1 8]
[0 7 5]
[5 3 3]
[8 9 5]]
a[1]....
[[8 8 4]
[3 4 4]
[0 0 9]
[3 7 3]
[3 4 7]]
a[2]....
[[9 5 4]
[7 7 3]
[9 5 9]
[8 7 8]
[5 8 8]]]
But I have tried every combination of reshaping, transposing to get it into a row representation. I haven't found a soution, short of reconstructing the array from first principles so that the three 2D blocks appear in one row.
Again, this is for teaching and visualization purposes and not for analysis. If I have overlooked the obvious, I would appreciate any comments.
EDIT
[[[4, 6, 4], [[8, 8, 4], [[9, 5, 4],
[1, 1, 8],
[0, 7, 5], etc etc
[5, 3, 3],
[8, 9, 5]], [3, 4, 7]], [5, 8, 8]]]
or similar... if this helps
apparently the kludge workaround I am using might help, it would be nice to work with the original data and restructure it, rather than to have to say...we will flip out to using lists and object arrays for awhile...
def to_row(a):
""" kludge workaround """
n, rows, cols = a.shape
e = np.empty((rows, cols), dtype='object')
for r in range(rows):
for c in range(cols):
e[r][c] = (a[c][r]).tolist()
return e
So you have an array with shape (3,5,3), and the default array function displays it has 3 planes, each a (5,3) 2d array.
Reshaping and transposing does not change this basic display format - it still splits the array on the 1st axis, and formats each block.
The formatting is handled by a builtin numpy function:
In [112]: arr=np.arange(2*3*4).reshape(2,3,4)
In [113]: arr.__format__('')
Out[113]: '[[[ 0 1 2 3]\n [ 4 5 6 7]\n [ 8 9 10 11]]\n\n [[12 13 14 15]\n [16 17 18 19]\n [20 21 22 23]]]'
np.array2string(arr) produces the same string.
Conceivably you could split this string on \n, and rearrange the pieces.
In [116]: np.get_printoptions()
Out[116]:
{'edgeitems': 3,
'formatter': None,
'infstr': 'inf',
'linewidth': 75,
'nanstr': 'nan',
'precision': 8,
'suppress': False,
'threshold': 1000}
the set_options function's doc describes these values. You might also look at np.set_string_function
Here's a first stab at rearranging the lines:
In [137]: astr=np.array2string(arr)
In [138]: lines=astr.splitlines()
In [139]: lines
Out[139]:
['[[[ 0 1 2 3]',
' [ 4 5 6 7]',
' [ 8 9 10 11]]',
'',
' [[12 13 14 15]',
' [16 17 18 19]',
' [20 21 22 23]]]']
In [140]: print '\n'.join([' '.join((lines[i],lines[i+4])) for i in range(3)])
[[[ 0 1 2 3] [[12 13 14 15]
[ 4 5 6 7] [16 17 18 19]
[ 8 9 10 11]] [20 21 22 23]]]
Brackets need to be cleaned up, but overall the shape looks right.
Another way to get such a set of lines is to format each plane:
In [151]: alist=[np.array2string(i).splitlines() for i in arr]
In [152]: alist
Out[152]:
[['[[ 0 1 2 3]', ' [ 4 5 6 7]', ' [ 8 9 10 11]]'],
['[[12 13 14 15]', ' [16 17 18 19]', ' [20 21 22 23]]']]
In [153]: zip(*alist) # a list form of transpose
Out[153]:
[('[[ 0 1 2 3]', '[[12 13 14 15]'),
(' [ 4 5 6 7]', ' [16 17 18 19]'),
(' [ 8 9 10 11]]', ' [20 21 22 23]]')]
which then can be joined. \t (tab) cleans up the bracket spacing.
In [155]: '\n'.join(['\t'.join(k) for k in zip(*alist)])
Out[155]: '[[ 0 1 2 3]\t[[12 13 14 15]\n [ 4 5 6 7]\t [16 17 18 19]\n [ 8 9 10 11]]\t [20 21 22 23]]'
In [156]: print _
[[ 0 1 2 3] [[12 13 14 15]
[ 4 5 6 7] [16 17 18 19]
[ 8 9 10 11]] [20 21 22 23]]
for 3 blocks - it still needs work :(
In [157]: arr1=np.arange(2*3*4).reshape(3,4,2)
In [158]: alist=[np.array2string(i).splitlines() for i in arr1]
In [159]: print '\n'.join(['\t'.join(k) for k in zip(*alist)])
[[0 1] [[ 8 9] [[16 17]
[2 3] [10 11] [18 19]
[4 5] [12 13] [20 21]
[6 7]] [14 15]] [22 23]]
In a sense it's the same problem you have with text when you want to display it in columns. May be there's a multi-column print utility.
Even though you are thinking in terms of blocks side by side, the display is still based on lines.

Resources