Multi-dimensional arrays
In fact, Julia views all arrays as a single stream of values and applies size and reshape parameters to compute the appropriate indexing.
Arrays with the number of dimensions greater than 2 (that is, array > 2
) can be defined in a straightforward method:
julia>
A = rand(4,4,4)
4x4x4 Array{Float64,3}:
[:, :, 1] =
0.522564 0.852847 0.452363 0.444234
0.992522 0.450827 0.885484 0.0693068
0.378972 0.365945 0.757072 0.807745
0.383636 0.383711 0.304271 0.389717
[:, :, 2] =
0.570806 0.912306 0.358262 0.494621
0.810382 0.235757 0.926146 0.915814
0.634989 0.196174 0.773742 0.158593
0.700649 0.843975 0.321075 0.306428
[:, :, 3] =
0.638391 0.606747 0.15706 0.241825
0.492206 0.798426 0.86354 0.715799
0.971428 0.200663 0.00568161 0.0868379
0.936388 0.183021 0.0476718 0.917008
[:, :, 4] =
0.252962 0.432026 0.817504 0.274034
0.164883 0.209135 0.925754 0.876917
0.125772 0.998318 0.593097 0.614772
0.865795 0.204839 0.315774 0.520044
Note the use of slice ':'
notation to display the 3D matrix; values are ordered by the third index, then the second, and finally the first.
It is possible to convert this 3D array into a standard matrix containing the same number of values, as follows:
julia>
B = reshape(A,8,8)
8x8 Array{Float64,2}:
0.522564 0.452363 0.570806 ... 0.15706 0.252962 0.817504
0.992522 0.885484 0.810382 ... 0.86354 0.164883 0.925754
0.378972 0.757072 0.634989 ... 0.005681 0.125772 0.593097
0.383636 0.304271 0.700649 ... 0.0476718 0.865795 0.31577
0.852847 0.444234 0.912306 ... 0.241825 0.432026 0.274034
0.450827 0.0693068 0.235757 ... 0.715799 0.209135 0.876917
0.365945 0.807745 0.196174 ... 0.086838 0.998318 0.614772
0.383711 0.389717 0.843975 ... 0.917008 0.204839 0.520044
Or, it could appear as a simple vector, like this:
julia>
C = reshape(A,64); typeof(C); # => Array{Float64,1}julia>
transpose(C) 1x64 LinearAlgebra.Transpose{Float64,Array{Float64,1}}: 0.522564 0.992522 0.378972 0.383636 ... 0.876917 0.614772 0.520044
Sparse matrices
Normal matrices are sometimes referred to as “dense,” which means that there is an entry for cell [i,j]. In cases where most cell values are, say, 0, this is inefficient, and it is better to implement a scheme of tuples (i,j,x), where x is the value referenced by i and J.
These are termed sparse matrices, and we can create a sparse matrix by executing the following code:
using SparseArrays S1 = SparseArrays.sparse(I, J, X[, m, n, combine])
S1
will have dimensions m by n and S[I[k], J[k]] = X[k].
If m and n are not given, they default to max(I
) and max(J)
respectively. The combine()
function is used to combine duplicates, and if not provided, duplicates are added by default.
Sparse matrices support much of the same set of operations as dense matrices, but there are a few special functions that can be applied. For example, spzeros()
is a counterpart of zeros()
, and random number arrays can be generated by sprand()
and sprandn()
:
# The 0.3 means only 30% for the numbers generated will be non-zero # This will produce different arrays each time it is runjulia>
A = sprand(5,5,0.3) ⋅ ⋅ ⋅ ⋅ 0.16395 0.21055 ⋅ 0.544431 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 0.76612 ⋅ ⋅ 0.785714 0.993288 ⋅ 0.740757 0.209118 ⋅ ⋅ # So squaring the matrix produces another sparse matrixjulia>
A * A 5×5 SparseMatrixCSC{Float64,Int64} with 10 stored entries: ⋅ 0.121447 0.034285 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 0.0345197 ⋅ ⋅ ⋅ ⋅ ⋅ 0.601951 0.735785 0.207715 0.617346 0.906046 0.155966 ⋅ 0.403291 ⋅ ⋅
Using Matrix()
converts the sparse matrix to a dense one, as follows:
julia>
convert(Matrix,A);
5×5 Matrix{Float64}:
0.0 0.0 0.0 0.0 0.16395
0.21055 0.0 0.544431 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.76612 0.0 0.0 0.785714 0.993288
0.0 0.740757 0.209118 0.0 0.0
Sparse vectors
Alternatively, we can convert a vector into a sparse array using the sparsevec()
function:
julia>
sparsevec([1 7 0 3 0])
5-element SparseVector{Int64, Int64} with 3 stored entries:
[1] = 1
[2] = 2
[4] = 4
Another method of construction can make use of a dictionary, as follows:
julia> sparsevec(Dict(1 => "Malcolm", 3 => "malcolm@myemail.org")) 3-element SparseVector{String, Int64} with 2 stored entries: [1] = "Malcolm" [3] = "malcolm@myemail.org" julia> sparsevec(Dict("name" => "Malcolm", "email" => "malcolm@ myemail.org")) ERROR: MethodError: no method matching sparsevec(::Dict{String, String})
Note: The key must be an integer; otherwise, an error is raised.
Sparse diagonal matrices
The eyes()
function to produce an identity matrix has been deprecated.
Instead, we can use spdiagm()
to create a sparse diagonal matrix, and then convert()
is required to convert it to a real matrix:
julia> A = spdiagm(ones(Int64,3)) # or spdiagm([1,1,1])
3×3 SparseMatrixCSC{Int64, Int64} with 3 stored entries:
1 ⋅ ⋅
⋅ 1 ⋅
⋅ ⋅ 1
julia>
convert(Matrix{Float64},A)
3×3 Matrix{Float64}:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
Arrays consist of a collection of homogeneous elements. Later, in Chapters 6 and 7, we will examine more sophisticated structures where the columns can be addressed by name.
These are termed DataFrames and can be thought of as equivalent to data held in a spreadsheet, but we will briefly introduce them here.