add example of dates interpolation

This commit is contained in:
Bogumił Kamiński 2022-06-26 19:21:57 +02:00
parent 3259f8aa8a
commit 70e470dfa9

574
slides/ch02_slides.md Normal file
View File

@ -0,0 +1,574 @@
---
marp: true
---
# Julia for Data Analysis
## Chapter 2: Getting started with Julia
### Bogumił Kamiński
https://github.com/bkamins/JuliaForDataAnalysis
---
# Outline
1. Values
2. Variables
3. Control flow
3.1. Conditional evaluation
3.2. Loops
3.3. Compound expressions
4. Defining functions
5. Scoping rules
---
# Values
* A *value* is a representation of some entity that is stored in computer's
memory and can be manipulated by Julia program.
* Every value is a result of evaluation of some Julia expression.
* Example values created by evaluation of *literals*:
```
julia> 0.1
0.1
julia> "Hello world!"
"Hello world!"
julia> [1, 2, 3]
3-element Vector{Int64}:
1
2
3
```
---
# Types
* Each value has a type, which you can check using the `typeof` function.
* When you define a function you optionally can define the types of arguments
that the function accepts.
* Example types of values:
```
julia> typeof(0.1)
Float64
julia> typeof("Hello world!")
String
julia> typeof([1, 2, 3])
Vector{Int64} (alias for Array{Int64, 1})
```
---
# Checking memory layout of numbers
* Numbers in Julia can have different types (e.g. `Int64`, `Float64`, `Int8`).
* Each such type can use a different memory layout to represent the same
mathematical value.
* Examples of representation of *one*:
```
julia> bitstring(1)
"0000000000000000000000000000000000000000000000000000000000000001"
julia> bitstring(1.0)
"0011111111110000000000000000000000000000000000000000000000000000"
julia> bitstring(Int8(1))
"00000001"
```
---
# Integer type
On 64-bit machines integers in Julia by default use 64-bit representation
(`Int64` type). As a shorthand you can use `Int` alias type name instead:
```
julia> Int
Int64
```
---
# Container types typically have parameters in Julia
```
julia> typeof([1, 2, 3])
Vector{Int64} (alias for Array{Int64, 1})
```
* `Vector{Int64}` tells us that `[1, 2, 3]` is a vector that can store
integer numbers; the `Int64` part is a parameter of `Vector`;
* `Array{Int64, 1}` is another way to write the same; now we have two parameters:
1. element type that our array can store (`Int64`, an integer);
2. dimension of our array (`1`, a vector).
---
# Checking if value has some type
You can check if some value has some type using the `isa` operator:
```
julia> [1, 2, 3] isa Vector{Int}
true
julia> [1, 2, 3] isa Array{Int64, 1}
true
```
---
# Variables
* You can bind a value to a variable name using the assignment operator `=`:
```
julia> x = 1
1
julia> y = [1, 2, 3]
3-element Vector{Int64}:
1
2
3
```
* The process of binding does not involve copying of values.
Python also follows this approach.
In R this is not the case.
---
# Only values have types in Julia
You can, in general assign values of different types to the same variable name:
```
julia> x = 1
1
julia> typeof(x)
Int64
julia> x = 0.1
0.1
julia> typeof(x)
Float64
```
Although this is allowed it is usually not recommended.
---
# You can use Unicode characters in variable names
```
julia> Kamiński = 1
1
julia> x₁ = 0.5
0.5
julia> ε = 0.0001
0.0001
```
In Julia REPL, VS Code ect., you can easily type such characters:
```
help?> ₁
"₁" can be typed by \_1<tab>
help?> ε
"ε" can be typed by \varepsilon<tab>
```
---
# The `if` statement
```
julia> x = -7
-7
julia> if x > 0
println("positive")
elseif x < 0
println("negative")
elseif x == 0
println("zero")
else
println("unexpected condition")
end
negative
```
---
# Conditions must be Boolean values
```
julia> x = -7
-7
julia> if x
println("condition was true")
end
ERROR: TypeError: non-boolean (Int64) used in boolean context
```
---
# Be careful with numeric comparisons of floats
```
julia> NaN > 0
false
julia> NaN < 0
false
julia> NaN == 0
false
julia> NaN != 0
true
julia> NaN != NaN
true
julia> 0.1 + 0.2 == 0.3
false
```
---
# Combining logical conditions with `&&` and `||`
```
julia> x = -7
-7
julia> x > 0 && x < 10
false
julia> x < 0 || log(x) > 10
true
```
---
# Short-circut evaluation
`&&` and `||` evaluate only as many conditions (starting from the leftmost) as
is needed to determine the logical value of the whole expression.
```
julia> x = -7
-7
julia> log(x)
ERROR: DomainError with -7.0:
log will only return a complex result if called with a complex argument. Try log(Complex(x)).
julia> x < 0 || log(x) > 10
true
```
---
# One-line conditional evaluation using `&&` and `||`
The codes below use short-circut evaluation:
```
julia> x = -7
-7
julia> x < 0 && println(x^2)
49
julia> iseven(x) || println("x is odd")
x is odd
```
---
# Ternary operator
Julia supports the *ternary operator* borrowed from the C programming language.
```
x > 0 ? sqrt(x) : sqrt(-x)
```
is equivalent to writing:
```
if x > 0
sqrt(x)
else
sqrt(-x)
end
```
---
# Conditional statements return a value
```
julia> x = -4.0
-4.0
julia> y = if x > 0
sqrt(x)
else
sqrt(-x)
end
2.0
julia> y
2.0
```
---
# Example `for` loop
```
julia> for i in [1, 2, 3]
println(i, " is ", isodd(i) ? "odd" : "even")
end
1 is odd
2 is even
3 is odd
```
---
# Example `while` loop
```
julia> i = 1
1
julia> while i < 4
println(i, " is ", isodd(i) ? "odd" : "even")
global i += 1
end
1 is odd
2 is even
3 is odd
```
We use `global` keyword in the loop as we want to update the `i` variable which
is in global scope.
---
# Standard `break` and `continue` keywords are supported in loops
```
julia> i = 0
0
julia> while true
global i += 1
i > 6 && break
isodd(i) && continue
println(i, " is even")
end
2 is even
4 is even
6 is even
```
---
# Compound expression using `begin`-`end` block
```
julia> x = -7
-7
julia> x < 0 && begin
println(x)
x += 1
println(x)
2 * x
end
-7
-6
-12
```
The value of the compound expression is the value of the last expression
inside it (`-12` in our case).
---
# Compound expression using semicolon `;`
If your code is short you can wrap several expressions in parentheses
and separate them using semicolon `;`:
```
julia> x = -7
-7
julia> x > 0 ? (println(x); x) : (x += 1; println(x); x)
-5
-5
```
---
# You can use the `function` keyword to define a function
```
julia> function times_two(x)
return 2 * x
end
times_two (generic function with 1 method)
julia> times_two(10)
20
```
---
# Functions allow positional and keyword arguments separated by `;` with optional default values
```
julia> function compose(x, y=10; a, b=10)
return x, y, a, b
end
compose (generic function with 2 methods)
julia> compose(1, 2; a=3, b=4)
(1, 2, 3, 4)
julia> compose(1, 2; a=3)
(1, 2, 3, 10)
julia> compose(1; a=3)
(1, 10, 3, 10)
julia> compose(1)
ERROR: UndefKeywordError: keyword argument a not assigned
julia> compose(; a=3)
ERROR: MethodError: no method matching g(; a=3)
```
---
# Passing arguments to functions in Julia
If you pass a value to a function Julia performs a binding of the function
argument name to this value. This feature is called *pass-by-sharing* and means
that Julia never copies data when arguments are passed to a function.
This is a behavior that you might know from Python, but is different from e.g.,
R, where copying of function arguments is performed.
---
# Short syntax for creation simple functions
You can use the assignment operator to create one-line functions:
```
julia> times_two(x) = 2 * x
times_two (generic function with 1 method)
julia> compose(x, y=10; a, b=10) = x, y, a, b
compose (generic function with 2 methods)
```
---
# Functions are first class objects in Julia
You can pass functions as arguments to other functions:
```
julia> map(times_two, [1, 2, 3])
3-element Vector{Int64}:
2
4
6
```
---
# You can define anonymous functions using the `->` operator
```
julia> map(x -> 2 * x, [1, 2, 3])
3-element Vector{Int64}:
2
4
6
julia> sum(x -> x ^ 2, [1, 2, 3])
14
```
---
# Julia supports `do` blocks
If a function takes another function as its first argument you can conveniently
define it using a `do` block:
```
julia> sum([1, 2, 3]) do x
println("processing ", x)
return x ^ 2
end
processing 1
processing 2
processing 3
14
```
---
# The `!` character in function names
Often you will see an exclamation mark (`!`) at the end of the function name,
e.g., `sort!`. There is a convention that developers are recommended to add `!`
at the end of the functions they create if such functions modify their arguments.
```
julia> x = [5, 1, 3, 2];
julia> sort(x); # returns a new vector; x is not changed
julia> sort!(x); # changes x in-place
```
---
# Variable scoping rules in Julia (simplified)
The following constructs we have learned till now create a new scope (*local scope*):
* functions, anonymous functions, `do`-`end` blocks;
* `for` and `while` loops.
Notably the `if` blocks and the `begin`-`end` blocks do not introduce a new
scope. This means that variables defined in such blocks leak out to the
enclosing scope.