Сообщество Engee

День 2

Автор
avatar-igarajaigaraja
Notebook

Основы работы с векторами, матрицами и массивами

  1. Понятия и различия массива, вектора и матрицы
  2. создание векторов и матриц
  3. индексация векторов и матриц
  4. итерирование по матрицам и векторам

Понятия и различия массива, вектора и матрицы

Матрица

Для начала познакомимся с понятием матрицы, которое в целом является интуитивным:

In [ ]:
M = [1 2 3;
     4 5 6;
     7 8 9;]
3×3 Matrix{Int64}:
 1  2  3
 4  5  6
 7  8  9
In [ ]:
size(M)
(3, 3)
In [ ]:
length(M)
9

Под размерностью (dimensions) в julia понимается не размерность матрицы, а её мерность:

2-мерная матрица размерности

In [ ]:
ndims(M)
2

Вектор

В julia вектором называется вектор-столбец:

In [ ]:
V = [1
     2
     3]
3-element Vector{Int64}:
 1
 2
 3

вектор-строка же в julia является матрицей размера 1×n

In [ ]:
Row = [4 5 6]
1×3 Matrix{Int64}:
 4  5  6
In [ ]:
[1, 2, 3]  # вектор
3-element Vector{Int64}:
 1
 2
 3

Сразу покажем как умножить вектор-строку на вектор-столбец:

Заметьте, что результатом является вектор, а не число.

In [ ]:
Row*V    # 1×3 * 3×1 = 1×1
         # 4*1 + 5*2 + 6*3 = 32
1-element Vector{Int64}:
 32
In [ ]:
V*Row    #3×1 * 1×3 = 3×3
3×3 Matrix{Int64}:
  4   5   6
  8  10  12
 12  15  18

Массив

До этого пункта мы рассматривали ситуации, где элементы матрицы/вектора имели один тип.
Проверить какой именно это тип можно с помощью eltype

In [ ]:
eltype([1 2 3])
Int64

Однако в julia можно создавать матрицы/вектора из элементов разных типов.

В таком случае всё равно у матрицы/вектора будет общий тип элементов: Any (пер. - любой)

In [ ]:
@show 1.2 isa Any
@show "Строка" isa Any;
1.2 isa Any = true
"Строка" isa Any = true
In [ ]:
M_different_types = [1, "Два", '3', abs]
4-element Vector{Any}:
 1
  "Два"
  '3': ASCII/Unicode U+0033 (category Nd: Number, decimal digit)
  abs (generic function with 11 methods)
In [ ]:
eltype(M_different_types)
Any

Иногда происходит продвижение типов: процесс приведения типов к одному общему, путём преобразование типов из "меньшего" типа в "больший". Подробнее об этом мы поговорим в следующей главе.

In [ ]:
V_numb = [1, 2//3, 4+5im]
# 1     - Int64
# 2//3  - Rational{Int64}
# 4+5im - Complex{Int64}
3-element Vector{Complex{Rational{Int64}}}:
 1//1 + 0//1*im
 2//3 + 0//1*im
 4//1 + 5//1*im

На самом деле и вектор и матрица представляют собой частный случай массива.

Вектор - массив, у которого размерность равна 1 (ndims≡1).

Матрица - массив, у которого размерность равна 2 (ndims≡2).

Если создать массив размерностью 3 и больше, то будет явно указываться,

что это именно массив, а не матрица

In [ ]:
zeros(2,2,2) # массив нулей размера 2×2×2 (своего рода "кубик")
2×2×2 Array{Float64, 3}:
[:, :, 1] =
 0.0  0.0
 0.0  0.0

[:, :, 2] =
 0.0  0.0
 0.0  0.0
In [ ]:
ndims(zeros(2,2,2))
3

Создание векторов и матриц

нулевые, константные, единичные, случайно заполненные матрицы

In [ ]:
import Pkg.add;
Pkg.add("LinearAlgebra")
In [ ]:
using LinearAlgebra

Единичная матрица размера

In [ ]:
I(3)
3×3 Diagonal{Bool, Vector{Bool}}:
 1  ⋅  ⋅
 ⋅  1  ⋅
 ⋅  ⋅  1

Матрица, заполненная единицами

In [ ]:
ones(3,3)
3×3 Matrix{Float64}:
 1.0  1.0  1.0
 1.0  1.0  1.0
 1.0  1.0  1.0

Заполнить матрицу размера значениями "abc"

In [ ]:
abc_strings = fill("abc",3,2)
3×2 Matrix{String}:
 "abc"  "abc"
 "abc"  "abc"
 "abc"  "abc"

Создать "пустую" (непроинициализированную) матрицу типа Float64 на основе другой матрицы.

(Т.е. такого же размера.)

In [ ]:
similar(abc_strings,Float64)
3×2 Matrix{Float64}:
 6.9531e-310  6.9531e-310
 6.9531e-310  6.9531e-310
 6.9531e-310  6.9531e-310
In [ ]:
similar(abc_strings,Float64) .= 4.
3×2 Matrix{Float64}:
 4.0  4.0
 4.0  4.0
 4.0  4.0

12 элементов от 10 до 76 с постоянным шагом (т.е. 6)

12 = 3*4

12 = 2*6

In [ ]:
reshape(range(10,76,12),3,4)
3×4 reshape(::StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, 3, 4) with eltype Float64:
 10.0  28.0  46.0  64.0
 16.0  34.0  52.0  70.0
 22.0  40.0  58.0  76.0
In [ ]:
reshape(range(10,76,12),2,6)
2×6 reshape(::StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, 2, 6) with eltype Float64:
 10.0  22.0  34.0  46.0  58.0  70.0
 16.0  28.0  40.0  52.0  64.0  76.0

Создание векторов/матриц по условию

In [ ]:
[x^2 for x  [1,3,6]]
3-element Vector{Int64}:
  1
  9
 36
In [ ]:
[[x for x in 1:y] for y in 1:3]
3-element Vector{Vector{Int64}}:
 [1]
 [1, 2]
 [1, 2, 3]
In [ ]:
[x for x in 1:10 if isodd(x)]
5-element Vector{Int64}:
 1
 3
 5
 7
 9

Обращение к элементам массива по индексу

In [ ]:
A = reshape(10:10:90,3,3)
3×3 reshape(::StepRange{Int64, Int64}, 3, 3) with eltype Int64:
 10  40  70
 20  50  80
 30  60  90
In [ ]:
A[1] == A[begin] == 10
true
In [ ]:
A[9] == A[end] == 90
true
In [ ]:
A[4]
40

In [ ]:
A[2,3]
80
In [ ]:
A[6:9]
4-element Vector{Int64}:
 60
 70
 80
 90

Итерирование по массивам

In [ ]:
A = [1:3 10:10:30 100:100:300]
3×3 Matrix{Int64}:
 1  10  100
 2  20  200
 3  30  300

Итерирование по индексу

In [ ]:
A_c = copy(A)
for i in eachindex(A_c)
    isodd(i) ? A_c[i] = 0 : nothing
end
A_c
3×3 Matrix{Int64}:
 0  10    0
 2   0  200
 0  30    0

Итерирование по элементам

In [ ]:
for a in A
    print("$a ")
end
1 2 3 10 20 30 100 200 300 

Итеррирование по строкам

In [ ]:
for row in eachrow(A)
    print(row)
    println(" row sum: $(sum(row))")
end
[1, 10, 100] row sum: 111
[2, 20, 200] row sum: 222
[3, 30, 300] row sum: 333

Итеррирование по стоблцам

In [ ]:
for column in eachcol(A)
    println(reverse(column))
end
[3, 2, 1]
[30, 20, 10]
[300, 200, 100]

Статические массивы

In [ ]:
Pkg.add("BenchmarkTools","StaticArrays")
In [ ]:
using BenchmarkTools
using StaticArrays

v = @SVector [i^2 for i in 1:100]
100-element SVector{100, Int64} with indices SOneTo(100):
     1
     4
     9
    16
    25
    36
    49
    64
    81
   100
     ⋮
  8464
  8649
  8836
  9025
  9216
  9409
  9604
  9801
 10000
In [ ]:
function sqrt_sum()
    v = [i^2 for i in 1:100]
    sqrt(sum(v))
end
@btime sqrt_sum()
  84.305 ns (1 allocation: 896 bytes)
581.6786054171153
In [ ]:
function sqrt_sum()
    s_v = @SVector [i^2 for i in 1:100]
    sqrt(sum(s_v))
end
@btime sqrt_sum()
  1.600 ns (0 allocations: 0 bytes)
581.6786054171153

Копирование векторов

Когда мы пропишем s = r, то s это не копия вектора, а ссылка на тот же вектор.

In [ ]:
r = [1,2,3]
s = r
s[1] = 100
r
3-element Vector{Int64}:
 100
   2
   3
In [ ]:
r = [1,2,3]
s = copy(r)
s[1] = 100
s
3-element Vector{Int64}:
 100
   2
   3
In [ ]:
r
3-element Vector{Int64}:
 1
 2
 3
In [ ]:
r = [[1],[2],[3]]
s = copy(r)
s[1][1] = 100
s
3-element Vector{Vector{Int64}}:
 [100]
 [2]
 [3]
In [ ]:
r
3-element Vector{Vector{Int64}}:
 [100]
 [2]
 [3]
In [ ]:
r = [[1],[2],[3]]
s = deepcopy(r)
s[1][1] = 100
s
3-element Vector{Vector{Int64}}:
 [100]
 [2]
 [3]
In [ ]:
r
3-element Vector{Vector{Int64}}:
 [1]
 [2]
 [3]