#matlab #julia
#matlab #джулия
Вопрос:
Я только начал изучать Julia. Я хотел бы спросить, как заставить срез вектора строки возвращать вектор строки?
Я искал и не мог найти ответа.
В Matlab взятие фрагмента вектора строки возвращает вектор строки, как и ожидалось. Но в Julia он возвращает массив. Версия 1.5.3 (2020-11-09)
>julia
julia> x=[1 2 3 4 5 6]
1×6 Array{Int64,2}:
1 2 3 4 5 6
julia> x[1:4]
4-element Array{Int64,1}:
1
2
3
4
В Matlab
>> x=[1 2 3 4 5 6 7]
>> x(1:4)
ans =
1 2 3 4
Как правильно в Julia это сделать? т.Е. фрагмент вектора строки возвращает вектор строки, и аналогично фрагмент вектора столбца возвращает вектор столбца.
Комментарии:
1. Исключение Matlab из общего правила на самом деле действительно увлекательно!
Ответ №1:
То, что у вас есть, это не вектор строки, а матрица с формой 1×6, то есть 2-мерный массив. Если вы заинтересованы в реальном глубоком погружении в то, как векторы обрабатываются в Julia, вы можете прочитать этот выпуск: https://github.com/julialang/julia/issues/4774 это называется «Серьезно относиться к переносу векторов». Вы можете видеть, что в этот дизайн было вложено много мыслей.
Срезы Julia будут удалять размеры предсказуемым образом: количество измерений выходных данных равно сумме измерений входных индексов. В вашем случае x[1:4]
входной индексный срез равен 1D, следовательно, выходной — 1D. Если вы хотите, чтобы выходные данные были 2D, вам нужны 1D 1D = 2D входные индексы:
jl> x[1:1, 1:4]
1×4 Matrix{Int64}:
1 2 3 4
Обратите внимание, что следующее создает 1D массив
jl> x[1, 1:4]
4-element Vector{Int64}:
1
2
3
4
Это потому, что первый индекс является скалярным, который является 0-мерным, поэтому результат равен 0D 1D = 1D.
Это сохраняется даже для пустых массивов:
jl> x[1:0, 1:4]
0×4 Matrix{Int64}
Это все еще матрица, хотя она имеет размер 0x4.
Вы также должны знать, что в большинстве случаев вам следует предпочесть правильные векторы: [1, 2, 3, 4, 5, 6]
вместо матриц 1xN, [1 2 3 4 5 6]
.
Комментарии:
1. Я бы привел правило, а не обсуждение дизайна: размерность результата равна сумме размерностей индексов. Или, еще точнее, оси результата — это объединенные оси индексов. docs.julialang.org/en/v1/manual/arrays/#man-array-indexing
Ответ №2:
Короткий и сомнительный:
y = x[1:4]'
Дольше и более познавательно:
Если вы обратите пристальное внимание на вывод
x = [1 2 3 4 5 6]
Вы увидите, что условность массива (!) равна двум:
1×6 Array{Int64,2}:
1 2 3 4 5 6
Это потому, что вы не собрали свои элементы в столбец, а принудительно поместили их в строку. Чтобы эффективно использовать julia, попробуйте использовать векторы столбцов, как в
y = [1,2,3,4,5,6]
Или больше полагаться на функции julias и использовать
z = collect(1:6)
Джулия использует макет основного столбца. Каждый столбец массива является непрерывной областью памяти. Это делает операции над столбцами быстрее, чем операции над строками. Другие языки могут иметь разные макеты. На самом деле FORTRAN и MatLab также используют массивы с основными столбцами. С другой стороны, языки программирования C используют основную компоновку строк.
РЕДАКТИРОВАТЬ: По-видимому, я заблудился во время написания. Я считаю, что правильный способ julia
— сделать все это в векторах столбцов. Конечно, есть немного алгебры, где это невозможно. Но для большинства программ не должно иметь значения, какую ориентацию имеют векторы. Поэтому в julia используйте вектор-столбец.
Комментарии:
1. Для
collect
такого диапазона нет никакой особой причины1:6
. Почти во всех случаях он ведет себя как обычный вектор, но более легкий и быстрый. Вам действительно нужно это сделать толькоcollect
в том случае, если вам нужно его видоизменить.
Ответ №3:
Как писал @2419, то, что вы получаете x=[1 2 3 4 5 6]
, на самом деле представляет собой однострочную матрицу, а Julia более эффективна с векторами столбцов.
Тем не менее, конечно, существует законное использование матриц
Вот длинная история.. когда у вас есть матрица и вы срезаете ее так, чтобы результатом была одна строка, она автоматически преобразуется в вектор-столбец:
julia> x = [1 2 3 4; 10 20 30 40; 100 200 300 400]
3×4 Matrix{Int64}:
1 2 3 4
10 20 30 40
100 200 300 400
julia> a = x[2,:]
4-element Vector{Int64}:
10
20
30
40
Однако, если вы разрежете его на 2 или более строк, он останется матрицей:
julia> b = x[[2,3],:]
2×4 Matrix{Int64}:
10 20 30 40
100 200 300 400
Я чувствую себя немного озадаченным этим выбором, но это так, и теперь это не изменится.
Обратите внимание, что получить обратно вектор строки в первом случае очень просто:
julia> transpose(a) # or, equivalently, `a'`
1×4 transpose(::Vector{Int64}) with eltype Int64:
10 20 30 40
Важно! transpose
это матричная операция и работает только с числовыми матрицами (или векторами).
Если ваша матрица содержит нечисловые элементы в виде строк, transpose
это приведет к ошибке, и вместо этого вам следует использовать permutedims
:
julia> x2 = [1 2 "c" 4; 10 20 "cc" 40; 100 200 300 "ddd"]
3×4 Matrix{Any}:
1 2 "c" 4
10 20 "cc" 40
100 200 300 "ddd"
julia> a2 = x2[2,:]
4-element Vector{Any}:
10
20
"cc"
40
julia> transpose(a2)
1×4 transpose(::Vector{Any}) with eltype Any:
Error showing value of type LinearAlgebra.Transpose{Any, Vector{Any}}:
ERROR: MethodError: no method matching transpose(::String)
# [...]
julia> permutedims(a2)
1×4 Matrix{Any}:
10 20 "cc" 40
Однако transpose
быстрее:
julia> using BenchmarkTools
julia> @btime transpose(a)
21.971 ns (1 allocation: 16 bytes)
1×4 transpose(::Vector{Int64}) with eltype Int64:
10 20 30 40
julia> @btime permutedims(a)
66.289 ns (2 allocations: 96 bytes)
1×4 Matrix{Int64}:
10 20 30 40
Итак, если вы уверены, что ваша матрица числовая, используйте transpose
, в противном случае используйте permutedims
.
Комментарии:
1. Пара придирок: во-первых, не количество выходных строк определяет, становится ли оно вектором или матрицей, а тип индексных выражений. So
x[1, 1:4]
является вектором иx[1:1, 1:4]
является матрицей, даже если она имеет только одну строку. Согласованность и стабильность типов являются ключевыми для этого дизайна. Во-вторых, транспонирование работает как для векторов, так и для матриц, а не только для матриц.2. Да, вы правы.. Я не хотел вводить термин «массив», различие, которое я пытался провести, было между числовыми и нечисловыми массивами (отредактировано)..
3. О, и еще кое-что.
transpose
на самом деле это ленивая операция и занимает практически нулевое время. Вы можете увидеть это, если интерполируете переменную в выражение бенчмаркинга:@btime transpose($a)
(обратите внимание на$
). Обычно вы должны использовать интерполяцию с помощью BenchmarkTools.