Introduction to Julia
Contents
1. Introduction to Julia#
1.1. Basics#
a = 2.5
5a
12.5
5*a
12.5
ans has the result from the last calculation:
ans
12.5
1.1.1. Two types of comments#
1.1.1.1. First type:#
# this is a one line comment
9a # comment can be at the end of a line too
22.5
1.1.1.2. Second type:#
#= This is the first line of a comment block
9a # comment can be at the end of a line too
This is the last line of the block =#
1.1.2. Julia allows simple way to swap values of variables#
a,b = 1,2
[a,b]
2-element Vector{Int64}:
1
2
# easy swapping of values
a,b = b,a
[a,b]
2-element Vector{Int64}:
2
1
# in most languages you have to do
a = 1
b = 2
temp = a
a = b
b = temp
[a,b]
2-element Vector{Int64}:
2
1
1.1.3. Julia allows simple boolean expressions#
# Example
1 < a < 3
true
# In many languages this has to be written as
1 < a && a < 3
true
1.1.4. Ternary Operator#
a = 1
b = 1
c = 2
res = a==b ? a : b
1
a==c ? a : c
2
a==c ? 1 : 10
10
a==c-b ? 1 : 10
1
1.1.5. Remainder#
99 % 10
9
100 % 10
0
90 % 10
0
1.2. Arrays (Vectors and Matricies)#
1.2.1. Declaration, Initialization and Indexing#
# empty vector of double precision floats
v = Array{Float64,1}()
Float64[]
push!(v,2.0)
v
1-element Vector{Float64}:
2.0
# vector of size 5, double precision floats
u = Array{Float64,1}(undef, 5)
5-element Vector{Float64}:
0.0
2.6510901773e-314
2.6510901773e-314
0.0
2.2853741065e-314
# matrix of size 3x5, double precision floats
U = Array{Float64,2}(undef, 3,5)
3×5 Matrix{Float64}:
2.65109e-314 2.31673e-314 2.65109e-314 2.31672e-314 2.31672e-314
0.0 4.4e-323 0.0 0.0 0.0
2.7404e-314 2.65109e-314 2.31693e-314 2.31693e-314 2.7404e-314
# vector of size 5, of 2.2
u = fill(2.2,5)
5-element Vector{Float64}:
2.2
2.2
2.2
2.2
2.2
zeros(5)
5-element Vector{Float64}:
0.0
0.0
0.0
0.0
0.0
zeros(3,5)
3×5 Matrix{Float64}:
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
zero(U)
3×5 Matrix{Float64}:
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
ones(3,5)
3×5 Matrix{Float64}:
1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0
using Random, Statistics, Distributions, LinearAlgebra, DataFrames, StatsPlots
rand(3,5) # uniform(0,1)
3×5 Matrix{Float64}:
0.129341 0.403507 0.793335 0.785751 0.28474
0.169252 0.586817 0.638285 0.302202 0.535084
0.0479145 0.648855 0.414168 0.473653 0.251349
randn(3,5) # standard normal
3×5 Matrix{Float64}:
-1.14629 0.592628 0.00659052 0.0827729 -0.588532
0.556471 0.398099 -0.544446 2.99655 0.81246
0.289367 2.6999 0.205432 -0.686602 0.486703
mean(randn(1_000_000))
0.002481562670449988
var(randn(1_000_000))
0.9980699762793211
M = rand(Binomial(2,0.5),10,20)
10×20 Matrix{Int64}:
0 1 2 1 2 2 1 1 0 1 2 1 0 2 0 1 1 0 0 1
0 0 0 1 1 1 2 2 1 1 1 1 2 1 1 1 0 2 1 0
0 2 1 1 0 1 1 1 1 1 1 1 1 1 1 1 2 1 0 1
1 1 1 1 1 1 0 1 0 2 1 0 1 1 1 1 1 1 2 0
1 1 1 2 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 2
2 2 0 0 1 1 1 1 1 1 1 1 2 0 1 2 2 0 1 2
0 1 0 0 1 1 1 1 2 1 2 1 0 0 2 1 2 2 1 1
1 1 2 2 0 2 2 1 1 1 0 1 0 2 1 2 2 2 0 2
2 1 1 1 0 0 1 2 1 1 1 0 1 2 1 0 0 1 1 1
2 1 1 1 1 1 2 0 2 0 0 1 2 0 1 2 1 0 1 2
1.2.1.1. Get first column as one dimensionsal array#
M[:,1]
10-element Vector{Int64}:
0
0
0
1
1
2
0
1
2
2
1.2.1.2. Get first row as one dimensionsal array¶#
M[1,:]
20-element Vector{Int64}:
0
1
2
1
2
2
1
1
0
1
2
1
0
2
0
1
1
0
0
1
1.2.1.3. Transposing and array gives a row vector#
M[1,:]'
1×20 adjoint(::Vector{Int64}) with eltype Int64:
0 1 2 1 2 2 1 1 0 1 2 1 0 2 0 1 1 0 0 1
1.2.1.4. Sum of squares of elements in first row#
M[1,:]'M[1,:]
29
M[1,:]'*M[1,:]
29
dot(M[1,:],M[1,:])
29
M[1,:].^2
20-element Vector{Int64}:
0
1
4
1
4
4
1
1
0
1
4
1
0
4
0
1
1
0
0
1
sum(M[1,:].^2)
29
1.2.1.5. Matrix transpose and product#
M'M == M'*M
true
1.2.2. Identity Matrix#
1.2.2.1. In general#
1I(3)
3×3 Diagonal{Int64, Vector{Int64}}:
1 ⋅ ⋅
⋅ 1 ⋅
⋅ ⋅ 1
1.0I(2)
2×2 Diagonal{Float64, Vector{Float64}}:
1.0 ⋅
⋅ 1.0
1.2.2.2. When dimensions and type can be inferred#
A = M'M + I
20×20 Matrix{Int64}:
16 11 8 9 6 8 11 9 10 … 6 12 8 9 12 10 6 9 14
11 16 10 10 8 12 12 11 11 9 11 10 11 14 16 9 8 15
8 10 14 12 7 12 11 9 7 7 6 13 7 11 11 8 5 12
9 10 12 15 7 12 13 11 9 8 9 13 9 12 11 11 7 13
6 8 7 7 11 10 9 8 7 7 8 7 7 10 9 6 7 9
8 12 12 12 10 16 14 11 10 … 10 9 12 10 15 15 11 7 14
11 12 11 13 9 14 19 13 14 11 13 12 12 16 14 13 8 16
9 11 9 11 8 11 13 16 10 8 11 13 11 11 11 13 9 11
10 11 7 9 7 10 14 10 15 9 11 7 12 13 13 11 8 14
7 10 8 8 7 10 9 11 7 6 8 10 9 10 11 10 8 8
5 10 7 6 9 10 9 11 8 … 7 7 9 9 9 11 9 7 8
6 9 7 8 7 10 11 8 9 9 8 7 8 11 11 8 5 11
12 11 6 9 8 9 13 11 11 8 17 7 10 13 10 8 10 12
8 10 13 13 7 12 12 13 7 7 7 17 8 10 10 11 6 11
9 11 7 9 7 10 12 11 12 8 10 8 13 12 13 12 9 12
12 14 11 12 10 15 16 11 13 … 11 13 10 12 19 17 11 9 17
10 16 11 11 9 15 14 11 13 11 10 10 13 17 21 12 8 17
6 9 8 11 6 11 13 13 11 8 8 11 12 11 12 17 8 10
9 8 5 7 7 7 8 9 8 5 10 6 9 9 8 8 11 8
14 15 12 13 9 14 16 11 14 11 12 11 12 17 17 10 8 21
B = rand(3,3) + I
3×3 Matrix{Float64}:
1.30066 0.238425 0.518354
0.914489 1.69864 0.759892
0.527934 0.571055 1.99534
B*I
3×3 Matrix{Float64}:
1.30066 0.238425 0.518354
0.914489 1.69864 0.759892
0.527934 0.571055 1.99534
B == B*I
true
B === B*I
false
1.2.3. Diagonal Matrix from \(\mathbf{A}\)#
Diagonal(A)
20×20 Diagonal{Int64, Vector{Int64}}:
16 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ 16 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ 14 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ 15 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ 11 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ 16 ⋅ ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 19 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 16 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 15 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 12 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 9 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 17 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 17 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 13 ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ 19 ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 21 ⋅ ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 17 ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 11 ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 21
1.2.4. Diagonal Matrix from \(\mathbf{v}\)#
v = [1,2,3]
Diagonal(v)
3×3 Diagonal{Int64, Vector{Int64}}:
1 ⋅ ⋅
⋅ 2 ⋅
⋅ ⋅ 3
1.2.5. Subset of Matrix#
B = A[1:2,3:4]
2×2 Matrix{Int64}:
8 9
10 10
C = A[1:2,11:end]
2×10 Matrix{Int64}:
5 6 12 8 9 12 10 6 9 14
10 9 11 10 11 14 16 9 8 15
1.2.6. Concatenation#
1.2.6.1. Horizontal#
[B C]
2×12 Matrix{Int64}:
8 9 5 6 12 8 9 12 10 6 9 14
10 10 10 9 11 10 11 14 16 9 8 15
hcat(B,C)
2×12 Matrix{Int64}:
8 9 5 6 12 8 9 12 10 6 9 14
10 10 10 9 11 10 11 14 16 9 8 15
1.2.6.2. Vertical#
[
A[1:2,:]
A[11:end,:]
]
12×20 Matrix{Int64}:
16 11 8 9 6 8 11 9 10 … 6 12 8 9 12 10 6 9 14
11 16 10 10 8 12 12 11 11 9 11 10 11 14 16 9 8 15
5 10 7 6 9 10 9 11 8 7 7 9 9 9 11 9 7 8
6 9 7 8 7 10 11 8 9 9 8 7 8 11 11 8 5 11
12 11 6 9 8 9 13 11 11 8 17 7 10 13 10 8 10 12
8 10 13 13 7 12 12 13 7 … 7 7 17 8 10 10 11 6 11
9 11 7 9 7 10 12 11 12 8 10 8 13 12 13 12 9 12
12 14 11 12 10 15 16 11 13 11 13 10 12 19 17 11 9 17
10 16 11 11 9 15 14 11 13 11 10 10 13 17 21 12 8 17
6 9 8 11 6 11 13 13 11 8 8 11 12 11 12 17 8 10
9 8 5 7 7 7 8 9 8 … 5 10 6 9 9 8 8 11 8
14 15 12 13 9 14 16 11 14 11 12 11 12 17 17 10 8 21
vcat(A[1:2,:],A[11:end,:])
12×20 Matrix{Int64}:
16 11 8 9 6 8 11 9 10 … 6 12 8 9 12 10 6 9 14
11 16 10 10 8 12 12 11 11 9 11 10 11 14 16 9 8 15
5 10 7 6 9 10 9 11 8 7 7 9 9 9 11 9 7 8
6 9 7 8 7 10 11 8 9 9 8 7 8 11 11 8 5 11
12 11 6 9 8 9 13 11 11 8 17 7 10 13 10 8 10 12
8 10 13 13 7 12 12 13 7 … 7 7 17 8 10 10 11 6 11
9 11 7 9 7 10 12 11 12 8 10 8 13 12 13 12 9 12
12 14 11 12 10 15 16 11 13 11 13 10 12 19 17 11 9 17
10 16 11 11 9 15 14 11 13 11 10 10 13 17 21 12 8 17
6 9 8 11 6 11 13 13 11 8 8 11 12 11 12 17 8 10
9 8 5 7 7 7 8 9 8 … 5 10 6 9 9 8 8 11 8
14 15 12 13 9 14 16 11 14 11 12 11 12 17 17 10 8 21
1.2.7. Sorting#
sort(M[:,1])
10-element Vector{Int64}:
0
0
0
0
1
1
1
2
2
2
index = sortperm(M[:,1])
10-element Vector{Int64}:
1
2
3
7
4
5
8
6
9
10
M[index,1]
10-element Vector{Int64}:
0
0
0
0
1
1
1
2
2
2
1.2.8. Sorting the entire matrix by the first column#
M[index,:]
10×20 Matrix{Int64}:
0 1 2 1 2 2 1 1 0 1 2 1 0 2 0 1 1 0 0 1
0 0 0 1 1 1 2 2 1 1 1 1 2 1 1 1 0 2 1 0
0 2 1 1 0 1 1 1 1 1 1 1 1 1 1 1 2 1 0 1
0 1 0 0 1 1 1 1 2 1 2 1 0 0 2 1 2 2 1 1
1 1 1 1 1 1 0 1 0 2 1 0 1 1 1 1 1 1 2 0
1 1 1 2 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 2
1 1 2 2 0 2 2 1 1 1 0 1 0 2 1 2 2 2 0 2
2 2 0 0 1 1 1 1 1 1 1 1 2 0 1 2 2 0 1 2
2 1 1 1 0 0 1 2 1 1 1 0 1 2 1 0 0 1 1 1
2 1 1 1 1 1 2 0 2 0 0 1 2 0 1 2 1 0 1 2
1.2.9. Sorting matrix by the sum of columns 1 and 2#
M[sortperm( M[:,1]+M[:,2] ),:]
10×20 Matrix{Int64}:
0 0 0 1 1 1 2 2 1 1 1 1 2 1 1 1 0 2 1 0
0 1 2 1 2 2 1 1 0 1 2 1 0 2 0 1 1 0 0 1
0 1 0 0 1 1 1 1 2 1 2 1 0 0 2 1 2 2 1 1
0 2 1 1 0 1 1 1 1 1 1 1 1 1 1 1 2 1 0 1
1 1 1 1 1 1 0 1 0 2 1 0 1 1 1 1 1 1 2 0
1 1 1 2 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 2
1 1 2 2 0 2 2 1 1 1 0 1 0 2 1 2 2 2 0 2
2 1 1 1 0 0 1 2 1 1 1 0 1 2 1 0 0 1 1 1
2 1 1 1 1 1 2 0 2 0 0 1 2 0 1 2 1 0 1 2
2 2 0 0 1 1 1 1 1 1 1 1 2 0 1 2 2 0 1 2
1.2.10. Selecting rows or columns of matrix#
1.2.10.1. Select rows where row sum is > 19#
vec(sum(M,dims=2) .> 19)
10-element BitVector:
0
0
0
0
1
1
1
1
0
1
M[vec(sum(M,dims=2) .> 19), :]
5×20 Matrix{Int64}:
1 1 1 2 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 2
2 2 0 0 1 1 1 1 1 1 1 1 2 0 1 2 2 0 1 2
0 1 0 0 1 1 1 1 2 1 2 1 0 0 2 1 2 2 1 1
1 1 2 2 0 2 2 1 1 1 0 1 0 2 1 2 2 2 0 2
2 1 1 1 1 1 2 0 2 0 0 1 2 0 1 2 1 0 1 2
1.2.10.2. Get random subset of 5 columns from M#
sel = sample(1:size(M,2),5,replace=false)
5-element Vector{Int64}:
16
1
13
7
9
M[:,sel]
10×5 Matrix{Int64}:
1 0 0 1 0
1 0 2 2 1
1 0 1 1 1
1 1 1 0 0
1 1 1 1 1
2 2 2 1 1
1 0 0 1 2
2 1 0 2 1
0 2 1 1 1
2 2 2 2 2
1.2.10.3. Get the remaining columns:#
M[:,-sel] does not work in Julia
M[:,Not(sel)]
10×15 Matrix{Int64}:
1 2 1 2 2 1 1 2 1 2 0 1 0 0 1
0 0 1 1 1 2 1 1 1 1 1 0 2 1 0
2 1 1 0 1 1 1 1 1 1 1 2 1 0 1
1 1 1 1 1 1 2 1 0 1 1 1 1 2 0
1 1 2 1 1 1 0 0 1 1 1 1 1 1 2
2 0 0 1 1 1 1 1 1 0 1 2 0 1 2
1 0 0 1 1 1 1 2 1 0 2 2 2 1 1
1 2 2 0 2 1 1 0 1 2 1 2 2 0 2
1 1 1 0 0 2 1 1 0 2 1 0 1 1 1
1 1 1 1 1 0 0 0 1 0 1 1 0 1 2
1.2.11. View of array#
m2 = @view M[:,2] # does not make a copy of the second column of M
10-element view(::Matrix{Int64}, :, 2) with eltype Int64:
1
0
2
1
1
2
1
1
1
1
m2[2] = 3
M
10×20 Matrix{Int64}:
0 1 2 1 2 2 1 1 0 1 2 1 0 2 0 1 1 0 0 1
0 3 0 1 1 1 2 2 1 1 1 1 2 1 1 1 0 2 1 0
0 2 1 1 0 1 1 1 1 1 1 1 1 1 1 1 2 1 0 1
1 1 1 1 1 1 0 1 0 2 1 0 1 1 1 1 1 1 2 0
1 1 1 2 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 2
2 2 0 0 1 1 1 1 1 1 1 1 2 0 1 2 2 0 1 2
0 1 0 0 1 1 1 1 2 1 2 1 0 0 2 1 2 2 1 1
1 1 2 2 0 2 2 1 1 1 0 1 0 2 1 2 2 2 0 2
2 1 1 1 0 0 1 2 1 1 1 0 1 2 1 0 0 1 1 1
2 1 1 1 1 1 2 0 2 0 0 1 2 0 1 2 1 0 1 2
Note that changing the value of m2[2] results in changing the second column of M.
1.2.11.1. View of a row from a matrix#
# view of row 2 from M
row2 = @view M[2,:]
20-element view(::Matrix{Int64}, 2, :) with eltype Int64:
0
3
0
1
1
1
2
2
1
1
1
1
2
1
1
1
0
2
1
0
Note that the view of a row from a matrix is a one-dimensional array that behaves like a column vector!
row2'row2
36
1.2.12. Copy of array#
v = [1, 2, 3]
3-element Vector{Int64}:
1
2
3
u = v
u[1] = 10
u
3-element Vector{Int64}:
10
2
3
v
3-element Vector{Int64}:
10
2
3
So, u is not just a copy of v. It is another name for v. To get a copy use:
v = [1, 2, 3]
u = copy(v)
u[1] = 10
u
3-element Vector{Int64}:
10
2
3
v
3-element Vector{Int64}:
1
2
3
1.2.13. Sparse Matrices#
using SparseArrays, LinearAlgebra
x=[1,1,2,2,2,2,3,3,4,1]
y=[1.1,1.2,1.9,1.2,2.0,1.7,1.0,1.7,1.1,1.7]
n = size(x,1)
10
# X is a sparse matrix, where only non-zero elements are stored
X = sparse(1:n,x,1.0) # In general, the last argument can be a vector
X =[ones(n) X] # # concatenation works with sparse X
10×5 SparseMatrixCSC{Float64, Int64} with 20 stored entries:
1.0 1.0 ⋅ ⋅ ⋅
1.0 1.0 ⋅ ⋅ ⋅
1.0 ⋅ 1.0 ⋅ ⋅
1.0 ⋅ 1.0 ⋅ ⋅
1.0 ⋅ 1.0 ⋅ ⋅
1.0 ⋅ 1.0 ⋅ ⋅
1.0 ⋅ ⋅ 1.0 ⋅
1.0 ⋅ ⋅ 1.0 ⋅
1.0 ⋅ ⋅ ⋅ 1.0
1.0 1.0 ⋅ ⋅ ⋅
# Full matrix from X
Matrix(X)
10×5 Matrix{Float64}:
1.0 1.0 0.0 0.0 0.0
1.0 1.0 0.0 0.0 0.0
1.0 0.0 1.0 0.0 0.0
1.0 0.0 1.0 0.0 0.0
1.0 0.0 1.0 0.0 0.0
1.0 0.0 1.0 0.0 0.0
1.0 0.0 0.0 1.0 0.0
1.0 0.0 0.0 1.0 0.0
1.0 0.0 0.0 0.0 1.0
1.0 1.0 0.0 0.0 0.0
# usual matrix operations work
rhs = X'y
lhs = X'X
5×5 SparseMatrixCSC{Float64, Int64} with 13 stored entries:
10.0 3.0 4.0 2.0 1.0
3.0 3.0 ⋅ ⋅ ⋅
4.0 ⋅ 4.0 ⋅ ⋅
2.0 ⋅ ⋅ 2.0 ⋅
1.0 ⋅ ⋅ ⋅ 1.0
lhs = X'X
rhs = X'y
5-element Vector{Float64}:
14.599999999999998
4.0
6.8
2.7
1.1
1.2.13.1. Getting solution to (X’X)b = X’y#
# lhs = X'X and rhs=X'y
QRLhs = qr(lhs)
b = QRLhs\rhs
5-element Vector{Float64}:
1.099999999999999
0.23333333333333395
0.6000000000000002
0.25000000000000117
0.0
[lhs*b rhs]
5×2 Matrix{Float64}:
14.6 14.6
4.0 4.0
6.8 6.8
2.7 2.7
1.1 1.1
1.2.13.2. Sparse Zero Matrix#
spzeros(2,2)
2×2 SparseMatrixCSC{Float64, Int64} with 0 stored entries:
⋅ ⋅
⋅ ⋅
1.2.13.3. Sparse Identity Matrix#
N = 1_000_000
R = sparse(1.0I,N,N)
1000000×1000000 SparseMatrixCSC{Float64, Int64} with 1000000 stored entries:
⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄
1.3. Control Flow and Loops#
1.3.1. Adding vectors u and v.#
1.3.1.1. Hard coding:#
This is one way to get the result. But, coding will be tedious for long vectors. Further, recoding will be required when the lenght of the vectors changes.
result = zero(u) # gets vector of zeros identical in dimension to that of u
result[1] = u[1] + v[1]
result[2] = u[2] + v[2]
result[3] = u[3] + v[3]
[u v result]
3×3 Matrix{Int64}:
10 1 11
2 2 4
3 3 6
1.3.1.2. Using loop:#
The code is the same for vectors of any length.
result = zero(u)
for i=1:size(u,1)
result[i] = u[i] + v[i]
end
[u v result]
3×3 Matrix{Int64}:
10 1 11
2 2 4
3 3 6
Use of a function is a more general way to do this!
1.3.2. Sum of elements in v#
mySum = 0.0
for i = v
mySum += i
end
mySum
6.0
1.3.3. Get vector of squared values in v#
1.3.3.1. Using loop:#
n = size(v,1)
result = zeros(n)
for i=1:n
result[i] = v[i]^2
end
result
3-element Vector{Float64}:
1.0
4.0
9.0
1.3.3.2. Using list comprehension:#
This is a more concise way to get the same result.
[i^2 for i in v]
3-element Vector{Int64}:
1
4
9
1.3.4. List comprehension with condition#
x = randn(10)
[sqrt(i) for i in x if i >= 0.0]
3-element Vector{Float64}:
0.922823681844622
1.1136044483660863
0.2911101749398534
res = [[i sqrt(value)] for (i,value) in enumerate(x) if value >= 0.0]
3-element Vector{Matrix{Float64}}:
[3.0 0.922823681844622]
[4.0 1.1136044483660863]
[10.0 0.2911101749398534]
1.3.5. Convert array of arrays to matrix:#
Each element of res computed above is also an array with two elements. Often, we would like to convert such and array of arrays to a matrix.
Two methods methods are given below to accomplish this.
1.3.5.1. Method 1:#
resMat = [row[i] for row in res, i=1:2]
3×2 Matrix{Float64}:
3.0 0.922824
4.0 1.1136
10.0 0.29111
1.3.5.2. Method 2:#
vcat(res...)
3×2 Matrix{Float64}:
3.0 0.922824
4.0 1.1136
10.0 0.29111
1.3.6. Matrix from list comprehension#
[i+j for i=1:2, j=3:5]
2×3 Matrix{Int64}:
4 5 6
5 6 7
1.3.7. Use of Range#
r = range(0, step=0.1, stop=1)
0.0:0.1:1.0
# This works too
r = 0:0.1:1
0.0:0.1:1.0
r is not an arryay, but in many contexts behaves like one
sin.(r)
11-element Vector{Float64}:
0.0
0.09983341664682815
0.19866933079506122
0.29552020666133955
0.3894183423086505
0.479425538604203
0.5646424733950354
0.644217687237691
0.7173560908995228
0.7833269096274834
0.8414709848078965
1.3.8. Use of Map to apply a function to elements of array#
map(sin,r)
11-element Vector{Float64}:
0.0
0.09983341664682815
0.19866933079506122
0.29552020666133955
0.3894183423086505
0.479425538604203
0.5646424733950354
0.644217687237691
0.7173560908995228
0.7833269096274834
0.8414709848078965
1.3.9. Reduce and Map-Reduce#
# sum of elements in u
reduce(+,u)
15
# product of elements in u
reduce(*,u)
60
reduce(+,1:1000000)
500000500000
1.3.9.1. Sum of squares#
n = 1_000_000
mapreduce(x -> x^2, +, 1:n)
333333833333500000
Here, a vector of squares is created first, which, as will be demonstrated later, slower because of the time used for memory allocation
reduce(+,(1:n).^2)
333333833333500000
1.4. Types#
1.4.1. Determine the type of a variable as:#
# type of M
typeof(M)
Matrix{Int64} (alias for Array{Int64, 2})
# type of v
typeof(v)
Vector{Int64} (alias for Array{Int64, 1})
1.4.2. Composite Types#
An example of a user-defined type:
# Example
mutable struct BankAccount
accountNumber::Int64
firstName::String
lastName::String
balance::Float64
end
1.4.2.1. Get all the names in a composite type:#
fieldnames(BankAccount)
(:accountNumber, :firstName, :lastName, :balance)
1.4.2.2. Get the types of all fields:#
BankAccount.types
svec(Int64, String, String, Float64)
1.4.2.3. Create an instance of BankAccount#
a1 = BankAccount(1234,"Tom","Smith",1000.0)
a2 = BankAccount(4321,"Jim","Shanks",500.0)
a3 = BankAccount(9321,"Scott","Williams",500.0)
BankAccount(9321, "Scott", "Williams", 500.0)
1.4.2.4. Access field in composite type:#
a1.balance
1000.0
# can modify fields of mutable structs
a1.balance = 2000.50
2000.5
a2.balance
500.0
a2.firstName
"Jim"
1.5. Dictionaries (Associative Arrays)#
A dictionary in Julia is a collection of key value pairs.
1.5.1. Declaration#
In the example given below, d is an empty dictionary that can store an instance of the composite type BankAccount with an associated integer key.
#=
d is an empty dictionary that can store "BackAccounts"
with an interger key (i.e., with the account number as the key)
=#
d = Dict{Int64,BankAccount}()
Dict{Int64, BankAccount}()
1.5.2. Putting values in dictionary#
Recall that a1 and a2 are instances of the composite type BankAccount.
@show(a1)
a1 = BankAccount(1234, "Tom", "Smith", 2000.5)
BankAccount(1234, "Tom", "Smith", 2000.5)
d[a1.accountNumber] = a1
d
Dict{Int64, BankAccount} with 1 entry:
1234 => BankAccount(1234, "Tom", "Smith", 2000.5)
d[a2.accountNumber] = a2
d
Dict{Int64, BankAccount} with 2 entries:
1234 => BankAccount(1234, "Tom", "Smith", 2000.5)
4321 => BankAccount(4321, "Jim", "Shanks", 500.0)
d[a3.accountNumber] = a3
d
Dict{Int64, BankAccount} with 3 entries:
1234 => BankAccount(1234, "Tom", "Smith", 2000.5)
4321 => BankAccount(4321, "Jim", "Shanks", 500.0)
9321 => BankAccount(9321, "Scott", "Williams", 500.0)
1.5.3. Get array of keys in d#
collect(keys(d))
3-element Vector{Int64}:
1234
4321
9321
1.5.3.1. Get the value associated with key = 1234#
d[1234]
BankAccount(1234, "Tom", "Smith", 2000.5)
1.5.4. Get array of values in d#
1.5.4.1. Using values function#
values(d)
ValueIterator for a Dict{Int64, BankAccount} with 3 entries. Values:
BankAccount(1234, "Tom", "Smith", 2000.5)
BankAccount(4321, "Jim", "Shanks", 500.0)
BankAccount(9321, "Scott", "Williams", 500.0)
collect(values(d))
3-element Vector{BankAccount}:
BankAccount(1234, "Tom", "Smith", 2000.5)
BankAccount(4321, "Jim", "Shanks", 500.0)
BankAccount(9321, "Scott", "Williams", 500.0)
1.5.4.2. Using list comprehension#
[i for i in values(d)]
3-element Vector{BankAccount}:
BankAccount(1234, "Tom", "Smith", 2000.5)
BankAccount(4321, "Jim", "Shanks", 500.0)
BankAccount(9321, "Scott", "Williams", 500.0)
keys(d)
KeySet for a Dict{Int64, BankAccount} with 3 entries. Keys:
1234
4321
9321
[d[i] for i in keys(d)]
3-element Vector{BankAccount}:
BankAccount(1234, "Tom", "Smith", 2000.5)
BankAccount(4321, "Jim", "Shanks", 500.0)
BankAccount(9321, "Scott", "Williams", 500.0)
1.5.5. Check if Dictionary has a particular key#
haskey(d,1234)
true
haskey(d,123)
false
1.6. Functions and Scope of Variables#
1.6.1. Function for adding two vectors#
Functions allow code to be reused. We have seen how a loop can be used to add two vectors:
u = [1,2]
v = [3,4]
result = zero(u)
for i=1:size(u,1)
result[i] = u[i] + v[i]
end
[u v result]
2×3 Matrix{Int64}:
1 3 4
2 4 6
Suppose we now want to add vector x to vector y:
x = [9,7,6,5]
y = [2,2,2,1];
We can do by copying the code from above as:
u = x
v = y
result = zero(u)
for i=1:size(u,1)
result[i] = u[i] + v[i]
end
[u v result]
4×3 Matrix{Int64}:
9 2 11
7 2 9
6 2 8
5 1 6
This can and should be avoided by using a function with the code that was repeated.
function addVectors(u,v)
if size(u,1) != size(v,1)
println("The size of u (= $(size(u,1))) is not equal to the size of v (= $(size(v,1))) ")
return []
end
result = zero(u)
for i=1:size(u,1)
result[i] = u[i] + v[i]
end
return result
end
addVectors (generic function with 1 method)
[u v addVectors(u,v)]
4×3 Matrix{Int64}:
9 2 11
7 2 9
6 2 8
5 1 6
[x y addVectors(x,y)]
4×3 Matrix{Int64}:
9 2 11
7 2 9
6 2 8
5 1 6
[x u addVectors(x,u)]
4×3 Matrix{Int64}:
9 9 18
7 7 14
6 6 12
5 5 10
1.6.2. Scope of Variables#
Note that within the function addVectors, the output is the sum of the vectors u and v, but calling it with the vectors x and y results their sum. The variables u and v within the function refer to those given when the function was called. Thus, the same function can be used to add any two vectors of the same length. The behavior of the variables u and v within the function has to do with what is called the scope of variables and how variables are passed to functions. In Julia variables are passed “by reference” rather than “by value”. This makes passing large structures to functions very efficient compared to passing arguments to the function “by value”, which requies making a copy of the argument.
However, at first, the way functions behave can be confusing as shown below.
function addOne(x) # x is a local variable pointing to the value of the argument of the function
@show(x)
x = x + 1 # x is now redirected to point the the value of (x+1)
@show(x)
return x
end
addOne (generic function with 1 method)
y = 2
@show(y)
@show(addOne(y))
@show(y); # y is still pointing to 2
y = 2
x = 2
x = 3
addOne(y) = 3
y = 2
function addOneToVec(x) # x is a local variable pointing to the vector argument of the function
@show(x)
x = x .+ 1 # x is now redirected to point a new vector with the values of (x+1)
@show(x)
return x
end
addOneToVec (generic function with 1 method)
u = [1,2]
@show(u)
@show(addOneToVec(u))
@show(u)
u = [1, 2]
x = [1, 2]
x = [2, 3]
addOneToVec(u) = [2, 3]
u = [1, 2]
2-element Vector{Int64}:
1
2
Compare the behavior of the following funtion with that above:
function addOneToVec!(x) # x is a local variable pointing to the vector argument of the function
@show(x)
x .= x .+ 1 # x still points to the same vector, but the elemets in the vector are modified
@show(x)
return x
end
addOneToVec! (generic function with 1 method)
u = [1,2]
@show(u)
@show(addOneToVec!(u))
@show(u)
u = [1, 2]
x = [1, 2]
x = [2, 3]
addOneToVec!(u) = [2, 3]
u = [2, 3]
2-element Vector{Int64}:
2
3
function addOneToVecLoop!(x) # x is a local variable pointing to the vector argument of the function
@show(x)
for i in 1:size(x,1)
x[i] += 1 # x still points to the same vector, but the elemets in the vector x are are modified here
end
@show(x)
return x
end
addOneToVecLoop! (generic function with 1 method)
u = [1,2]
@show(u)
@show(addOneToVecLoop!(u))
@show(u)
u = [1, 2]
x = [1, 2]
x = [2, 3]
addOneToVecLoop!(u) = [2, 3]
u = [2, 3]
2-element Vector{Int64}:
2
3
Nice explanation of the difference in bahavior of these functions is given here: The Map is Not the Territory!
1.6.2.1. Functions can have arguments with default values#
function addYToVec!(x,y=1) # x is a local variable pointing to the vector argument of the function
@show(x)
x .= x .+ y # x still points to the same vector, but the elemets in the vector are modified
@show(x)
return x
end
addYToVec! (generic function with 2 methods)
u = [1,2]
@show(u)
@show(addYToVec!(u)) # default value is added to each element of u
@show(u)
u = [1, 2]
x = [1, 2]
x = [2, 3]
addYToVec!(u) = [2, 3]
u = [2, 3]
2-element Vector{Int64}:
2
3
u = [1,2]
@show(u)
@show(addYToVec!(u,2))
@show(u)
u = [1, 2]
x = [1, 2]
x = [3, 4]
addYToVec!(u, 2) = [3, 4]
u = [3, 4]
2-element Vector{Int64}:
3
4
function addkTimesYToVec!(x,k=1,y=2) # x is a local variable pointing to the vector argument of the function
@show(x)
x .= x .+ y*k # x still points to the same vector, but the elemets in the vector are modified
@show(x)
return x
end
addkTimesYToVec! (generic function with 3 methods)
u = [1,2]
@show(u)
@show(addkTimesYToVec!(u))
@show(u)
u = [1, 2]
x = [1, 2]
x = [3, 4]
addkTimesYToVec!(u) = [3, 4]
u = [3, 4]
2-element Vector{Int64}:
3
4
addkTimesYToVec!(u,2,2)
x = [3, 4]
x = [7, 8]
2-element Vector{Int64}:
7
8
1.6.3. Functions with key value pairs#
function addcxToV!(v;c=1,x=2)
v .= c*x .+ v
end
addcxToV! (generic function with 1 method)
v = [2,5]
@show(addcxToV!(v))
addcxToV!(v) = [4, 7]
2-element Vector{Int64}:
4
7
v = [2,5]
@show(addcxToV!(v,x=1))
addcxToV!(v, x = 1) = [3, 6]
2-element Vector{Int64}:
3
6
1.6.4. Multiple Dispatch of “+” Operator (Overloading Operators)#
What the “+” operator does depends on the arguments. The function defined below will be called when it is used with two BankAccount arguments. Other operators can be similarly “overloaded” to work with user-defined types.
import Base.+
function +(a1::BankAccount,a2::BankAccount)
a1.balance += a2.balance
a2.balance = 0
end
+ (generic function with 337 methods)
@show(a1,a2)
a1 + a2
@show(a1,a2)
a1 = BankAccount(1234, "Tom", "Smith", 2000.5)
a2 = BankAccount(4321, "Jim", "Shanks", 500.0)
a1 = BankAccount(1234, "Tom", "Smith", 2500.5)
a2 = BankAccount(4321, "Jim", "Shanks", 0.0)
BankAccount(4321, "Jim", "Shanks", 0.0)
@show(a1,a2)
+(a1,a2)
@show(a1,a2)
a1 = BankAccount(1234, "Tom", "Smith", 2500.5)
a2 = BankAccount(4321, "Jim", "Shanks", 0.0)
a1 = BankAccount(1234, "Tom", "Smith", 2500.5)
a2 = BankAccount(4321, "Jim", "Shanks", 0.0)
BankAccount(4321, "Jim", "Shanks", 0.0)
1.6.5. Keyword arguments cannot be used for multiple dispatch#
See example below.
struct T1
a
end
struct T2
a
end
struct T3
a
end
function f1(;a::T1=T1(1),b::T2=T2(2))
println("called f1.1")
end
function f1(;a::T1=T1(1),b::T3=T2(2))
println("called f1.2")
end
f1 (generic function with 4 methods)
function f1(a::T1,b::T2)
println("called f1.1")
end
function f1(a::T1,b::T3)
println("called f1.2")
end
f1 (generic function with 4 methods)
Observe that there is only once version of the function f1. The error message below indicates that this is the second version of f1.
t1 = T1(1)
t2 = T2(2)
f1(t1,t2)
called f1.1
t1 = T1(1)
t3 = T3(2)
f1(t1,t3)
called f1.2
1.6.6. Often loops faster than vectorizng!#
function f1(n)
mapreduce(x -> x^2, +, 1:n)
end
f1 (generic function with 4 methods)
function f2(n)
reduce(+,(1:n).^2)
end
f2 (generic function with 1 method)
@time f1(1_000_000)
0.000008 seconds
333333833333500000
@time f2(1_000_000)
0.001482 seconds (2 allocations: 7.629 MiB)
333333833333500000
function f3(n)
sum = 0
for i=1:n
sum += i^2
end
return sum
end
f3 (generic function with 1 method)
@time f3(1_000_000)
0.000001 seconds
333333833333500000
1.6.7. Exercise 1#
Write a function that uses loops to get the sum of two matrices.
Write a function with two matrix arguments that adds the second matrix to the first.
Write a function that uses loops to get the product of two matrices.
1.7. Reading and Writing from Files#
1.7.1. Text Files#
using Printf # needed for formatted print commands
A = randn(5,3)
5×3 Matrix{Float64}:
0.669857 -1.21934 1.31056
-0.462572 -1.16608 0.791675
-0.593859 -0.328803 0.167676
1.71628 0.229148 -1.38876
0.159478 -0.0830671 0.287764
out = open("outFile","w")
n,p = size(A)
for j=1:p
for i=1:n
@printf(out,"%10.5f ", A[i,j])
end
@printf(out,"\n")
end
close(out)
;cat outFile
0.66986 -0.46257 -0.59386 1.71628 0.15948
-1.21934 -1.16608 -0.32880 0.22915 -0.08307
1.31056 0.79168 0.16768 -1.38876 0.28776
out = open("outFile","w")
n,p = size(A)
for j=1:p
for i=1:n
print(out,A[i,j]," ")
end
print(out,"\n")
end
close(out)
;cat outFile
0.6698567590661276 -0.46257224464332686 -0.5938591760174075 1.7162807282163426 0.15947807674461775
-1.2193382243272648 -1.1660833900777565 -0.32880276954201504 0.2291476939774907 -0.08306709656829485
1.3105565730969828 0.7916752349695576 0.1676757568305786 -1.3887550352180391 0.28776434339771584
out = open("outFile","w")
n,p = size(A)
for j=1:p
for i=1:n
@printf(out,"%10.5e ", A[i,j])
end
@printf(out,"\n")
end
close(out)
;cat outFile
6.69857e-01 -4.62572e-01 -5.93859e-01 1.71628e+00 1.59478e-01
-1.21934e+00 -1.16608e+00 -3.28803e-01 2.29148e-01 -8.30671e-02
1.31056e+00 7.91675e-01 1.67676e-01 -1.38876e+00 2.87764e-01
inStream = open("outFile","r")
for line = eachline(inStream)
println(line)
end
close(inStream)
6.69857e-01 -4.62572e-01 -5.93859e-01 1.71628e+00 1.59478e-01
-1.21934e+00 -1.16608e+00 -3.28803e-01 2.29148e-01 -8.30671e-02
1.31056e+00 7.91675e-01 1.67676e-01 -1.38876e+00 2.87764e-01
B = Array{Float64,2}(undef,5,3)
5×3 Matrix{Float64}:
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
B = zeros(5,3)
5×3 Matrix{Float64}:
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
inStream = open("outFile","r")
j = 1
for line = eachline(inStream)
B[:,j] = parse.(Float64,split(line))
j += 1
end
close(inStream)
B
5×3 Matrix{Float64}:
0.669857 -1.21934 1.31056
-0.462572 -1.16608 0.791675
-0.593859 -0.328803 0.167676
1.71628 0.229148 -1.38876
0.159478 -0.0830671 0.287764
;cat outFile
6.69857e-01 -4.62572e-01 -5.93859e-01 1.71628e+00 1.59478e-01
-1.21934e+00 -1.16608e+00 -3.28803e-01 2.29148e-01 -8.30671e-02
1.31056e+00 7.91675e-01 1.67676e-01 -1.38876e+00 2.87764e-01
1.7.2. Binary Files#
Write matrix A. In Julia matrices are stored by column (column-major). So writing should be done by column.
binOut = open("out.bin","w")
n,p = size(A)
write(binOut,n,p)
for j=1:p, i=1:n
write(binOut,A[i,j])
end
close(binOut)
binIn = open("out.bin","r")
IOStream(<file out.bin>)
1.7.3. Reading from a binary file is easy.#
mySize = zeros(Int64,2)
read!(binIn,mySize)
n = mySize[1]
p = mySize[2]
3
C = zeros(n,p)
read!(binIn,C)
close(binIn)
C
5×3 Matrix{Float64}:
0.669857 -1.21934 1.31056
-0.462572 -1.16608 0.791675
-0.593859 -0.328803 0.167676
1.71628 0.229148 -1.38876
0.159478 -0.0830671 0.287764
1.8. Working with DataFrames#
using DataFrames, CSV
1.8.1. Create a DataFrame#
mydf = DataFrame(ID=1:3, y=randn(3), m1=[0.0,1.0,2.0],m2=[2.0,2.0,1.0])
| ID | y | m1 | m2 | |
|---|---|---|---|---|
| Int64 | Float64 | Float64 | Float64 | |
| 1 | 1 | -0.212574 | 0.0 | 2.0 |
| 2 | 2 | -1.39152 | 1.0 | 2.0 |
| 3 | 3 | -0.621479 | 2.0 | 1.0 |
Or you can create a DataFrame from a matix:
m=[0.0 2.0
1.0 2.0
2.0 1.0]
dfnames=["m1","m2"]
mydf = DataFrame(m,dfnames)
| m1 | m2 | |
|---|---|---|
| Float64 | Float64 | |
| 1 | 0.0 | 2.0 |
| 2 | 1.0 | 2.0 |
| 3 | 2.0 | 1.0 |
1.8.2. Insert columns into a DataFrame:#
insertcols!(mydf, 1, :ID => 1:3) #1 means the 1st column
| ID | m1 | m2 | |
|---|---|---|---|
| Int64 | Float64 | Float64 | |
| 1 | 1 | 0.0 | 2.0 |
| 2 | 2 | 1.0 | 2.0 |
| 3 | 3 | 2.0 | 1.0 |
insertcols!(mydf, 2, :y => randn(3)) #2 means the 2nd column
| ID | y | m1 | m2 | |
|---|---|---|---|---|
| Int64 | Float64 | Float64 | Float64 | |
| 1 | 1 | -1.23616 | 0.0 | 2.0 |
| 2 | 2 | -1.54222 | 1.0 | 2.0 |
| 3 | 3 | -0.369228 | 2.0 | 1.0 |
1.8.3. change type of a column#
mydf[!,:ID] = string.(mydf[!,:ID]) #change from Int64 to string
3-element Vector{String}:
"1"
"2"
"3"
mydf
| ID | y | m1 | m2 | |
|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | |
| 1 | 1 | -1.23616 | 0.0 | 2.0 |
| 2 | 2 | -1.54222 | 1.0 | 2.0 |
| 3 | 3 | -0.369228 | 2.0 | 1.0 |
1.8.4. Save a DataFrame as a CSV file#
CSV.write("test.csv", mydf)
"test.csv"
1.8.5. Read data from CSV files as DataFrame#
mydf=CSV.read("test.csv",DataFrame)
mydf[!,:ID] = string.(mydf[!,:ID]);
mydf
| ID | y | m1 | m2 | |
|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | |
| 1 | 1 | -1.23616 | 0.0 | 2.0 |
| 2 | 2 | -1.54222 | 1.0 | 2.0 |
| 3 | 3 | -0.369228 | 2.0 | 1.0 |
more options can be found in the documentation (run ?CSV.File())
1.8.6. Access the columns of a data frame without copying#
mydf[!,"ID"]
3-element Vector{String}:
"1"
"2"
"3"
mydf[!,1:2]
| ID | y | |
|---|---|---|
| String | Float64 | |
| 1 | 1 | -1.23616 |
| 2 | 2 | -1.54222 |
| 3 | 3 | -0.369228 |
mydf[!,[:ID,:y]]
| ID | y | |
|---|---|---|
| String | Float64 | |
| 1 | 1 | -1.23616 |
| 2 | 2 | -1.54222 |
| 3 | 3 | -0.369228 |
a=mydf[!,"ID"]
a[1]="will change";
mydf
| ID | y | m1 | m2 | |
|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | |
| 1 | will change | -1.23616 | 0.0 | 2.0 |
| 2 | 2 | -1.54222 | 1.0 | 2.0 |
| 3 | 3 | -0.369228 | 2.0 | 1.0 |
1.8.7. get a copy of the column#
mydf[:,"ID"]
3-element Vector{String}:
"will change"
"2"
"3"
mydf[:,1:2]
| ID | y | |
|---|---|---|
| String | Float64 | |
| 1 | will change | -1.23616 |
| 2 | 2 | -1.54222 |
| 3 | 3 | -0.369228 |
a=mydf[:,"ID"]
a[1]="this won't change"; #will not change because a is the copy of the column
mydf
| ID | y | m1 | m2 | |
|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | |
| 1 | will change | -1.23616 | 0.0 | 2.0 |
| 2 | 2 | -1.54222 | 1.0 | 2.0 |
| 3 | 3 | -0.369228 | 2.0 | 1.0 |
mydf[:,:ID] = ["a1","a2","a3"]; #this will change the column
mydf
| ID | y | m1 | m2 | |
|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | |
| 1 | a1 | -1.23616 | 0.0 | 2.0 |
| 2 | a2 | -1.54222 | 1.0 | 2.0 |
| 3 | a3 | -0.369228 | 2.0 | 1.0 |
mydf[!,:ID] = ["ind1","ind2","ind3"]; #this will change the column
mydf
| ID | y | m1 | m2 | |
|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | |
| 1 | ind1 | -1.23616 | 0.0 | 2.0 |
| 2 | ind2 | -1.54222 | 1.0 | 2.0 |
| 3 | ind3 | -0.369228 | 2.0 | 1.0 |
1.8.8. Indexing#
mydf[1:2,:y] # returns a vector
2-element Vector{Float64}:
-1.2361576577666837
-1.542222753508024
mydf[1:2,2] # returns a vector
2-element Vector{Float64}:
-1.2361576577666837
-1.542222753508024
mydf[1:2,[:y]] #returns a data frame object
| y | |
|---|---|
| Float64 | |
| 1 | -1.23616 |
| 2 | -1.54222 |
mydf[1:2,[2]] #returns a data frame object
| y | |
|---|---|
| Float64 | |
| 1 | -1.23616 |
| 2 | -1.54222 |
mydf[1:2,[1,3]] #returns a data frame object
| ID | m1 | |
|---|---|---|
| String | Float64 | |
| 1 | ind1 | 0.0 |
| 2 | ind2 | 1.0 |
mydf[1:2,end] #end means the last one
2-element Vector{Float64}:
2.0
2.0
1.8.9. DataFrame to Matrix#
Matrix(mydf[:,[:m1,:m2]])
3×2 Matrix{Float64}:
0.0 2.0
1.0 2.0
2.0 1.0
1.8.10. get basic information about a dataframe#
size(mydf)
(3, 4)
size(mydf,1)
3
size(mydf,2)
4
nrow(mydf)
3
ncol(mydf)
4
first(mydf, 2) #show the first 2 rows
| ID | y | m1 | m2 | |
|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | |
| 1 | ind1 | -1.23616 | 0.0 | 2.0 |
| 2 | ind2 | -1.54222 | 1.0 | 2.0 |
last(mydf, 3) #show the last 3 rows
| ID | y | m1 | m2 | |
|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | |
| 1 | ind1 | -1.23616 | 0.0 | 2.0 |
| 2 | ind2 | -1.54222 | 1.0 | 2.0 |
| 3 | ind3 | -0.369228 | 2.0 | 1.0 |